[
  {
    "path": ".github/workflows/buildPipeline.yml",
    "content": "name: CI Pipeline\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\njobs:\n  build:\n    name: Build and run Unit and Architecture Tests\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v4\n        with:\n          dotnet-version: 8.0.x\n      - name: Run build\n        run: ./build.sh BuildAndUnitTests --configuration Release\n\n  integration:\n    name: Build and run Integration Tests\n    needs: [build]\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v4\n        with:\n          dotnet-version: 8.0.x\n      - name: Run build\n        run: ./build.sh RunAllIntegrationTests\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n.vscode/\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/lib/\n!/wwwroot/lib/signalr\n!/wwwroot/lib/toastr\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\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# 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*.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\npub/\n/src/Web/WebMVC/Properties/PublishProfiles/eShopOnContainersWebMVC2016 - Web Deploy-publish.ps1\n/src/Web/WebMVC/Properties/PublishProfiles/publish-module.psm1\n/src/Services/Identity/eShopOnContainers.Identity/Properties/launchSettings.json\n\n#Ignore marker-file used to know which docker files we have.\n.eshopdocker_*\n/src/Web/WebMVC/wwwroot/lib\n/src/Web/WebMVC/wwwroot/css/site.min.css\n**/.kube/**\n.mfractor\n\n#Ignore logs folder\n[Ll]ogs\n\n#Ignore uploaded files folder\nUploadedFiles\n/src/CompanyName.MyMeetings.v3.ncrunchsolution\n\n#Nuke working directory\n.nuke-working-directory\n/src/API/CompanyName.MyMeetings.API/tempkey.jwk\n"
  },
  {
    "path": ".nuke/build.schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"$ref\": \"#/definitions/build\",\n  \"title\": \"Build Schema\",\n  \"definitions\": {\n    \"build\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Configuration\": {\n          \"type\": \"string\",\n          \"description\": \"Configuration to build - Default is 'Debug' (local) or 'Release' (server)\",\n          \"enum\": [\n            \"Debug\",\n            \"Release\"\n          ]\n        },\n        \"Continue\": {\n          \"type\": \"boolean\",\n          \"description\": \"Indicates to continue a previously failed build attempt\"\n        },\n        \"DatabaseConnectionString\": {\n          \"type\": \"string\",\n          \"description\": \"Modular Monolith database connection string\"\n        },\n        \"Help\": {\n          \"type\": \"boolean\",\n          \"description\": \"Shows the help text for this build assembly\"\n        },\n        \"Host\": {\n          \"type\": \"string\",\n          \"description\": \"Host for execution. Default is 'automatic'\",\n          \"enum\": [\n            \"AppVeyor\",\n            \"AzurePipelines\",\n            \"Bamboo\",\n            \"Bitbucket\",\n            \"Bitrise\",\n            \"GitHubActions\",\n            \"GitLab\",\n            \"Jenkins\",\n            \"Rider\",\n            \"SpaceAutomation\",\n            \"TeamCity\",\n            \"Terminal\",\n            \"TravisCI\",\n            \"VisualStudio\",\n            \"VSCode\"\n          ]\n        },\n        \"NoLogo\": {\n          \"type\": \"boolean\",\n          \"description\": \"Disables displaying the NUKE logo\"\n        },\n        \"Partition\": {\n          \"type\": \"string\",\n          \"description\": \"Partition to use on CI\"\n        },\n        \"Plan\": {\n          \"type\": \"boolean\",\n          \"description\": \"Shows the execution plan (HTML)\"\n        },\n        \"Profile\": {\n          \"type\": \"array\",\n          \"description\": \"Defines the profiles to load\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"Root\": {\n          \"type\": \"string\",\n          \"description\": \"Root directory during build execution\"\n        },\n        \"Skip\": {\n          \"type\": \"array\",\n          \"description\": \"List of targets to be skipped. Empty list skips all dependencies\",\n          \"items\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"ArchitectureTests\",\n              \"BuildAdministrationModuleIntegrationTests\",\n              \"BuildAndUnitTests\",\n              \"BuildMeetingsModuleIntegrationTests\",\n              \"BuildPaymentsModuleIntegrationTests\",\n              \"BuildSystemIntegrationTests\",\n              \"BuildUserAccessModuleIntegrationTests\",\n              \"Clean\",\n              \"Compile\",\n              \"CompileDbUpMigrator\",\n              \"CompileDbUpMigratorForIntegrationTests\",\n              \"CreateDatabase\",\n              \"MigrateDatabase\",\n              \"PrepareInputFiles\",\n              \"PrepareSqlServer\",\n              \"PrepareSUT\",\n              \"Restore\",\n              \"RunAdministrationModuleIntegrationTests\",\n              \"RunAllIntegrationTests\",\n              \"RunDatabaseMigrations\",\n              \"RunMeetingsModuleIntegrationTests\",\n              \"RunPaymentsModuleIntegrationTests\",\n              \"RunSystemIntegrationTests\",\n              \"RunUserAccessModuleIntegrationTests\",\n              \"UnitTests\"\n            ]\n          }\n        },\n        \"Solution\": {\n          \"type\": \"string\",\n          \"description\": \"Path to a solution file that is automatically loaded\"\n        },\n        \"SUTTestName\": {\n          \"type\": \"string\",\n          \"description\": \"SUT creator test name to execute\"\n        },\n        \"Target\": {\n          \"type\": \"array\",\n          \"description\": \"List of targets to be invoked. Default is '{default_target}'\",\n          \"items\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"ArchitectureTests\",\n              \"BuildAdministrationModuleIntegrationTests\",\n              \"BuildAndUnitTests\",\n              \"BuildMeetingsModuleIntegrationTests\",\n              \"BuildPaymentsModuleIntegrationTests\",\n              \"BuildSystemIntegrationTests\",\n              \"BuildUserAccessModuleIntegrationTests\",\n              \"Clean\",\n              \"Compile\",\n              \"CompileDbUpMigrator\",\n              \"CompileDbUpMigratorForIntegrationTests\",\n              \"CreateDatabase\",\n              \"MigrateDatabase\",\n              \"PrepareInputFiles\",\n              \"PrepareSqlServer\",\n              \"PrepareSUT\",\n              \"Restore\",\n              \"RunAdministrationModuleIntegrationTests\",\n              \"RunAllIntegrationTests\",\n              \"RunDatabaseMigrations\",\n              \"RunMeetingsModuleIntegrationTests\",\n              \"RunPaymentsModuleIntegrationTests\",\n              \"RunSystemIntegrationTests\",\n              \"RunUserAccessModuleIntegrationTests\",\n              \"UnitTests\"\n            ]\n          }\n        },\n        \"Verbosity\": {\n          \"type\": \"string\",\n          \"description\": \"Logging verbosity during build execution. Default is 'Normal'\",\n          \"enum\": [\n            \"Minimal\",\n            \"Normal\",\n            \"Quiet\",\n            \"Verbose\"\n          ]\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": ".nuke/parameters.json",
    "content": "{\n  \"$schema\": \"./build.schema.json\",\n  \"Solution\": \"src/CompanyName.MyMeetings.sln\"\n}"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Kamil Grzybek\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Modular Monolith with DDD\n\nFull Modular Monolith .NET application with Domain-Driven Design approach.\n\n## Announcement\n\n![](docs/Images/glory_to_ukraine.jpg)\n\nLearn, use and benefit from this project only if:\n\n- You **condemn Russia and its military aggression against Ukraine**\n- You **recognize that Russia is an occupant that unlawfully invaded a sovereign state**\n- You **support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas**\n- You **reject false narratives perpetuated by Russian state propaganda**\n\nOtherwise, leave this project immediately and educate yourself.\n\nPutin, idi nachuj.\n\n## CI\n\n![](https://github.com/kgrzybek/modular-monolith-with-ddd/workflows/Build%20Pipeline/badge.svg)\n\n## FrontEnd application\n\nFrontEnd application : [Modular Monolith With DDD: FrontEnd React application](https://github.com/kgrzybek/modular-monolith-with-ddd-fe-react)\n\n## Table of contents\n\n[1. Introduction](#1-introduction)\n\n&nbsp;&nbsp;[1.1 Purpose of this Repository](#11-purpose-of-this-repository)\n\n&nbsp;&nbsp;[1.2 Out of Scope](#12-out-of-scope)\n\n&nbsp;&nbsp;[1.3 Reason](#13-reason)\n\n&nbsp;&nbsp;[1.4 Disclaimer](#14-disclaimer)\n\n&nbsp;&nbsp;[1.5 Give a Star](#15-give-a-star)\n\n&nbsp;&nbsp;[1.6 Share It](#16-share-it)\n\n[2. Domain](#2-domain)\n\n&nbsp;&nbsp;[2.1 Description](#21-description)\n\n&nbsp;&nbsp;[2.2 Conceptual Model](#22-conceptual-model)\n\n&nbsp;&nbsp;[2.3 Event Storming](#23-event-storming)\n\n[3. Architecture](#3-architecture)\n\n&nbsp;&nbsp;[3.0 C4 Model](#30-c4-model)\n\n&nbsp;&nbsp;[3.1 High Level View](#31-high-level-view)\n\n&nbsp;&nbsp;[3.2 Module Level View](#32-module-level-view)\n\n&nbsp;&nbsp;[3.3 API and Module Communication](#33-api-and-module-communication)\n\n&nbsp;&nbsp;[3.4 Module Requests Processing via CQRS](#34-module-requests-processing-via-cqrs)\n\n&nbsp;&nbsp;[3.5 Domain Model Principles and Attributes](#35-domain-model-principles-and-attributes)\n\n&nbsp;&nbsp;[3.6 Cross-Cutting Concerns](#36-cross-cutting-concerns)\n\n&nbsp;&nbsp;[3.7 Modules Integration](#37-modules-integration)\n\n&nbsp;&nbsp;[3.8 Internal Processing](#38-internal-processing)\n\n&nbsp;&nbsp;[3.9 Security](#39-security)\n\n&nbsp;&nbsp;[3.10 Unit Tests](#310-unit-tests)\n\n&nbsp;&nbsp;[3.11 Architecture Decision Log](#311-architecture-decision-log)\n\n&nbsp;&nbsp;[3.12 Architecture Unit Tests](#312-architecture-unit-tests)\n\n&nbsp;&nbsp;[3.13 Integration Tests](#313-integration-tests)\n\n&nbsp;&nbsp;[3.14 System Integration Testing](#314-system-integration-testing)\n\n&nbsp;&nbsp;[3.15 Event Sourcing](#315-event-sourcing)\n\n&nbsp;&nbsp;[3.16 Database change management](#316-database-change-management)\n\n&nbsp;&nbsp;[3.17 Continuous Integration](#317-continuous-integration)\n\n&nbsp;&nbsp;[3.18 Static code analysis](#318-static-code-analysis)\n\n&nbsp;&nbsp;[3.19 System Under Test SUT](#319-system-under-test-sut)\n\n&nbsp;&nbsp;[3.20 Mutation Testing](#320-mutation-testing)\n\n[4. Technology](#4-technology)\n\n[5. How to Run](#5-how-to-run)\n\n[6. Contribution](#6-contribution)\n\n[7. Roadmap](#7-roadmap)\n\n[8. Authors](#8-authors)\n\n[9. License](#9-license)\n\n[10. Inspirations and Recommendations](#10-inspirations-and-recommendations)\n\n## 1. Introduction\n\n### 1.1 Purpose of this Repository\n\nThis is a list of the main goals of this repository:\n\n- Showing how you can implement a **monolith** application in a **modular** way\n- Presentation of the **full implementation** of an application\n  - This is not another simple application\n  - This is not another proof of concept (PoC)\n  - The goal is to present the implementation of an application that would be ready to run in production\n- Showing the application of **best practices** and **object-oriented programming principles**\n- Presentation of the use of **design patterns**. When, how and why they can be used\n- Presentation of some **architectural** considerations, decisions, approaches\n- Presentation of the implementation using **Domain-Driven Design** approach (**tactical** patterns)\n- Presentation of the implementation of **Unit Tests** for Domain Model (Testable Design in mind)\n- Presentation of the implementation of **Integration Tests**\n- Presentation of the implementation of **Event Sourcing**\n- Presentation of **C4 Model**\n- Presentation of **diagram as text** approach\n\n### 1.2 Out of Scope\n\nThis is a list of subjects which are out of scope for this repository:\n\n- Business requirements gathering and analysis\n- System analysis\n- Domain exploration\n- Domain distillation\n- Domain-Driven Design **strategic** patterns\n- Architecture evaluation, quality attributes analysis\n- Integration, system tests\n- Project management\n- Infrastructure\n- Containerization\n- Software engineering process\n- Deployment process\n- Maintenance\n- Documentation\n\n### 1.3 Reason\n\nThe reason for creating this repository is the lack of something similar. Most sample applications on GitHub have at least one of the following issues:\n\n- Very, very simple - few entities and use cases implemented\n- Not finished (for example there is no authentication, logging, etc..)\n- Poorly designed (in my opinion)\n- Poorly implemented (in my opinion)\n- Not well described\n- Assumptions and decisions are not clearly explained\n- Implements \"Orders\" domain - yes, everyone knows this domain, but something different is needed\n- Implemented in old technology\n- Not maintained\n\nTo sum up, there are some very good examples, but there are far too few of them. This repository has the task of filling this gap at some level.\n\n### 1.4 Disclaimer\n\nSoftware architecture should always be created to resolve specific **business problems**. Software architecture always supports some quality attributes and at the same time does not support others. A lot of other factors influence your software architecture - your team, opinions, preferences, experiences, technical constraints, time, budget, etc.\n\nAlways functional requirements, quality attributes, technical constraints and other factors should be considered before an architectural decision is made.\n\nBecause of the above, the architecture and implementation presented in this repository is **one of the many ways** to solve some problems. Take from this repository as much as you want, use it as you like but remember to **always pick the best solution which is appropriate to the problem class you have**.\n\n### 1.5 Give a Star\n\nMy primary focus in this project is on quality. Creating a good quality product involves a lot of analysis, research and work. It takes a lot of time. If you like this project, learned something or you are using it in your applications, please give it a star :star:.  This is the best motivation for me to continue this work. Thanks!\n\n### 1.6 Share It\n\nThere are very few really good examples of this type of application. If you think this repository makes a difference and is worth it, please share it with your friends and on social networks. I will be extremely grateful.\n\n## 2. Domain\n\n### 2.1 Description\n\n**Definition:**\n\n> Domain - A sphere of knowledge, influence, or activity. The subject area to which the user applies a program is the domain of the software. [Domain-Driven Design Reference](http://domainlanguage.com/ddd/reference/), Eric Evans\n\nThe **Meeting Groups** domain was selected for the purposes of this project based on the [Meetup.com](https://www.meetup.com/) system.\n\n**Main reasons for selecting this domain:**\n\n- It is common, a lot of people use the Meetup site to organize or attend meetings\n- There is a system for it, so everyone can check this implementation against a working site which supports this domain\n- It is not complex so it is easy to understand\n- It is not trivial - there are some business rules and logic and it is not just CRUD operations\n- You don't need much specific domain knowledge unlike other domains like financing, banking, medical\n- It is not big so it is easier to implement\n\n**Meetings**\n\nThe main business entities are `Member`, `Meeting Group` and `Meeting`. A `Member` can create a `Meeting Group`, be part of a `Meeting Group` or can attend a `Meeting`.\n\nA `Meeting Group Member` can be an `Organizer` of this group or a normal `Member`.\n\nOnly an `Organizer` of a `Meeting Group` can create a new `Meeting`.\n\nA `Meeting` has attendees, not attendees (`Members` which declare they will not attend the `Meeting`) and `Members` on the `Waitlist`.\n\nA `Meeting` can have an attendee limit. If the limit is reached, `Members` can only sign up to the `Waitlist`.\n\nA `Meeting Attendee` can bring guests to the `Meeting`. The number of guests allowed is an attribute of the `Meeting`. Bringing guests can be unallowed.\n\nA `Meeting Attendee` can have one of two roles: `Attendee` or `Host`. A `Meeting` must have at least one `Host`. The `Host` is a special role which grants permission to edit `Meeting` information or change the attendees list.\n\nA `Member` can comment `Meetings`. A `Member` can reply to, like other `Comments`. `Organizer` manages commenting of `Meeting` by `Meeting Commenting Configuration`. `Organizer` can delete any `Comment`.\n\nEach `Meeting Group` must have an organizer with active `Subscription`. One organizer can cover 3 `Meeting Groups` by his `Subscription`.\n\nAdditionally, Meeting organizer can set an `Event Fee`. Each `Meeting Attendee` is obliged to pay the fee. All guests should be paid by `Meeting Attendee` too.\n\n**Administration**\n\nTo create a new `Meeting Group`, a `Member` needs to propose the group. A `Meeting Group Proposal` is sent to `Administrators`. An `Administrator` can accept or reject a `Meeting Group Proposal`. If a `Meeting Group Proposal` is accepted, a `Meeting Group` is created.\n\n**Payments**\n\nEach `Member` who is the `Payer` can buy the `Subscription`. He needs to pay the `Subscription Payment`. `Subscription` can expire so `Subscription Renewal` is required (by `Subscription Renewal Payment` payment to keep `Subscription` active).\n\nWhen the `Meeting` fee is required, the `Payer` needs to pay `Meeting Fee` (through `Meeting Fee Payment`).\n\n**Users**\n\nEach `Administrator`, `Member` and `Payer` is a `User`. To be a `User`, `User Registration` is required and confirmed.\n\nEach `User` is assigned one or more `User Role`.\n\nEach `User Role` has set of `Permissions`. A `Permission` defines whether `User` can invoke a particular action.\n\n### 2.2 Conceptual Model\n\n**Definition:**\n\n> Conceptual Model - A conceptual model is a representation of a system, made of the composition of concepts that are used to help people know, understand, or simulate a subject the model represents. [Wikipedia - Conceptual model](https://en.wikipedia.org/wiki/Conceptual_model)\n\n**Conceptual Model**\n\nPlantUML version:\n![](https://www.plantuml.com/plantuml/proxy?cache=no&src=https://raw.githubusercontent.com/kgrzybek/modular-monolith-with-ddd/master/docs/PlantUML/Conceptual_Model.puml)\n\nVisualParadigm version (not maintained, only for demonstration):\n![](docs/Images/Conceptual_Model.png)\n\n**Conceptual Model of commenting feature**\n![](https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/kgrzybek/modular-monolith-with-ddd/master/docs/PlantUML/Commenting_Conceptual_Model.puml)\n\n### 2.3 Event Storming\n\nWhile a Conceptual Model focuses on structures and relationships between them, **behavior** and **events** that occur in our domain are more important.\n\nThere are many ways to show behavior and events. One of them is a light technique called [Event Storming](https://www.eventstorming.com/) which is becoming more popular. Below are presented 3 main business processes using this technique: user registration, meeting group creation and meeting organization.\n\nNote: Event Storming is a light, live workshop. One of the possible outputs of this workshop is presented here. Even if you are not doing Event Storming workshops, this type of process presentation can be very valuable to you and your stakeholders.\n\n**User Registration process**\n\n------\n\n![](docs/Images/User_Registration.jpg)\n\n------\n\n**Meeting Group creation**\n![](docs/Images/Meeting_Group_Creation.jpg)\n\n------\n\n**Meeting organization**\n![](docs/Images/Meeting_Organization.jpg)\n\n------\n\n**Payments**\n![](docs/Images/Payments_EventStorming_Design.jpg)\n[Download high resolution file](docs/Images/Payments_EventStorming_Design_HighRes.jpg)\n\n------\n\n## 3. Architecture\n\n### 3.0 C4 Model\n\n[C4 model](https://c4model.com/) is a lean graphical notation technique for modelling the architecture of software systems. <br>\n\nAs can be found on the website of the author of this model ([Simon Brown](https://simonbrown.je/)): *The C4 model was created as a way to help software development teams describe and communicate software architecture, both during up-front design sessions and when retrospectively documenting an existing codebase* <br>\n\n*Model C4* defines 4 levels (views) of the system architecture: *System Context*, *Container*, *Component* and *Code*. Below are examples of each of these levels that describe the architecture of this system. <br>\n\n*Note: The [PlantUML](https://plantuml.com/) (diagram as text) component was used to describe all C4 model levels. Additionally, for levels C1-C3, a [C4-PlantUML](https://github.com/plantuml-stdlib/C4-PlantUML) plug-in connecting PlantUML with the C4 model was used*.\n\n#### 3.0.1 C1 System Context\n\n![](http://www.plantuml.com/plantuml/png/7OrDgeD048JtxnGl1z0ca5LMGWuYutIZulIqz0_6d3vZDbLG5Dytc2VruF9tMsikWHHQ_XVttPu0cev-Nds9AOmqItMgtcTXs6Rzd1Djm89HadOiLKgxTiSLY0YSp4a19Hky7f3levrjuV77UNk_Nzg1AhR-0W00)\n\n#### 3.0.2 C2 Container\n\n![](docs/C4/C2_Containers.png)\n\n#### 3.0.3 C3 Component (high-level)\n\n![](docs/C4/C3_Components.png)\n\n#### 3.0.4 C3 Component (module-level)\n\n![](http://www.plantuml.com/plantuml/png/jLHFRzCm5B_dKsI1GojjBOKn5QH9wxeTAgrem7QUdEGrjHJRaVqCgX3V7QVUl7XkbnA2BusUVt_y_7xrXK8YKRCoEi8rC8Yhab0U7L6UbJg7U8rOgS_ZiIG_HmN5jKwr0fa9Zi1nb0asDWHU2vmep4kQZkUd9xTrwNvvCsP48KXJUfWBLWbUSwhQB9hbkIlTaMAGC02al539SVmsBUQY5F8yUNEQmRkpZyamn9ESKKuLIe9KS9y57zBfsNGN2twOBtMfNzYy_pIPJ4bTMmcEJzNLTXcPwFj68R27Iw5vJkHca4sEusIvYPUFXuuj81d6lwBOB0TacoV8hA8lEBFRXIFKovrqGBROUj_yZBvStvaz2PRWuFR3CtjKNefSbs2epifMd5lWwAWBlf94eTGPQjcK6Faxxc0tD9N6kxuw98KwVvxZiCLgLbKbpRRJQ_eqoZsON0b6gATlApr8BpX2OTDtlKrLqoNOx6vubJvtGv0qnveJ9BMmojR0oAkIlwCmB_vVoALcvfNRi-FB10dovGxEaQ-Q30yoRsOgS6vizcnhCnKwsdhFPc7k0jy0qlq8BeC-i4vYu1laiSN4fTBp-gf1my0zr4REzX3RLpjPy9W14yqc7DXA6raZ77s3qhwaUn-tUmM64W8RIV5HkvLw8Be4XHnVj3CXZCtV7P0WEOpXXk7WZL7uIMWTY0_VUxklg_u7aLstlzUcLt8unkvD42JjxFR1-gn_2L-tlY-0vvgLVm00)\n\n#### 3.0.5 C4 Code (meeting group aggregate)\n\n![](http://www.plantuml.com/plantuml/png/5OqxheD0303xTugN0x1kg58XvI3HObk0yAwHFqB9wGFDJ3FIJ1xL8flyFRQEaiHfyhz67Fu4i7gMPOirvtGsr1xSew0ss1VxVcRUeIcbL1kQTfKh7SuRH0IjUh01AJgyHi3nZLBTot7V9kvq-GS0)\n\n### 3.1 High Level View\n\n![](docs/Images/Architecture_high_level.png)\n\n**Module descriptions:**\n\n- **API** - Very thin ASP.NET MVC Core REST API application. Main responsibilities are:\n  1. Accept request\n  2. Authenticate and authorize request (using User Access module)\n  3. Delegate work to specific module sending Command or Query\n  4. Return response\n- **User Access** - responsible for user authentication and authorization\n- **Registrations** - responsible for user registration\n- **Meetings** - implements Meetings Bounded Context: creating meeting groups, meetings\n- **Administration** - implements Administration Bounded Context: implements administrative tasks like meeting group proposal verification\n- **Payments** - implements Payments Bounded Context: implements all functionalities associated with payments\n- **In Memory Events Bus** - Publish/Subscribe implementation to asynchronously integrate all modules using events ([Event Driven Architecture](https://en.wikipedia.org/wiki/Event-driven_architecture)).\n\n**Key assumptions:**\n\n1. API contains no application logic\n2. API communicates with Modules using a small interface to send Queries and Commands\n3. Each Module has its own interface which is used by API\n4. **Modules communicate each other only asynchronously using Events Bus** - direct method calls are not allowed\n5. Each Module **has it's own data** in a separate schema - shared data is not allowed\n   - Module data could be moved into separate databases if desired\n6. Modules can only have a dependency on the integration events assembly of other Module (see [Module level view](#32-module-level-view))\n7. Each Module has its own [Composition Root](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/), which implies that each Module has its own Inversion-of-Control container\n8. API as a host needs to initialize each module and each module has an initialization method\n9. Each Module is **highly encapsulated** - only required types and members are public, the rest are internal or private\n\n### 3.2 Module Level View\n\n![](docs/Images/Module_level_diagram.png)\n\nEach Module has [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) and consists of the following submodules (assemblies):\n\n- **Application** - the application logic submodule which is responsible for requests processing: use cases, domain events, integration events, internal commands.\n- **Domain** - Domain Model in Domain-Driven Design terms implements the applicable [Bounded Context](https://martinfowler.com/bliki/BoundedContext.html)\n- **Infrastructure** - infrastructural code responsible for module initialization, background processing, data access, communication with Events Bus and other external components or systems\n- **IntegrationEvents** - **Contracts** published to the Events Bus; only this assembly can be called by other modules\n\n![](docs/Images/VSSolution.png)\n\n**Note:** Application, Domain and Infrastructure assemblies could be merged into one assembly. Some people like horizontal layering or more decomposition, some don't. Implementing the Domain Model or Infrastructure in separate assembly allows encapsulation using the [`internal`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal) keyword. Sometimes Bounded Context logic is not worth it because it is too simple. As always, be pragmatic and take whatever approach you like.\n\n### 3.3 API and Module Communication\n\nThe API only communicates with Modules in two ways: during module initialization and request processing.\n\n**Module initialization**\n\nEach module has a static ``Initialize`` method which is invoked in the API ``Startup`` class. All configuration needed by this module should be provided as arguments to this method. All services are configured during initialization and the Composition Root is created using the Inversion-of-Control Container.\n\n```csharp\npublic static void Initialize(\n    string connectionString,\n    IExecutionContextAccessor executionContextAccessor,\n    ILogger logger,\n    EmailsConfiguration emailsConfiguration)\n{\n    var moduleLogger = logger.ForContext(\"Module\", \"Meetings\");\n\n    ConfigureCompositionRoot(connectionString, executionContextAccessor, moduleLogger, emailsConfiguration);\n\n    QuartzStartup.Initialize(moduleLogger);\n\n    EventsBusStartup.Initialize(moduleLogger);\n}\n```\n\n**Request processing**\n\nEach module has the same interface signature exposed to the API. It contains 3 methods: command with result, command without result and query.\n\n```csharp\npublic interface IMeetingsModule\n{\n    Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n    Task ExecuteCommandAsync(ICommand command);\n\n    Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n}\n```\n\n**Note:** Some people say that processing a command should not return a result. This is an understandable approach but sometimes impractical, especially when you want to immediately return the ID of a newly created resource. Sometimes the boundary between Command and Query is blurry. One example is ``AuthenticateCommand`` - it returns a token but it is not a query because it has a side effect.\n\n### 3.4 Module Requests Processing via CQRS\n\nProcessing of Commands and Queries is separated by applying the architectural style/pattern [Command Query Responsibility Segregation (CQRS)](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs).\n\n![](docs/Images/CQRS.jpg)\n\nCommands are processed using *Write Model* which is implemented using DDD tactical patterns:\n\n```csharp\ninternal class CreateNewMeetingGroupCommandHandler : ICommandHandler<CreateNewMeetingGroupCommand>\n{\n    private readonly IMeetingGroupRepository _meetingGroupRepository;\n    private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\n\n    internal CreateNewMeetingGroupCommandHandler(\n        IMeetingGroupRepository meetingGroupRepository,\n        IMeetingGroupProposalRepository meetingGroupProposalRepository)\n    {\n        _meetingGroupRepository = meetingGroupRepository;\n        _meetingGroupProposalRepository = meetingGroupProposalRepository;\n    }\n\n    public async Task Handle(CreateNewMeetingGroupCommand request, CancellationToken cancellationToken)\n    {\n        var meetingGroupProposal = await _meetingGroupProposalRepository.GetByIdAsync(request.MeetingGroupProposalId);\n\n        var meetingGroup = meetingGroupProposal.CreateMeetingGroup();\n\n        await _meetingGroupRepository.AddAsync(meetingGroup);\n\n        \n    }\n}\n```\n\nQueries are processed using *Read Model* which is implemented by executing raw SQL statements on database views:\n\n```csharp\ninternal class GetAllMeetingGroupsQueryHandler : IQueryHandler<GetAllMeetingGroupsQuery, List<MeetingGroupDto>>\n{\n    private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n    internal GetAllMeetingGroupsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n    {\n        _sqlConnectionFactory = sqlConnectionFactory;\n    }\n\n    public async Task<List<MeetingGroupDto>> Handle(GetAllMeetingGroupsQuery request, CancellationToken cancellationToken)\n    {\n        var connection = _sqlConnectionFactory.GetOpenConnection();\n\n        const string sql = $\"\"\"\n                           SELECT \n                                [MeetingGroup].[Id] as [{nameof(MeetingGroupDto.Id)}] , \n                                [MeetingGroup].[Name] as [{nameof(MeetingGroupDto.Name)}], \n                                [MeetingGroup].[Description] as [{nameof(MeetingGroupDto.Description)}] \n                                [MeetingGroup].[LocationCountryCode] as [{nameof(MeetingGroupDto.LocationCountryCode)}],\n                                [MeetingGroup].[LocationCity] as [{nameof(MeetingGroupDto.LocationCity)}]\n                           FROM [meetings].[v_MeetingGroups] AS [MeetingGroup]\n                           \"\"\";\n        var meetingGroups = await connection.QueryAsync<MeetingGroupDto>(sql);\n\n        return meetingGroups.AsList();\n    }\n}\n```\n\n**Key advantages:**\n\n- Solution is appropriate to the problem - reading and writing needs are usually different\n- Supports [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle) (SRP) - one handler does one thing\n- Supports [Interface Segregation Principle](https://en.wikipedia.org/wiki/Interface_segregation_principle) (ISP) - each handler implements interface with exactly one method\n- Supports [Parameter Object pattern](https://refactoring.com/catalog/introduceParameterObject.html) - Commands and Queries are objects which are easy to serialize/deserialize\n- Easy way to apply [Decorator pattern](https://en.wikipedia.org/wiki/Decorator_pattern) to handle cross-cutting concerns\n- Supports Loose Coupling by use of the [Mediator pattern](https://en.wikipedia.org/wiki/Mediator_pattern) - separates invoker of request from handler of request\n\n**Disadvantage:**\n\n- Mediator pattern introduces extra indirection and is harder to reason about which class handles the request\n\nFor more information: [Simple CQRS implementation with raw SQL and DDD](https://www.kamilgrzybek.com/design/simple-cqrs-implementation-with-raw-sql-and-ddd/)\n\n### 3.5 Domain Model Principles and Attributes\n\nThe Domain Model, which is the central and most critical part in the system, should be designed with special attention. Here are some key principles and attributes which are applied to Domain Models of each module:\n\n1. **High level of encapsulation**\n\n    All members are ``private`` by default, then ``internal`` - only ``public`` at the very edge.\n\n2. **High level of PI (Persistence Ignorance)**\n\n    No dependencies to infrastructure, databases, etc. All classes are [POCOs](https://en.wikipedia.org/wiki/Plain_old_CLR_object).\n\n3. **Rich in behavior**\n\n    All business logic is located in the Domain Model. No leaks to the application layer or elsewhere.\n\n4. **Low level of Primitive Obsession**\n\n    Primitive attributes of Entites grouped together using ValueObjects.\n\n5. **Business language**\n\n    All classes, methods and other members are named in business language used in this Bounded Context.\n\n6. **Testable**\n\n    The Domain Model is a critical part of the system so it should be easy to test (Testable Design).\n\n```csharp\npublic class MeetingGroup : Entity, IAggregateRoot\n{\n    public MeetingGroupId Id { get; private set; }\n\n    private string _name;\n\n    private string _description;\n\n    private MeetingGroupLocation _location;\n\n    private MemberId _creatorId;\n\n    private List<MeetingGroupMember> _members;\n\n    private DateTime _createDate;\n\n    private DateTime? _paymentDateTo;\n\n    internal static MeetingGroup CreateBasedOnProposal(\n        MeetingGroupProposalId meetingGroupProposalId,\n        string name,\n        string description,\n        MeetingGroupLocation location, MemberId creatorId)\n    {\n        return new MeetingGroup(meetingGroupProposalId, name, description, location, creatorId);\n    }\n\n     public Meeting CreateMeeting(\n            string title,\n            MeetingTerm term,\n            string description,\n            MeetingLocation location,\n            int? attendeesLimit,\n            int guestsLimit,\n            Term rsvpTerm,\n            MoneyValue eventFee,\n            List<MemberId> hostsMembersIds,\n            MemberId creatorId)\n        {\n            this.CheckRule(new MeetingCanBeOrganizedOnlyByPayedGroupRule(_paymentDateTo));\n\n            this.CheckRule(new MeetingHostMustBeAMeetingGroupMemberRule(creatorId, hostsMembersIds, _members));\n\n            return new Meeting(this.Id,\n                title,\n                term,\n                description,\n                location,\n                attendeesLimit,\n                guestsLimit,\n                rsvpTerm,\n                eventFee,\n                hostsMembersIds,\n                creatorId);\n        }\n```\n\n### 3.6 Cross-Cutting Concerns\n\nTo support [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle) and [Don't Repeat Yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principles, the implementation of cross-cutting concerns is done using the [Decorator Pattern](https://en.wikipedia.org/wiki/Decorator_pattern). Each Command processor is decorated by 3 decorators: logging, validation and unit of work.\n\n![](docs/Images/Decorator.jpg)\n\n**Logging**\n\nThe Logging decorator logs execution, arguments and processing of each Command. This way each log inside a processor has the log context of the processing command.\n\n```csharp\ninternal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T> where T:ICommand\n{\n    private readonly ILogger _logger;\n    private readonly IExecutionContextAccessor _executionContextAccessor;\n    private readonly ICommandHandler<T> _decorated;\n\n    public LoggingCommandHandlerDecorator(\n        ILogger logger,\n        IExecutionContextAccessor executionContextAccessor,\n        ICommandHandler<T> decorated)\n    {\n        _logger = logger;\n        _executionContextAccessor = executionContextAccessor;\n        _decorated = decorated;\n    }\n    public async Task Handle(T command, CancellationToken cancellationToken)\n    {\n        if (command is IRecurringCommand)\n        {\n            return await _decorated.Handle(command, cancellationToken);\n        }\n        using (\n            LogContext.Push(\n                new RequestLogEnricher(_executionContextAccessor),\n                new CommandLogEnricher(command)))\n        {\n            try\n            {\n                this._logger.Information(\n                    \"Executing command {Command}\",\n                    command.GetType().Name);\n\n                var result = await _decorated.Handle(command, cancellationToken);\n\n                this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\n\n                return result;\n            }\n            catch (Exception exception)\n            {\n                this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\n                throw;\n            }\n        }\n    }\n\n    private class CommandLogEnricher : ILogEventEnricher\n    {\n        private readonly ICommand _command;\n\n        public CommandLogEnricher(ICommand command)\n        {\n            _command = command;\n        }\n        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n        {\n            logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n        }\n    }\n\n    private class RequestLogEnricher : ILogEventEnricher\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n        {\n            _executionContextAccessor = executionContextAccessor;\n        }\n        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n        {\n            if (_executionContextAccessor.IsAvailable)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\n            }\n        }\n    }\n}\n```\n\n**Validation**\n\nThe Validation decorator performs Command data validation. It checks rules against Command arguments using the FluentValidation library.\n\n```csharp\ninternal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T> where T:ICommand\n{\n    private readonly IList<IValidator<T>> _validators;\n    private readonly ICommandHandler<T> _decorated;\n\n    public ValidationCommandHandlerDecorator(\n        IList<IValidator<T>> validators,\n        ICommandHandler<T> decorated)\n    {\n        this._validators = validators;\n        _decorated = decorated;\n    }\n\n    public Task<Unit> Handle(T command, CancellationToken cancellationToken)\n    {\n        var errors = _validators\n            .Select(v => v.Validate(command))\n            .SelectMany(result => result.Errors)\n            .Where(error => error != null)\n            .ToList();\n\n        if (errors.Any())\n        {\n            var errorBuilder = new StringBuilder();\n\n            errorBuilder.AppendLine(\"Invalid command, reason: \");\n\n            foreach (var error in errors)\n            {\n                errorBuilder.AppendLine(error.ErrorMessage);\n            }\n\n            throw new InvalidCommandException(errorBuilder.ToString(), null);\n        }\n\n        return _decorated.Handle(command, cancellationToken);\n    }\n}\n```\n\n**Unit Of Work**\n\nAll Command processing has side effects. To avoid calling commit on every handler, `UnitOfWorkCommandHandlerDecorator` is used. It additionally marks `InternalCommand` as processed (if it is Internal Command) and dispatches all Domain Events (as part of [Unit Of Work](https://martinfowler.com/eaaCatalog/unitOfWork.html)).\n\n```csharp\npublic class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T> where T:ICommand\n{\n    private readonly ICommandHandler<T> _decorated;\n    private readonly IUnitOfWork _unitOfWork;\n    private readonly MeetingsContext _meetingContext;\n\n    public UnitOfWorkCommandHandlerDecorator(\n        ICommandHandler<T> decorated,\n        IUnitOfWork unitOfWork,\n        MeetingsContext meetingContext)\n    {\n        _decorated = decorated;\n        _unitOfWork = unitOfWork;\n        _meetingContext = meetingContext;\n    }\n\n    public async Task Handle(T command, CancellationToken cancellationToken)\n    {\n        await this._decorated.Handle(command, cancellationToken);\n\n        if (command is InternalCommandBase)\n        {\n            var internalCommand =\n                await _meetingContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id,\n                    cancellationToken: cancellationToken);\n\n            if (internalCommand != null)\n            {\n                internalCommand.ProcessedDate = DateTime.UtcNow;\n            }\n        }\n\n        await this._unitOfWork.CommitAsync(cancellationToken);\n\n        \n    }\n}\n```\n\n### 3.7 Modules Integration\n\nIntegration between modules is strictly **asynchronous** using Integration Events and the In Memory Event Bus as broker. In this way coupling between modules is minimal and exists only on the structure of Integration Events.\n\n**Modules don't share data** so it is not possible nor desirable to create a transaction which spans more than one module. To ensure maximum reliability, the [Outbox / Inbox pattern](http://www.kamilgrzybek.com/design/the-outbox-pattern/) is used. This pattern provides accordingly *\"At-Least-Once delivery\"* and *\"At-Least-Once processing\"*.\n\n![](docs/Images/OutboxInbox.jpg)\n\nThe Outbox and Inbox is implemented using two SQL tables and a background worker for each module. The background worker is implemented using the Quartz.NET library.\n\n**Saving to Outbox:**\n\n![](docs/Images/OutboxSave.png)\n\n**Processing Outbox:**\n\n![](docs/Images/OutboxProcessing.png)\n\n### 3.8 Internal Processing\n\nThe main principle of this system is that you can change its state only by calling a specific Command.\n\nCommands can be called not only by the API, but by the processing module itself. The main use case which implements this mechanism is data processing in eventual consistency mode when we want to process something in a different process and transaction. This applies, for example, to Inbox processing because we want to do something (calling a Command) based on an Integration Event from the Inbox.\n\nThis idea is taken from Alberto's Brandolini's Event Storming picture called \"The picture that explains “almost” everything\" which shows that every side effect (domain event) is created by invoking a Command on Aggregate. See [EventStorming cheat sheet](https://xebia.com/blog/eventstorming-cheat-sheet/) article for more details.\n\nImplementation of internal processing is very similar to implementation of the Outbox and Inbox. One SQL table and one background worker for processing. Each internally processing Command must inherit from `InternalCommandBase` class:\n\n```csharp\ninternal abstract class InternalCommandBase : ICommand\n{\n    public Guid Id { get; }\n\n    protected InternalCommandBase(Guid id)\n    {\n        this.Id = id;\n    }\n}\n```\n\nThis is important because the `UnitOfWorkCommandHandlerDecorator` must mark an internal Command as processed during committing:\n\n```csharp\npublic async Task Handle(T command, CancellationToken cancellationToken)\n{\n    await this._decorated.Handle(command, cancellationToken);\n\n    if (command is InternalCommandBase)\n    {\n        var internalCommand =\n            await _meetingContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id,\n                cancellationToken: cancellationToken);\n\n        if (internalCommand != null)\n        {\n            internalCommand.ProcessedDate = DateTime.UtcNow;\n        }\n    }\n\n    await this._unitOfWork.CommitAsync(cancellationToken);\n\n    \n}\n```\n\n### 3.9 Security\n\n**Authentication**\n\nAuthentication is implemented using JWT Token and Bearer scheme using IdentityServer. For now, only one authentication method is implemented: forms style authentication (username and password) via the OAuth2 [Resource Owner Password Grant Type](https://www.oauth.com/oauth2-servers/access-tokens/password-grant/). It requires implementation of the `IResourceOwnerPasswordValidator` interface:\n\n```csharp\npublic class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator\n{\n    private readonly IUserAccessModule _userAccessModule;\n\n    public ResourceOwnerPasswordValidator(IUserAccessModule userAccessModule)\n    {\n        _userAccessModule = userAccessModule;\n    }\n\n    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)\n    {\n        var authenticationResult = await _userAccessModule.ExecuteCommandAsync(new AuthenticateCommand(context.UserName, context.Password));\n        if (!authenticationResult.IsAuthenticated)\n        {\n            context.Result = new GrantValidationResult(\n                TokenRequestErrors.InvalidGrant,\n                authenticationResult.AuthenticationError);\n            return;\n        }\n        context.Result = new GrantValidationResult(\n            authenticationResult.User.Id.ToString(),\n            \"forms\",\n            authenticationResult.User.Claims);\n    }\n}\n```\n\n**Authorization**\n\nAuthorization is achieved by implementing [RBAC (Role Based Access Control)](https://en.wikipedia.org/wiki/Role-based_access_control) using Permissions. Permissions are more granular and a much better way to secure your application than Roles alone. Each User has a set of Roles and each Role contains one or more Permission. The User's set of Permissions is extracted from all Roles the User belongs to. Permissions are always checked on `Controller` level - never Roles:\n\n```csharp\n[HttpPost]\n[Route(\"\")]\n[HasPermission(MeetingsPermissions.ProposeMeetingGroup)]\npublic async Task<IActionResult> ProposeMeetingGroup(ProposeMeetingGroupRequest request)\n{\n    await _meetingsModule.ExecuteCommandAsync(\n        new ProposeMeetingGroupCommand(\n            request.Name,\n            request.Description,\n            request.LocationCity,\n            request.LocationCountryCode));\n\n    return Ok();\n}\n```\n\n### 3.10 Unit Tests\n\n**Definition:**\n\n>A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It’s trustworthy, readable, and maintainable. It’s consistent in its results as long as production code hasn’t changed. [Art of Unit Testing 2nd Edition](https://www.manning.com/books/the-art-of-unit-testing-second-edition) Roy Osherove\n\n**Attributes of good unit test**\n\n- Automated\n- Maintainable\n- Runs very fast (in ms)\n- Consistent, Deterministic (always the same result)\n- Isolated from other tests\n- Readable\n- Can be executed by anyone\n- Testing public API, not internal behavior (overspecification)\n- Looks like production code\n- Treated as production code\n\n**Implementation**\n\nUnit tests should mainly test business logic (domain model): </br>\n![](docs/Images/unit_tests.jpg)\n\nEach unit test has 3 standard sections: Arrange, Act and Assert:\n\n![](docs/Images/UnitTestsGeneral.jpg)\n\n**1\\. Arrange**\n\nThe Arrange section is responsible for preparing the Aggregate for testing the public method that we want to test. This public method is often called (from the unit tests perspective) the SUT (system under test).\n\nCreating an Aggregate ready for testing involves **calling one or more other public constructors/methods** on the Domain Model. At first it may seem that we are testing too many things at the same time, but this is not true. We need to be one hundred percent sure that the Aggregate is in a state exactly as it will be in production. This can only be ensured when we:\n\n- **Use only public API of Domain Model**\n- Don't use [InternalsVisibleToAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=netframework-4.8) class\n  - This exposes the Domain Model to the Unit Tests library, removing encapsulation so our tests and production code are treated differently and it is a very bad thing\n- Don't use [ConditionalAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute?view=netframework-4.8) classes - it reduces readability and increases complexity\n- Don't create any special constructors/factory methods for tests (even with conditional compilation symbols)\n  - Special constructor/factory method only for unit tests causes duplication of business logic in the test itself and focuses on state - this kind of approach causes the test to be very sensitive to changes and hard to maintain\n- Don't remove encapsulation from Domain Model (for example: change keywords from `internal`/`private` to `public`)\n- Don't make methods `protected` to inherit from tested class and in this way provide access to internal methods/properties\n\n**Isolation of external dependencies**\n\nThere are 2 main concepts - stubs and mocks:\n\n> A stub is a controllable replacement for an existing dependency (or collaborator) in the system. By using a stub, you can test your code without dealing with the dependency directly.\n\n>A mock object is a fake object in the system that decides whether the unit test has passed or failed. It does so by verifying whether the object under test called the fake object as expected. There’s usually no more than one mock per test.\n>[Art of Unit Testing 2nd Edition](https://www.manning.com/books/the-art-of-unit-testing-second-edition) Roy Osherove\n\nGood advice: use stubs if you need to, but try to avoid mocks. Mocking causes us to test too many internal things and leads to overspecification.\n\n**2\\. Act**\n\nThis section is very easy - we execute **exactly one** public method on aggregate (SUT).\n\n**3\\. Assert**\n\nIn this section we check expectations. There are only 2 possible outcomes:\n\n- Method completed and Domain Event(s) published\n- Business rule was broken\n\nSimple example:\n\n```csharp\n[Test]\npublic void NewUserRegistration_WithUniqueLogin_IsSuccessful()\n{\n    // Arrange\n    var usersCounter = Substitute.For<IUsersCounter>();\n\n    // Act\n    var userRegistration =\n        UserRegistration.RegisterNewUser(\n            \"login\", \"password\", \"test@email\",\n            \"firstName\", \"lastName\", usersCounter);\n\n    // Assert\n    var newUserRegisteredDomainEvent = AssertPublishedDomainEvent<NewUserRegisteredDomainEvent>(userRegistration);\n    Assert.That(newUserRegisteredDomainEvent.UserRegistrationId, Is.EqualTo(userRegistration.Id));\n}\n\n[Test]\npublic void NewUserRegistration_WithoutUniqueLogin_BreaksUserLoginMustBeUniqueRule()\n{\n    // Arrange\n    var usersCounter = Substitute.For<IUsersCounter>();\n    usersCounter.CountUsersWithLogin(\"login\").Returns(x => 1);\n\n    // Assert\n    AssertBrokenRule<UserLoginMustBeUniqueRule>(() =>\n    {\n        // Act\n        UserRegistration.RegisterNewUser(\n            \"login\", \"password\", \"test@email\",\n            \"firstName\", \"lastName\", usersCounter);\n    });\n}\n```\n\nAdvanced example:\n\n```csharp\n[Test]\npublic void AddAttendee_WhenMemberIsAlreadyAttendeeOfMeeting_IsNotPossible()\n{\n    // Arrange\n    var creatorId = new MemberId(Guid.NewGuid());\n    var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n    {\n        CreatorId = creatorId\n    });\n    var newMemberId = new MemberId(Guid.NewGuid());\n    meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n    meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n\n    // Assert\n    AssertBrokenRule<MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule>(() =>\n    {\n        // Act\n        meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n    });\n}\n```\n\n`CreateMeetingTestData` method is an implementation of [SUT Factory](https://blog.ploeh.dk/2009/02/13/SUTFactory/) described by Mark Seemann which allows keeping common creation logic in one place:\n\n```csharp\nprotected MeetingTestData CreateMeetingTestData(MeetingTestDataOptions options)\n{\n    var proposalMemberId = options.CreatorId ?? new MemberId(Guid.NewGuid());\n    var meetingProposal = MeetingGroupProposal.ProposeNew(\n        \"name\", \"description\",\n        new MeetingGroupLocation(\"Warsaw\", \"PL\"), proposalMemberId);\n\n    meetingProposal.Accept();\n\n    var meetingGroup = meetingProposal.CreateMeetingGroup();\n\n    meetingGroup.UpdatePaymentInfo(DateTime.Now.AddDays(1));\n\n    var meetingTerm = options.MeetingTerm ??\n                      new MeetingTerm(DateTime.UtcNow.AddDays(1), DateTime.UtcNow.AddDays(2));\n\n    var rsvpTerm = options.RvspTerm ?? Term.NoTerm;\n    var meeting = meetingGroup.CreateMeeting(\"title\",\n        meetingTerm,\n        \"description\",\n        new MeetingLocation(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n        options.AttendeesLimit,\n        options.GuestsLimit,\n        rsvpTerm,\n        MoneyValue.Zero,\n        new List<MemberId>(),\n        proposalMemberId);\n\n    DomainEventsTestHelper.ClearAllDomainEvents(meetingGroup);\n\n    return new MeetingTestData(meetingGroup, meeting);\n}\n```\n\n### 3.11 Architecture Decision Log\n\nAll Architectural Decisions (AD) are documented in the [Architecture Decision Log (ADL)](docs/architecture-decision-log).\n\nMore information about documenting architecture-related decisions in this way : [https://github.com/joelparkerhenderson/architecture_decision_record](https://github.com/joelparkerhenderson/architecture_decision_record)\n\n### 3.12 Architecture Unit Tests\n\nIn some cases it is not possible to enforce the application architecture, design or established conventions using compiler (compile-time). For this reason, code implementations can diverge from the original design and architecture. We want to minimize this behavior, not only by code review.</br>\n\nTo do this, unit tests of system architecture, design, major conventions and assumptions  have been written. In .NET there is special library for this task: [NetArchTest](https://github.com/BenMorris/NetArchTest). This library has been written based on the very popular JAVA architecture unit tests library - [ArchUnit](https://www.archunit.org/).</br>\n\nUsing this kind of tests we can test proper layering of our application, dependencies, encapsulation, immutability, DDD correct implementation, naming, conventions and so on - everything what we need to test. Example:</br>\n\n![](docs/Images/architecture_unit_tests.png)\n\nMore information about architecture unit tests here: [https://blogs.oracle.com/javamagazine/unit-test-your-architecture-with-archunit](https://blogs.oracle.com/javamagazine/unit-test-your-architecture-with-archunit)\n\n### 3.13 Integration Tests\n\n#### Definition\n\n\"Integration Test\" term is blurred. It can mean test between classes, modules, services, even systems - see [this](https://martinfowler.com/bliki/IntegrationTest.html) article (by Martin Fowler). </br>\n\nFor this reason, the definition of integration test in this project is as follows:</br>\n\n- it verifies how system works in integration with \"out-of-process\" dependencies - database, messaging system, file system or external API\n- it tests particular use case\n- it can be slow (as opposed to Unit Test)\n\n#### Approach\n\n- **Do not mock dependencies over which you have full control** (like database). Full control dependency means you can always revert all changes (remove side-effects) and no one can notice it. They are not visible to others. See next point, please.\n- **Use \"production\", normal, real database version**. Some use e.g. in memory repository, some use light databases instead \"production\" version. This is still mocking. Testing makes sense if we have full confidence in testing. You can't trust the test if you know that the infrastructure in the production environment will vary. Be always as close to production environment as possible.\n- **Mock dependencies over which you don't have control**. No control dependency means you can't remove side-effects after interaction with this dependency (external API, messaging system, SMTP server etc.). They can be visible to others.\n\n#### Implementation\n\nIntegration test should test exactly one use case. One use case is represented by one Command/Query processing so CommandHandler/QueryHandler in Application layer is perfect starting point for running the Integration Test:</br>\n\n![](docs/Images/integration_tests.jpg)\nFor each test, the following preparation steps must be performed:</br>\n\n1. Clear database\n2. Prepare mocks\n3. Initialize testing module\n\n```csharp\n[SetUp]\npublic async Task BeforeEachTest()\n{\n    const string connectionStringEnvironmentVariable =\n        \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n    ConnectionString = Environment.GetEnvironmentVariable(connectionStringEnvironmentVariable, EnvironmentVariableTarget.Machine);\n    if (ConnectionString == null)\n    {\n        throw new ApplicationException(\n            $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n    }\n\n    using (var sqlConnection = new SqlConnection(ConnectionString))\n    {\n        await ClearDatabase(sqlConnection);\n    }\n\n    Logger = Substitute.For<ILogger>();\n    EmailSender = Substitute.For<IEmailSender>();\n    EventsBus = new EventsBusMock();\n    ExecutionContext = new ExecutionContextMock(Guid.NewGuid());\n    \n    PaymentsStartup.Initialize(\n        ConnectionString,\n        ExecutionContext,\n        Logger,\n        EventsBus,\n        false);\n\n    PaymentsModule = new PaymentsModule();\n}\n```\n\nAfter preparation, test is performed on clear database. Usually, it is the execution of some (or many) Commands and: </br>\na) running a Query or/and  </br>\nb) verifying mocks </br>\nto check the result.\n\n```csharp\n[TestFixture]\npublic class MeetingPaymentTests : TestBase\n{\n    [Test]\n    public async Task CreateMeetingPayment_Test()\n    {\n        PayerId payerId = new PayerId(Guid.NewGuid());\n        MeetingId meetingId = new MeetingId(Guid.NewGuid());\n        decimal value = 100;\n        string currency = \"EUR\";\n        await PaymentsModule.ExecuteCommandAsync(new CreateMeetingPaymentCommand(Guid.NewGuid(),\n            payerId, meetingId, value, currency));\n\n        var payment = await PaymentsModule.ExecuteQueryAsync(new GetMeetingPaymentQuery(meetingId.Value, payerId.Value));\n\n        Assert.That(payment.PayerId, Is.EqualTo(payerId.Value));\n        Assert.That(payment.MeetingId, Is.EqualTo(meetingId.Value));\n        Assert.That(payment.FeeValue, Is.EqualTo(value));\n        Assert.That(payment.FeeCurrency, Is.EqualTo(currency));\n    }\n}\n```\n\nEach Command/Query processing is a separate execution (with different object graph resolution, context, database connection etc.) thanks to Composition Root of each module. This behavior is important and desirable.\n\n### 3.14 System Integration Testing\n\n#### Definition\n\n[System Integration Testing (SIT)](https://en.wikipedia.org/wiki/System_integration_testing) is performed to verify the interactions between the modules of a software system. It involves the overall testing of a complete system of many subsystem components or elements.\n\n#### Implementation\n\nImplementation of system integration tests is based on approach of integration testing of modules in isolation (invoking commands and queries) described in the previous section.\n\nThe problem is that in this case we are dealing with **asynchronous communication**. Due to asynchrony, our **test must wait for the result** at certain times.\n\nTo correctly implement such tests, the **Sampling** technique and implementation described in the [Growing Object-Oriented Software, Guided by Tests](https://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627) book was used:\n\n>An asynchronous test must wait for success and use timeouts to detect failure. This implies that every tested activity must have an observable effect: a test must affect the system so that its observable state becomes different. This sounds obvious but it drives how we think about writing asynchronous tests. If an activity has no observable effect, there is nothing the test can wait for, and therefore no way for the test to synchronize with the system it is testing. There are two ways a test can observe the system: by sampling its observable state or by listening for events that it sends out.\n\n![](docs/Images/SystemIntegrationTests.jpg)\n\nTest below:\n\n1. Creates Meeting Group Proposal in Meetings module\n2. Waits until Meeting Group Proposal to verification will be available in Administration module with 10 seconds timeout\n3. Accepts Meeting Group Proposal in Administration module\n4. Waits until Meeting Group is created in Meetings module with 15 seconds timeout\n\n```csharp\npublic class CreateMeetingGroupTests : TestBase\n{\n    [Test]\n    public async Task CreateMeetingGroupScenario_WhenProposalIsAccepted()\n    {\n        var meetingGroupId = await MeetingsModule.ExecuteCommandAsync(\n            new ProposeMeetingGroupCommand(\"Name\",\n            \"Description\",\n            \"Location\",\n            \"PL\"));\n\n        AssertEventually(\n            new GetMeetingGroupProposalFromAdministrationProbe(meetingGroupId, AdministrationModule), \n            10000);\n\n        await AdministrationModule.ExecuteCommandAsync(new AcceptMeetingGroupProposalCommand(meetingGroupId));\n\n        AssertEventually(\n            new GetCreatedMeetingGroupFromMeetingsProbe(meetingGroupId, MeetingsModule),\n            15000);\n    }\n\n    private class GetCreatedMeetingGroupFromMeetingsProbe : IProbe\n    {\n        private readonly Guid _expectedMeetingGroupId;\n\n        private readonly IMeetingsModule _meetingsModule;\n\n        private List<MeetingGroupDto> _allMeetingGroups;\n\n        public GetCreatedMeetingGroupFromMeetingsProbe(\n            Guid expectedMeetingGroupId, \n            IMeetingsModule meetingsModule)\n        {\n            _expectedMeetingGroupId = expectedMeetingGroupId;\n            _meetingsModule = meetingsModule;\n        }\n\n        public bool IsSatisfied()\n        {\n            return _allMeetingGroups != null && \n                   _allMeetingGroups.Any(x => x.Id == _expectedMeetingGroupId);\n        }\n\n        public async Task SampleAsync()\n        {\n            _allMeetingGroups = await _meetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupsQuery());\n        }\n\n        public string DescribeFailureTo() \n            => $\"Meeting group with ID: {_expectedMeetingGroupId} is not created\";\n    }\n\n    private class GetMeetingGroupProposalFromAdministrationProbe : IProbe\n    {\n        private readonly Guid _expectedMeetingGroupProposalId;\n\n        private MeetingGroupProposalDto _meetingGroupProposal;\n\n        private readonly IAdministrationModule _administrationModule;\n\n        public GetMeetingGroupProposalFromAdministrationProbe(Guid expectedMeetingGroupProposalId, IAdministrationModule administrationModule)\n        {\n            _expectedMeetingGroupProposalId = expectedMeetingGroupProposalId;\n            _administrationModule = administrationModule;\n        }\n\n        public bool IsSatisfied()\n        {\n            if (_meetingGroupProposal == null)\n            {\n                return false;\n            }\n\n            if (_meetingGroupProposal.Id == _expectedMeetingGroupProposalId &&\n                _meetingGroupProposal.StatusCode == MeetingGroupProposalStatus.ToVerify.Value)\n            {\n                return true;\n            }\n\n            return false;\n        }\n\n        public async Task SampleAsync()\n        {\n            try\n            {\n                _meetingGroupProposal =\n                    await _administrationModule.ExecuteQueryAsync(\n                        new GetMeetingGroupProposalQuery(_expectedMeetingGroupProposalId));\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public string DescribeFailureTo()\n            => $\"Meeting group proposal with ID: {_expectedMeetingGroupProposalId} to verification not created\";\n    }\n}\n```\n\nPoller class implementation (based on example in the book):\n\n```csharp\npublic class Poller\n{\n    private readonly int _timeoutMillis;\n\n    private readonly int _pollDelayMillis;\n\n    public Poller(int timeoutMillis)\n    {\n        _timeoutMillis = timeoutMillis;\n        _pollDelayMillis = 1000;\n    }\n\n    public void Check(IProbe probe)\n    {\n        var timeout = new Timeout(_timeoutMillis);\n        while (!probe.IsSatisfied())\n        {\n            if (timeout.HasTimedOut())\n            {\n                throw new AssertErrorException(DescribeFailureOf(probe));\n            }\n\n            Thread.Sleep(_pollDelayMillis);\n            probe.SampleAsync();\n        }\n    }\n\n    private static string DescribeFailureOf(IProbe probe)\n    {\n        return probe.DescribeFailureTo();\n    }\n}\n```\n\n### 3.15 Event Sourcing\n\n#### Theory\n\nDuring the implementation of the Payment module, *Event Sourcing* was used. *Event Sourcing* is a way of preserving the state of our system by recording a sequence of events. No less, no more.\n\nIt is important here to really restore the state of our application from events. If we collect events only for auditing purposes, it is an [Audit Log/Trail](https://en.wikipedia.org/wiki/Audit_trail) - not the *Event Sourcing*.\n\nThe main elements of *Event Sourcing* are as follows:\n\n- Events Stream\n- Objects that are restored based on events. There are 2 types of such objects depending on the purpose:\n-- Objects responsible for the change of state. In Domain-Driven Design they will be *Aggregates*.\n-- *Projections*: read models prepared for a specific purpose\n- *Subscriptions* : a way to receive information about new events\n- *Snapshots*: from time to time, objects saved in the traditional way for performance purposes. Mainly used if there are many events to restore the object from the entire event history. (Note: there is currently no snapshot implementation in the project)\n\n![](docs/Images/ES_elements.jpg)\n\n#### Tool\n\nIn order not to reinvent the wheel, the *SQL Stream Store* library was used. As the [documentation](https://sqlstreamstore.readthedocs.io/en/latest/) says:\n\n*SQL Stream Store is a .NET library to assist with developing applications that use event sourcing or wish to use stream based patterns over a relational database and existing operational infrastructure.*\n\nLike every library, it has its limitations and assumptions (I recommend the linked documentation chapter \"Things you need to know before adopting\"). For me, the most important 2 points from this chapter are:\n\n1. *\"Subscriptions (and thus projections) are **eventually consistent** and always will be.\"* This means that there will always be an inconsistency time from saving the event to the stream and processing the event by the projector(s).\n2. *\"No support for ambient System.Transaction scopes enforcing the concept of the stream as the consistency and transactional boundary.\"* This means that if we save the event to a events stream and want to save something **in the same transaction**, we must use [TransactionScope](https://learn.microsoft.com/en-us/dotnet/api/system.transactions.transactionscope?view=net-8.0). If we cannot use *TransactionScope* for some reason, we must accept the Eventual Consistency also in this case.\n\nOther popular tools:\n\n- [EventStore](https://eventstore.com/) *\"An industrial-strength database solution built from the ground up for event sourcing.\"*\n- [Marten](https://martendb.io/) *\".NET Transactional Document DB and Event Store on PostgreSQL\"*\n\n#### Implementation\n\nThere are 2 main \"flows\" to handle:\n\n- Command handling: change of state - adding new events to stream (writing)\n- Projection of events to create read models\n\n##### Command Handling\n\nThe whole process looks like this:\n\n![](docs/Images/ES_command_handling.png)\n\n1. We create / update an aggregate by creating an event\n2. We add changes to the Aggregate Store. This is the class responsible for writing / loading our aggregates. We are not saving changes yet.\n3. As part of Unit Of Work  a) Aggregate Store adds events to the stream b) messages are added to the Outbox\n\nCommand Handler:\n\n```csharp\npublic class BuySubscriptionCommandHandler : ICommandHandler<BuySubscriptionCommand, Guid>\n{\n    private readonly IAggregateStore _aggregateStore;\n\n    private readonly IPayerContext _payerContext;\n\n    private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n    public BuySubscriptionCommandHandler(\n        IAggregateStore aggregateStore, \n        IPayerContext payerContext, \n        ISqlConnectionFactory sqlConnectionFactory)\n    {\n        _aggregateStore = aggregateStore;\n        _payerContext = payerContext;\n        _sqlConnectionFactory = sqlConnectionFactory;\n    }\n\n    public async Task<Guid> Handle(BuySubscriptionCommand command, CancellationToken cancellationToken)\n    {\n        var priceList = await PriceListProvider.GetPriceList(_sqlConnectionFactory.GetOpenConnection());\n\n        var subscriptionPayment = SubscriptionPayment.Buy(\n            _payerContext.PayerId,\n            SubscriptionPeriod.Of(command.SubscriptionTypeCode),\n            command.CountryCode,\n            MoneyValue.Of(command.Value, command.Currency),\n            priceList);\n        \n        _aggregateStore.AppendChanges(subscriptionPayment);\n\n        return subscriptionPayment.Id;\n    }\n}\n```\n\n`SubscriptionPayment` Aggregate:\n\n```csharp\npublic class SubscriptionPayment : AggregateRoot\n{\n    private PayerId _payerId;\n\n    private SubscriptionPeriod _subscriptionPeriod;\n\n    private string _countryCode;\n\n    private SubscriptionPaymentStatus _subscriptionPaymentStatus;\n\n    private MoneyValue _value;\n\n    protected override void Apply(IDomainEvent @event)\n    {\n        this.When((dynamic)@event);\n    }\n\n    public static SubscriptionPayment Buy(\n        PayerId payerId,\n        SubscriptionPeriod period,\n        string countryCode,\n        MoneyValue priceOffer,\n        PriceList priceList)\n    {\n        var priceInPriceList = priceList.GetPrice(countryCode, period, PriceListItemCategory.New);\n        CheckRule(new PriceOfferMustMatchPriceInPriceListRule(priceOffer, priceInPriceList));\n\n        var subscriptionPayment = new SubscriptionPayment();\n\n        var subscriptionPaymentCreated = new SubscriptionPaymentCreatedDomainEvent(\n            Guid.NewGuid(),\n            payerId.Value,\n            period.Code,\n            countryCode,\n            SubscriptionPaymentStatus.WaitingForPayment.Code,\n            priceOffer.Value,\n            priceOffer.Currency);\n\n        subscriptionPayment.Apply(subscriptionPaymentCreated);\n        subscriptionPayment.AddDomainEvent(subscriptionPaymentCreated);\n\n        return subscriptionPayment;\n    }\n\n    private void When(SubscriptionPaymentCreatedDomainEvent @event)\n    {\n        this.Id = @event.SubscriptionPaymentId;\n        _payerId = new PayerId(@event.PayerId);\n        _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n        _countryCode = @event.CountryCode;\n        _subscriptionPaymentStatus = SubscriptionPaymentStatus.Of(@event.Status);\n        _value = MoneyValue.Of(@event.Value, @event.Currency);\n    }\n```\n\n`AggregateRoot` base class:\n\n```csharp\npublic abstract class AggregateRoot\n{\n    public Guid Id { get; protected set; }\n\n    public int Version { get; private set; }\n\n    private readonly List<IDomainEvent> _domainEvents;\n\n    protected AggregateRoot()\n    {\n        _domainEvents = new List<IDomainEvent>();\n\n        Version = -1;\n    }\n\n    protected void AddDomainEvent(IDomainEvent @event)\n    {\n        _domainEvents.Add(@event);\n    }\n\n    public IReadOnlyCollection<IDomainEvent> GetDomainEvents() => _domainEvents.AsReadOnly();\n\n    public void Load(IEnumerable<IDomainEvent> history)\n    {\n        foreach (var e in history)\n        {\n            Apply(e);\n            Version++;\n        }\n    }\n\n    protected abstract void Apply(IDomainEvent @event);\n\n    protected static void CheckRule(IBusinessRule rule)\n    {\n        if (rule.IsBroken())\n        {\n            throw new BusinessRuleValidationException(rule);\n        }\n    }\n}\n\n```\n\nAggregate Store implementation with SQL Stream Store library usage:\n\n```csharp\npublic class SqlStreamAggregateStore : IAggregateStore\n{\n    private readonly IStreamStore _streamStore;\n\n    private readonly List<IDomainEvent> _appendedChanges;\n\n    private readonly List<AggregateToSave> _aggregatesToSave;\n\n    public SqlStreamAggregateStore(\n        ISqlConnectionFactory sqlConnectionFactory)\n    {\n        _appendedChanges = new List<IDomainEvent>();\n\n        _streamStore =\n            new MsSqlStreamStore(\n                new MsSqlStreamStoreSettings(sqlConnectionFactory.GetConnectionString())\n                    {\n                        Schema = DatabaseSchema.Name\n                });\n\n        _aggregatesToSave = new List<AggregateToSave>();\n    }\n\n    public async Task Save()\n    {\n        foreach (var aggregateToSave in _aggregatesToSave)\n        {\n            await _streamStore.AppendToStream(\n                GetStreamId(aggregateToSave.Aggregate),\n                aggregateToSave.Aggregate.Version,\n                aggregateToSave.Messages.ToArray());\n        }\n\n        _aggregatesToSave.Clear();\n    }\n\n    public async Task<T> Load<T>(AggregateId<T> aggregateId) where T : AggregateRoot\n    {\n        var streamId = GetStreamId(aggregateId);\n\n        IList<IDomainEvent> domainEvents = new List<IDomainEvent>();\n        ReadStreamPage readStreamPage;\n        do\n        {\n            readStreamPage = await _streamStore.ReadStreamForwards(streamId, StreamVersion.Start, maxCount: 100);\n            var messages = readStreamPage.Messages;\n            foreach (var streamMessage in messages)\n            {\n                Type type = DomainEventTypeMappings.Dictionary[streamMessage.Type];\n                var jsonData = await streamMessage.GetJsonData();\n                var domainEvent = JsonConvert.DeserializeObject(jsonData, type) as IDomainEvent;\n\n                domainEvents.Add(domainEvent);\n            }\n        } while (!readStreamPage.IsEnd);\n\n        var aggregate = (T)Activator.CreateInstance(typeof(T), true);\n\n        aggregate.Load(domainEvents);\n\n        return aggregate;\n    }\n\n```\n\n##### Events Projection\n\nThe whole process looks like this:\n\n![](docs/Images/ES_events_projection.png)\n\n1. Special class `Subscriptions Manager` subscribes to Events Store (using SQL Store Stream library)\n2. Events Store raises `StreamMessageRecievedEvent`\n3. `Subscriptions Manager` invokes all projectors\n4. If projector know how to handle given event, it updates particular read model. In current implementation it updates special table in SQL database.\n\n`SubscriptionsManager` class implementation:\n\n```csharp\npublic class SubscriptionsManager\n{\n    private readonly IStreamStore _streamStore;\n\n    public SubscriptionsManager(\n        IStreamStore streamStore)\n    {\n        _streamStore = streamStore;\n    }\n\n    public void Start()\n    {\n        long? actualPosition;\n\n        using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n        {\n            var checkpointStore = scope.Resolve<ICheckpointStore>();\n\n            actualPosition = checkpointStore.GetCheckpoint(SubscriptionCode.All);\n        }\n\n        _streamStore.SubscribeToAll(actualPosition, StreamMessageReceived);\n    }\n\n    public void Stop()\n    {\n        _streamStore.Dispose();\n    }\n\n    private static async Task StreamMessageReceived(\n        IAllStreamSubscription subscription, StreamMessage streamMessage, CancellationToken cancellationToken)\n    {\n        var type = DomainEventTypeMappings.Dictionary[streamMessage.Type];\n        var jsonData = await streamMessage.GetJsonData(cancellationToken);\n        var domainEvent = JsonConvert.DeserializeObject(jsonData, type) as IDomainEvent;\n\n        using var scope = PaymentsCompositionRoot.BeginLifetimeScope();\n\n        var projectors = scope.Resolve<IList<IProjector>>();\n\n        var tasks = projectors\n            .Select(async projector =>\n            {\n                await projector.Project(domainEvent);\n            });\n\n        await Task.WhenAll(tasks);\n\n        var checkpointStore = scope.Resolve<ICheckpointStore>();\n        await checkpointStore.StoreCheckpoint(SubscriptionCode.All, streamMessage.Position);\n    }\n}\n\n```\n\nExample projector:\n\n```csharp\ninternal class SubscriptionDetailsProjector : ProjectorBase, IProjector\n{\n    private readonly IDbConnection _connection;\n\n    public SubscriptionDetailsProjector(ISqlConnectionFactory sqlConnectionFactory)\n    {\n        _connection = sqlConnectionFactory.GetOpenConnection();\n    }\n\n    public async Task Project(IDomainEvent @event)\n    {\n        await When((dynamic) @event);\n    }\n\n    private async Task When(SubscriptionRenewedDomainEvent subscriptionRenewed)\n    {\n        var period = SubscriptionPeriod.GetName(subscriptionRenewed.SubscriptionPeriodCode);\n        \n        await _connection.ExecuteScalarAsync(\"UPDATE payments.SubscriptionDetails \" +\n                                                \"SET \" +\n                                                    \"[Status] = @Status, \" +\n                                                    \"[ExpirationDate] = @ExpirationDate, \" +\n                                                    \"[Period] = @Period \" +\n                                                \"WHERE [Id] = @SubscriptionId\",\n            new\n            {\n                subscriptionRenewed.SubscriptionId,\n                subscriptionRenewed.Status,\n                subscriptionRenewed.ExpirationDate,\n                period\n            });\n    }\n\n    private async Task When(SubscriptionExpiredDomainEvent subscriptionExpired)\n    {\n        await _connection.ExecuteScalarAsync(\"UPDATE payments.SubscriptionDetails \" +\n                                             \"SET \" +\n                                             \"[Status] = @Status \" +\n                                             \"WHERE [Id] = @SubscriptionId\",\n            new\n            {\n                subscriptionExpired.SubscriptionId,\n                subscriptionExpired.Status\n            });\n    }\n\n    private async Task When(SubscriptionCreatedDomainEvent subscriptionCreated)\n    {\n        var period = SubscriptionPeriod.GetName(subscriptionCreated.SubscriptionPeriodCode);\n        \n        await _connection.ExecuteScalarAsync(\"INSERT INTO payments.SubscriptionDetails \" +\n                                       \"([Id], [Period], [Status], [CountryCode], [ExpirationDate]) \" +\n                                       \"VALUES (@SubscriptionId, @Period, @Status, @CountryCode, @ExpirationDate)\",\n            new\n            {\n                subscriptionCreated.SubscriptionId,\n                period,\n                subscriptionCreated.Status,\n                subscriptionCreated.CountryCode,\n                subscriptionCreated.ExpirationDate\n            });\n    }\n}\n\n```\n\n#### Sample view of Event Store\n\nSample *Event Store* view after execution of SubscriptionLifecycleTests Integration Test which includes following steps:\n\n1. Creating Price List\n2. Buying Subscription\n3. Renewing Subscription\n4. Expiring Subscription\n\nlooks like this (*SQL Stream Store* table - *payments.Messages*):\n\n![](docs/Images/ES_event_store_db_sample.png)\n\n### 3.16 Database Change Management\n\nDatabase change management is accomplished by *migrations/transitions* versioning. Additionally, the current state of the database structure is also versioned.\n\nMigrations are applied using a simple [DatabaseMigrator](src/Database/DatabaseMigrator) console application that uses the [DbUp](https://dbup.readthedocs.io/en/latest/) library. The current state of the database structure is kept in the [SSDT Database Project](https://docs.microsoft.com/en-us/sql/ssdt/how-to-create-a-new-database-project).\n\nThe database update is performed by running the following command:\n\n```shell\ndotnet DatabaseMigrator.dll \"connection_string\" \"scripts_directory_path\"\n```\n\nThe entire solution is described in detail in the following articles:\n\n1. [Database change management](https://www.kamilgrzybek.com/database/database-change-management/) (theory)\n2. [Using database project and DbUp for database management](https://www.kamilgrzybek.com/database/using-database-project-and-dbup-for-database-management/) (implementation)\n\n### 3.17 Continuous Integration\n\n#### Definition\n\nAs defined on [Martin Fowler's website](https://martinfowler.com/articles/continuousIntegration.html):\n> *Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible.*\n\n#### YAML Implementation [OBSOLETE]\n\n*Originally the build was implemented using yaml and GitHub Actions functionality. Currently, the build is implemented with NUKE (see next section). See [buildPipeline.yml](.github/workflows/buildPipeline.yml)* file history.\n\n##### Pipeline description\n\nCI was implemented using [GitHub Actions](https://docs.github.com/en/actions/getting-started-with-github-actions/about-github-actions). For this purpose, one workflow, which triggers on Pull Request to *master* branch or Push to *master* branch was created. It contains 2 jobs:\n\n- build test, execute Unit Tests and Architecture Tests\n- execute Integration Tests\n\n![](docs/Images/ci.jpg)\n\n**Steps description**<br/>\na) Checkout repository - clean checkout of git repository <br/>\nb) Setup .NET - install .NET 8.0 SDK<br/>\nc) Install dependencies - resolve NuGet packages<br/>\nd) Build - build solution<br/>\ne) Run Unit Tests - run automated Unit Tests (see section 3.10)<br/>\nf) Run Architecture Tests - run automated Architecture Tests (see section 3.12)<br/>\ng) Initialize containers - setup Docker container for MS SQL Server<br/>\nh) Wait for SQL Server initialization - after container initialization MS SQL Server is not ready, initialization of server itself takes some time so 30 seconds timeout before execution of next step is needed<br/>\ni) Create Database - create and initialize database<br/>\nj) Migrate Database - execute database upgrade using *DatabaseMigrator* application (see 3.16 section)<br/>\nk) Run Integration Tests - perform Integration and System Integration Testing (see section 3.13 and 3.14)<br/>\n\n##### Workflow definition\n\nWorkflow definition: [buildPipeline.yml](.github/workflows/buildPipeline.yml)\n\n##### Example workflow execution\n\nExample workflow output:\n\n![](docs/Images/ci_job1.png)\n\n![](docs/Images/ci_job2.png)\n\n#### NUKE\n\n[Nuke](https://nuke.build/) is *the cross-platform build automation solution for .NET with C# DSL.*\n\nThe 2 main advantages of its use over pure yaml defined in GitHub actions are as follows:\n\n- You run the same code on local machine and in the build server. See [buildPipeline.yml](.github/workflows/buildPipeline.yml)\n- You use C# with all the goodness (debugging, compilation, packages, refactoring and so on)\n\nThis is how one of the stage definition looks like (execute Build, Unit Tests, Architecture Tests) [Build.cs](build/Build.cs):\n\n```csharp\npartial class Build : NukeBuild\n{\n    /// Support plugins are available for:\n    ///   - JetBrains ReSharper        https://nuke.build/resharper\n    ///   - JetBrains Rider            https://nuke.build/rider\n    ///   - Microsoft VisualStudio     https://nuke.build/visualstudio\n    ///   - Microsoft VSCode           https://nuke.build/vscode\n\n    public static int Main () => Execute<Build>(x => x.Compile);\n\n    [Parameter(\"Configuration to build - Default is 'Debug' (local) or 'Release' (server)\")]\n    readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;\n\n    [Solution] readonly Solution Solution;\n\n    Target Clean => _ => _\n        .Before(Restore)\n        .Executes(() =>\n        {\n            EnsureCleanDirectory(WorkingDirectory);\n        });\n\n    Target Restore => _ => _\n        .Executes(() =>\n        {\n            DotNetRestore(s => s\n                .SetProjectFile(Solution));\n        });\n\n    Target Compile => _ => _\n        .DependsOn(Restore)\n        .Executes(() =>\n        {\n            DotNetBuild(s => s\n                .SetProjectFile(Solution)\n                .SetConfiguration(Configuration)\n                .EnableNoRestore());\n        });\n\n    Target UnitTests => _ => _\n        .DependsOn(Compile)\n        .Executes(() =>\n        {\n            DotNetTest(s => s\n                .SetProjectFile(Solution)\n                .SetFilter(\"UnitTests\")\n                .SetConfiguration(Configuration)\n                .EnableNoRestore()\n                .EnableNoBuild());\n        });\n\n    Target ArchitectureTests => _ => _\n        .DependsOn(UnitTests)\n        .Executes(() =>\n        {\n            DotNetTest(s => s\n                .SetProjectFile(Solution)\n                .SetFilter(\"ArchTests\")\n                .SetConfiguration(Configuration)\n                .EnableNoRestore()\n                .EnableNoBuild());\n        });\n\n    Target BuildAndUnitTests => _ => _\n        .Triggers(ArchitectureTests)\n        .Executes(() =>\n        {\n        });\n}\n\n```\n\nIf you want to see more complex scenario when integration tests are executed (with SQL Server database creation using docker) see [BuildIntegrationTests.cs](build/BuildIntegrationTests.cs) file.\n\n#### SQL Server database project build\n\nCurrently, compilation of database projects is not supported by the .NET Core and dotnet tool. For this reason, the [MSBuild.Sdk.SqlProj](https://github.com/rr-wfm/MSBuild.Sdk.SqlProj/) library was used. In order to do that, you need to create .NET standard library, change SDK and create links to scripts folders. Final [database project](src/Database/CompanyName.MyMeetings.Database.Build/CompanyName.MyMeetings.Database.Build.csproj) looks as follows:\n\n```xml\n<Project Sdk=\"MSBuild.Sdk.SqlProj/1.6.0\">\n    <PropertyGroup>\n        <TargetFramework>netstandard2.0</TargetFramework>\n    </PropertyGroup>\n    <ItemGroup>\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\administration\\**\\*.sql\" />\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\app\\**\\*.sql\" />\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\meetings\\**\\*.sql\" />\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\payments\\**\\*.sql\" />\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\users\\**\\*.sql\" />\n        <Content Include=\"..\\CompanyName.MyMeetings.Database\\Security\\**\\*.sql\" />\n    </ItemGroup>\n</Project>\n```\n\n### 3.18 Static code analysis\n\nIn order to standardize the appearance of the code and increase its readability, the [StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) library was used. This library implements StyleCop rules using the .NET Compiler Platform and is responsible for the static code analysis.<br/>\n\nUsing this library is trivial - it is just added as a NuGet package to all projects. There are many ways to configure rules, but currently the best way to do this is to edit the [.editorconfig](src/.editorconfig) file. More information can be found at the link above.<br/>\n\n**Note! Static code analysis works best when the following points are met:**<br/>\n\n1. Each developer has an IDE that respects the rules and helps to follow them\n2. The rules are checked during the project build process as part of Continuous Integration\n3. The rules are set to *help your system grow*. **Static analysis is not a value in itself.** Some rules may not make complete sense and should be turned off. Other rules may have higher priority. It all depends on the project, company standards and people involved in the project. Be pragmatic.\n\n### 3.19 System Under Test SUT\n\nThere is always a need to prepare the entire system in a specific state, e.g. for manual, exploratory, UX / UI tests. The fact that the tests are performed manually does not mean that we cannot automate the preparation phase (Given / Arrange). Thanks to the automation of system state preparation ([System Under Test](https://en.wikipedia.org/wiki/System_under_test)), we are able to recreate exactly the same state in any environment. In addition, such automation can be used later to automate the entire test (e.g. through an [3.13 Integration Tests](#313-integration-tests)).<br/>\n\nThe implementation of such automation based on the use of NUKE and the test framework is presented below. As in the case of integration testing, we use the public API of modules.\n\n![](docs/Images/sut-preparation.jpg)\n\nBelow is a SUT whose task is to go through the whole process - from setting up a *Meeting Group*, through its *Payment*, adding a new *Meeting* and signing up for it by another user.\n\n```csharp\npublic class CreateMeeting : TestBase\n{\n    protected override bool PerformDatabaseCleanup => true;\n\n    [Test]\n    public async Task Prepare()\n    {\n        await UsersFactory.GivenAdmin(\n            UserAccessModule,\n            \"testAdmin@mail.com\",\n            \"testAdminPass\",\n            \"Jane Doe\",\n            \"Jane\",\n            \"Doe\",\n            \"testAdmin@mail.com\");\n\n        var userId = await UsersFactory.GivenUser(\n            UserAccessModule,\n            ConnectionString,\n            \"adamSmith@mail.com\",\n            \"adamSmithPass\",\n            \"Adam\",\n            \"Smith\",\n            \"adamSmith@mail.com\");\n\n        ExecutionContextAccessor.SetUserId(userId);\n\n        var meetingGroupId = await MeetingGroupsFactory.GivenMeetingGroup(\n            MeetingsModule,\n            AdministrationModule,\n            ConnectionString,\n            \"Software Craft\",\n            \"Group for software craft passionates\",\n            \"Warsaw\",\n            \"PL\");\n\n        await TestPriceListManager.AddPriceListItems(PaymentsModule, ConnectionString);\n\n        await TestPaymentsManager.BuySubscription(\n            PaymentsModule,\n            ExecutionContextAccessor);\n        \n        SetDate(new DateTime(2022, 7, 1, 10, 0, 0));\n\n        var meetingId = await TestMeetingFactory.GivenMeeting(\n            MeetingsModule,\n            meetingGroupId,\n            \"Tactical DDD\",\n            new DateTime(2022, 7, 10, 18, 0, 0),\n            new DateTime(2022, 7, 10, 20, 0, 0),\n            \"Meeting about Tactical DDD patterns\",\n            \"Location Name\",\n            \"Location Address\",\n            \"01-755\",\n            \"Warsaw\",\n            50,\n            0,\n            null,\n            null,\n            0,\n            null,\n            new List<Guid>()\n        );\n        \n        var attendeeUserId = await UsersFactory.GivenUser(\n            UserAccessModule,\n            ConnectionString,\n            \"rickmorty@mail.com\",\n            \"rickmortyPass\",\n            \"Rick\",\n            \"Morty\",\n            \"rickmorty@mail.com\");\n        \n        ExecutionContextAccessor.SetUserId(attendeeUserId);\n\n        await TestMeetingGroupManager.JoinToGroup(MeetingsModule, meetingGroupId);\n\n        await TestMeetingManager.AddAttendee(MeetingsModule, meetingId, guestsNumber: 1);\n    }\n}\n```\n\nYou can create this SUT using following *NUKE* target providing connection string and particular test name:\n\n```shell\n .\\build PrepareSUT --DatabaseConnectionString \"connection_string\" --SUTTestName CreateMeeting\n```\n\n### 3.20 Mutation Testing\n\n#### Description\n\nMutation testing is an approach to test and evaluate our existing tests. During mutation testing a special framework modifies pieces of our code and runs our tests. These modifications are called *mutations* or *mutants*. If a given *mutation* does not cause a failure of at least once test, it means that the mutant has *survived* so our tests are probably not sufficient.\n\n#### Example\n\nIn this repository, the [Stryker.NET](https://stryker-mutator.io/docs/stryker-net/Introduction) framework was used for mutation testing. In the simplest use, after installation, all you need to do is enter the directory of tests that you want to mutate and run the following command:\n\n```shell\ndotnet stryker\n```\n\nThe result of this command is the *mutation report file*. Assuming we want to test the unit tests of the Meetings module, such a [report](docs/mutation-tests-reports/mutation-report.html) has been generated. This is its first page:\n\n![](docs/Images/mutation_testing_report.png)\n\nLet us analyze one of the places where the mutant survived. This is the *AddNotAttendee* method of the *Meeting* class. This method is used to add a *Member* to the list of people who have decided not to attend the meeting. According to the logic, if the same person previously indicated that he was going to the *Meeting* and later changed his mind, then if there is someone on the *Waiting List*, he should be added to the attendees. Based on requirements, this should be the person who signed up on the *Waiting List* **first** (based on **SignUpDate**).\n\n![](docs/Images/mutation_testing_example.png)\n\nAs you can see, the mutation framework changed our sorting in linq query (from default ascending to descending). However, each test was successful, so it means that mutant survived so we don't have a test that checks the correct sort based on *SignUpDate*.\n\nFrom the example above, one more important thing can be deduced - **code coverage is insufficient**. In the given example, this code is covered, but our tests do not check the given requirement, therefore our code may have errors. Mutation testing allow to detect such situations. Of course, as with any tool, we should use it wisely, as not every case requires our attention.\n\n## 4. Technology\n\nList of technologies, frameworks and libraries used for implementation:\n\n- [.NET 8.0](https://dotnet.microsoft.com/download) (platform). Note for Visual Studio users: **VS 2019** is required.\n- [MS SQL Server Express](https://www.microsoft.com/en-us/sql-server/sql-server-editions-express) (database)\n- [Entity Framework Core 8.0](https://docs.microsoft.com/en-us/ef/core/) (ORM Write Model implementation for DDD)\n- [Autofac](https://autofac.org/) (Inversion of Control Container)\n- [IdentityServer4](http://docs.identityserver.io) (Authentication and Authorization)\n- [Serilog](https://serilog.net/) (structured logging)\n- [Hellang.Middleware.ProblemDetails](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails) (API Problem Details support)\n- [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle) (Swagger automated documentation)\n- [Dapper](https://github.com/StackExchange/Dapper) (micro ORM for Read Model)\n- [Newtonsoft.Json](https://www.newtonsoft.com/json) (serialization/deserialization to/from JSON)\n- [Quartz.NET](https://www.quartz-scheduler.net/) (background processing)\n- [FluentValidation](https://fluentvalidation.net/) (data validation)\n- [MediatR](https://github.com/jbogard/MediatR) (mediator implementation)\n- [Postman](https://www.getpostman.com/) (API tests)\n- [NUnit](https://nunit.org/) (Testing framework)\n- [NSubstitute](https://nsubstitute.github.io/) (Testing isolation framework)\n- [Visual Paradigm Community Edition](https://www.visual-paradigm.com/download/community.jsp) (CASE tool for modeling and documentation)\n- [NetArchTest](https://github.com/BenMorris/NetArchTest) (Architecture Unit Tests library)\n- [Polly](https://github.com/App-vNext/Polly) (Resilience and transient-fault-handling library)\n- [SQL Stream Store](https://github.com/SQLStreamStore) (Library to assist with Event Sourcing)\n- [DbUp](https://dbup.readthedocs.io/en/latest/) (Database migrations deployment)\n- [SSDT Database Project](https://docs.microsoft.com/en-us/sql/ssdt/how-to-create-a-new-database-project) (Database structure versioning)\n- [GitHub Actions](https://docs.github.com/en/actions) (Continuous Integration workflows implementation)\n- [StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) (Static code analysis library)\n- [PlantUML](https://plantuml.com) (UML diagrams from textual description, diagrams as text)\n- [C4 Model](https://c4model.com/) (Model for visualising software architecture)\n- [C4-PlantUML](https://github.com/plantuml-stdlib/C4-PlantUML) (C4 Model for PlantUML plugin)\n- [NUKE](https://nuke.build/) (Build automation system)\n- [MSBuild.Sdk.SqlProj](https://github.com/rr-wfm/MSBuild.Sdk.SqlProj/) (Database project compilation)\n- [Stryker.NET](https://stryker-mutator.io/docs/stryker-net/Introduction) (Mutation Testing framework)\n\n## 5. How to Run\n\n### Install .NET 8.0 SDK\n\n- [Download](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) and install .NET 8.0 SDK\n\n### Create database\n\n- Download and install MS SQL Server Express or other\n- Create an empty database using [CreateDatabase_Windows.sql](src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Windows.sql) or [CreateDatabase_Linux.sql](src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Linux.sql). Script adds **app** schema which is needed for migrations journal table. Change database file path if needed.\n- Run database migrations using **MigrateDatabase** NUKE target by executing the build.sh script present in the root folder:\n\n```shell\n.\\build MigrateDatabase --DatabaseConnectionString \"connection_string\"\n```\n\n*\"connection_string\"* - connection string to your database\n\n### Seed database\n\n- Execute [SeedDatabase.sql](src/Database/CompanyName.MyMeetings.Database/Scripts/SeedDatabase.sql) script\n- 2 test users will be created - check the script for usernames and passwords\n\n### Configure connection string\n\nSet a database connection string called `MeetingsConnectionString` in the root of the API project's appsettings.json or use [Secrets](https://blogs.msdn.microsoft.com/mihansen/2017/09/10/managing-secrets-in-net-core-2-0-apps/)\n\nExample config setting in appsettings.json for a database called `MyMeetings`:\n\n```json\n{\n \"MeetingsConnectionString\": \"Server=(localdb)\\\\mssqllocaldb;Database=MyMeetings;Trusted_Connection=True;\"\n}\n```\n\n### Configure startup in IDE\n\n- Set the Startup Item in your IDE to the API Project, not IIS Express\n\n### Authenticate\n\n- Once it is running you'll need a token to make API calls. This is done via OAuth2 [Resource Owner Password Grant Type](https://www.oauth.com/oauth2-servers/access-tokens/password-grant/). By default IdentityServer is configured with the following:\n- `client_id = ro.client`\n- `client_secret = secret` **(this is literally the value - not a statement that this value is secret!)**\n- `scope = myMeetingsAPI openid profile`\n- `grant_type = password`\n\nInclude the credentials of a test user created in the [SeedDatabase.sql](src/Database/CompanyName.MyMeetings.Database/Scripts/SeedDatabase.sql) script - for example:\n\n- `username = testMember@mail.com`\n- `password = testMemberPass`\n\n**Example HTTP Request for an Access Token:**\n\n```http\nPOST /connect/token HTTP/1.1\nHost: localhost:5000\n \ngrant_type=password\n&username=testMember@mail.com\n&password=testMemberPass\n&client_id=ro.client\n&client_secret=secret\n```\n\nThis will fetch an access token for this user to make authorized API requests using the HTTP request header `Authorization: Bearer <access_token>`\n\nIf you use a tool such as Postman to test your API, the token can be fetched and stored within the tool itself and appended to all API calls. Check your tool documentation for instructions.\n\n### Run using Docker Compose\n\nYou can run whole application using [docker compose](https://docs.docker.com/compose/) from root folder:\n\n```shell\ndocker-compose up\n```\n\nIt will create following services: <br/>\n\n- MS SQL Server Database\n- Database Migrator\n- Application\n\n### Run Integration Tests in Docker\n\nYou can run all Integration Tests in Docker (exactly the same process is executed on CI) using **RunAllIntegrationTests** NUKE target:\n\n```shell\n.\\build RunAllIntegrationTests\n```\n\n## 6. Contribution\n\nThis project is still under analysis and development. I assume its maintenance for a long time and I would appreciate your contribution to it. Please let me know by creating an Issue or Pull Request.\n\n## 7. Roadmap\n\nList of features/tasks/approaches to add:\n\n| Name                               | Status | Release date |\n|------------------------------------| -------- |--------------|\n| Domain Model Unit Tests            |Completed | 2019-09-10   |\n| Architecture Decision Log update   |  Completed | 2019-11-09   |\n| Integration automated tests        | Completed | 2020-02-24   |\n| Migration to .NET Core 3.1         |Completed  | 2020-03-04   |\n| System Integration Testing         | Completed  | 2020-03-28   |\n| More advanced Payments module      | Completed  | 2020-07-11   |\n| Event Sourcing implementation      | Completed  | 2020-07-11   |\n| Database Change Management         | Completed  | 2020-08-23   |\n| Continuous Integration             | Completed  | 2020-09-01   |\n| StyleCop Static Code Analysis      | Completed  | 2020-09-05   |\n| FrontEnd SPA application           | Completed | 2020-11-08   |\n| Docker support                     | Completed | 2020-11-26   |\n| PlantUML Conceptual Model          | Completed | 2021-03-22   |\n| C4 Model                           | Completed | 2021-03-29   |\n| Meeting comments feature           | Completed | 2021-03-30   |\n| NUKE build automation              | Completed | 2021-06-15   |\n| Database project compilation on CI | Completed | 2021-06-15   |\n| System Under Test implementation   | Completed | 2022-07-17   |\n| Mutation Testing                   | Completed | 2022-08-23   |\n| Migration to .NET 8.0              | Completed | 2023-12-09   |\n\nNOTE: Please don't hesitate to suggest something else or a change to the existing code. All proposals will be considered.\n\n## 8. Authors\n\nKamil Grzybek\n\nBlog: [https://kamilgrzybek.com](https://kamilgrzybek.com)\n\nTwitter: [https://twitter.com/kamgrzybek](https://twitter.com/kamgrzybek)\n\nLinkedIn: [https://www.linkedin.com/in/kamilgrzybek/](https://www.linkedin.com/in/kamilgrzybek/)\n\nGitHub: [https://github.com/kgrzybek](https://github.com/kgrzybek)\n\n### 8.1 Main contributors\n\n- [Andrei Ganichev](https://github.com/AndreiGanichev)\n- [Bela Istok](https://github.com/bistok)\n- [Almar Aubel](https://github.com/AlmarAubel)\n\n## 9. License\n\nThe project is under [MIT license](https://opensource.org/licenses/MIT).\n\n## 10. Inspirations and Recommendations\n\n### Modular Monolith\n\n- [\"Modular Monolith: A Primer\"](https://www.kamilgrzybek.com/design/modular-monolith-primer/) Modular Monolith architecture article series, Kamil Grzybek\n- [\"Modular Monolith Architecture: One to rule them all\"](https://www.youtube.com/watch?v=njDSXUWeik0) presentation, Kamil Grzybek\n- [\"Modular Monoliths\"](https://www.youtube.com/watch?v=5OjqD-ow8GE) presentation, Simon Brown\n- [\"Majestic Modular Monoliths\"](https://www.youtube.com/watch?v=BOvxJaklcr0) presentation, Axel Fontaine\n- [\"Building Better Monoliths – Modulithic Applications with Spring Boot\"](https://speakerdeck.com/olivergierke/building-better-monoliths-modulithic-applications-with-spring-boot-cd16e6ec-d334-497d-b9f6-3f92d5db035a) slides, Oliver Drotbohm\n- [\"MonolithFirst\"](https://martinfowler.com/bliki/MonolithFirst.html) article, Martin Fowler\n- [\"Pattern: Monolithic Architecture\"](https://microservices.io/patterns/monolithic.html) pattern description, Chris Richardson\n\n### Domain-Driven Design\n\n- [\"Domain-Driven Design: Tackling Complexity in the Heart of Software\"](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215) book, Eric Evans\n- [\"Implementing Domain-Driven Design\"](https://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577) book, Vaughn Vernon\n- [\"Domain-Driven Design Distilled\"](https://www.amazon.com/dp/0134434420) book, Vaughn Vernon\n- [\"Patterns, Principles, and Practices of Domain-Driven Design\"](https://www.amazon.com/Patterns-Principles-Practices-Domain-Driven-Design-ebook/dp/B00XLYUA0W) book, Scott Millett, Nick Tune\n- [\"Secure By Design\"](https://www.amazon.com/Secure-Design-Daniel-Deogun/dp/1617294357) book, Daniel Deogun, Dan Bergh Johnsson, Daniel Sawano\n- [\"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice\"](https://www.amazon.com/Hands-Domain-Driven-Design-NET-ebook/dp/B07C5WSR9B) book, Alexey Zimarev\n- [\"Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#\"](https://www.amazon.com/Domain-Modeling-Made-Functional-Domain-Driven-ebook/dp/B07B44BPFB) book, Scott Wlaschin\n- [\"DDD by examples - library\"](https://github.com/ddd-by-examples/library) GH repository, Jakub Pilimon, Bartłomiej Słota\n- [\"IDDD_Samples\"](https://github.com/VaughnVernon/IDDD_Samples) GH repository, Vaughn Vernon\n- [\"IDDD_Samples_NET\"](https://github.com/VaughnVernon/IDDD_Samples_NET) GH repository, Vaughn Vernon\n- [\"Awesome Domain-Driven Design\"](https://github.com/heynickc/awesome-ddd) GH repository, Nick Chamberlain\n\n### Application Architecture\n\n- [\"Patterns of Enterprise Application Architecture\"](https://martinfowler.com/books/eaa.html) book, Martin Fowler\n- [\"Dependency Injection Principles, Practices, and Patterns\"](https://www.manning.com/books/dependency-injection-principles-practices-patterns) book, Steven van Deursen, Mark Seemann\n- [\"Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series\"](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164) book, Robert C. Martin\n- [\"The Clean Architecture\"](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) article, Robert C. Martin\n- [\"The Onion Architecture\"](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/) article series, Jeffrey Palermo\n- [\"Hexagonal/Ports & Adapters Architecture\"](https://web.archive.org/web/20180822100852/http://alistair.cockburn.us/Hexagonal+architecture) article, Alistair Cockburn\n- [\"DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together\"](https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/) article, Herberto Graca\n\n### Software Architecture\n\n- [\"Software Architecture in Practice (3rd Edition)\"](https://www.amazon.com/Software-Architecture-Practice-3rd-Engineering/dp/0321815734) book, Len Bass, Paul Clements, Rick Kazman\n- [\"Software Architecture for Developers Vol 1 & 2\"](https://softwarearchitecturefordevelopers.com/) book, Simon Brown\n- [\"Just Enough Software Architecture: A Risk-Driven Approach\"](https://www.amazon.com/Just-Enough-Software-Architecture-Risk-Driven/dp/0984618104) book, George H. Fairbanks\n- [\"Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives (2nd Edition)\"](https://www.amazon.com/Software-Systems-Architecture-Stakeholders-Perspectives/dp/032171833X/) book, Nick Rozanski, Eóin Woods\n- [\"Design It!: From Programmer to Software Architect (The Pragmatic Programmers)\"](https://www.amazon.com/Design-Programmer-Architect-Pragmatic-Programmers/dp/1680502093) book, Michael Keeling\n\n### System Architecture\n\n- [\"Enterprise Integration Patterns : Designing, Building, and Deploying Messaging Solutions\"](https://www.enterpriseintegrationpatterns.com/) book and catalogue, Gregor Hohpe, Bobby Woolf\n- [\"Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems \"](https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321) book, Martin Kleppman\n- [\"Building Evolutionary Architectures: Support Constant Change\"](https://www.amazon.com/Building-Evolutionary-Architectures-Support-Constant/dp/1491986360) book, Neal Ford\n- [\"Building Microservices: Designing Fine-Grained Systems\"](https://www.amazon.com/Building-Microservices-Designing-Fine-Grained-Systems/dp/1491950358) book, Sam Newman\n\n### Design\n\n- [\"Refactoring: Improving the Design of Existing Code\"](https://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672) book, Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts\n- [\"Clean Code: A Handbook of Agile Software Craftsmanship\"](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) book, Robert C. Martin\n- [\"Agile Principles, Patterns, and Practices in C#\"](https://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258) book, Robert C. Martin\n- [\"Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition)\"](https://www.amazon.com/Applying-UML-Patterns-Introduction-Object-Oriented/dp/0131489062) book, Craig Larman\n- [\"Working Effectively with Legacy Code\"](https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052) book, Michael Feathers\n- [\"Code Complete: A Practical Handbook of Software Construction, Second Edition\"](https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670) book, Steve McConnell\n- [\"Design Patterns: Elements of Reusable Object-Oriented Software\"](https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) book, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides\n\n### Craftsmanship\n\n- [\"The Clean Coder: A Code of Conduct for Professional Programmers\"](https://www.amazon.com/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073) book, Robert C. Martin\n- [\"The Pragmatic Programmer: From Journeyman to Master\"](https://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X) book, Andrew Hunt\n\n### Testing\n\n- [\"The Art of Unit Testing: with examples in C#\"](https://www.amazon.com/Art-Unit-Testing-examples/dp/1617290890) book, Roy Osherove\n- [\"Unit Test Your Architecture with ArchUnit\"](https://blogs.oracle.com/javamagazine/unit-test-your-architecture-with-archunit) article, Jonas Havers\n- [\"Unit Testing Principles, Practices, and Patterns\"](https://www.amazon.com/Unit-Testing-Principles-Practices-Patterns/dp/1617296279) book, Vladimir Khorikov\n- [\"Growing Object-Oriented Software, Guided by Tests\"](https://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627) book, Steve Freeman, Nat Pryce\n- [Automated Tests](https://www.kamilgrzybek.com/blog/series/automated-tests) article series, Kamil Grzybek\n\n### UML\n\n- [\"UML Distilled: A Brief Guide to the Standard Object Modeling Language (3rd Edition)\"](https://www.amazon.com/UML-Distilled-Standard-Modeling-Language/dp/0321193687) book, Martin Fowler\n\n### Event Storming\n\n- [\"Introducing EventStorming\"](https://leanpub.com/introducing_eventstorming) book, Alberto Brandolini\n- [\"Awesome EventStorming\"](https://github.com/mariuszgil/awesome-eventstorming) GH repository, Mariusz Gil\n\n### Event Sourcing\n\n- [\"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice\"](https://www.amazon.com/Hands-Domain-Driven-Design-NET-ebook/dp/B07C5WSR9B) book, Alexey Zimarev\n- [\"Versioning in an Event Sourced System\"](https://leanpub.com/esversioning) book, Greg Young\n- [Hands-On-Domain-Driven-Design-with-.NET-Core](https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core) GH repository, Alexey Zimarev\n- [EventSourcing.NetCore](https://github.com/oskardudycz/EventSourcing.NetCore) GH repository, Oskar Dudycz\n"
  },
  {
    "path": "azure-pipelines.yml",
    "content": "# ASP.NET Core (.NET Framework)\n# Build and test ASP.NET Core projects targeting the full .NET Framework.\n# Add steps that publish symbols, save build artifacts, and more:\n# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core\n\ntrigger:\n- master\n\npool:\n  vmImage: 'windows-latest'\n\nvariables:\n  solution: '**/*.sln'\n  buildPlatform: 'Any CPU'\n  buildConfiguration: 'Release'\n\nsteps:\n- task: NuGetToolInstaller@1\n\n- task: NuGetCommand@2\n  inputs:\n    restoreSolution: '$(solution)'\n\n- task: VSBuild@1\n  inputs:\n    solution: '$(solution)'\n    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation=\"$(build.artifactStagingDirectory)\\WebApp.zip\" /p:DeployIisAppPath=\"Default Web Site\"'\n    platform: '$(buildPlatform)'\n    configuration: '$(buildConfiguration)'\n\n- task: VSTest@2\n  inputs:\n    platform: '$(buildPlatform)'\n    configuration: '$(buildConfiguration)'\n"
  },
  {
    "path": "build/.editorconfig",
    "content": "[*.cs]\ndotnet_style_qualification_for_field = false:warning\ndotnet_style_qualification_for_property = false:warning\ndotnet_style_qualification_for_method = false:warning\ndotnet_style_qualification_for_event = false:warning\ndotnet_style_require_accessibility_modifiers = never:warning\n\ncsharp_style_expression_bodied_methods = true:silent\ncsharp_style_expression_bodied_properties = true:warning\ncsharp_style_expression_bodied_indexers = true:warning\ncsharp_style_expression_bodied_accessors = true:warning\n"
  },
  {
    "path": "build/Build.cs",
    "content": "using Nuke.Common;\nusing Nuke.Common.IO;\nusing Nuke.Common.ProjectModel;\nusing Nuke.Common.Tools.DotNet;\nusing static Nuke.Common.Tools.DotNet.DotNetTasks;\n\n\npartial class Build : NukeBuild\n{\n    /// Support plugins are available for:\n    ///   - JetBrains ReSharper        https://nuke.build/resharper\n    ///   - JetBrains Rider            https://nuke.build/rider\n    ///   - Microsoft VisualStudio     https://nuke.build/visualstudio\n    ///   - Microsoft VSCode           https://nuke.build/vscode\n\n    public static int Main () => Execute<Build>(x => x.Compile);\n\n    [Parameter(\"Configuration to build - Default is 'Debug' (local) or 'Release' (server)\")]\n    readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;\n\n    [Solution] readonly Solution Solution;\n\n    Target Clean => _ => _\n        .Before(Restore)\n        .Executes(() =>\n        {\n            AbsolutePath.Create(WorkingDirectory).CreateOrCleanDirectory();\n        });\n\n    Target Restore => _ => _\n        .Executes(() =>\n        {\n            DotNetRestore(s => s\n                .SetProjectFile(Solution));\n        });\n\n    Target Compile => _ => _\n        .DependsOn(Restore)\n        .Executes(() =>\n        {\n            DotNetBuild(s => s\n                .SetProjectFile(Solution)\n                .SetConfiguration(Configuration)\n                .EnableNoRestore());\n        });\n\n    Target UnitTests => _ => _\n        .DependsOn(Compile)\n        .Executes(() =>\n        {\n            DotNetTest(s => s\n                .SetProjectFile(Solution)\n                .SetFilter(\"UnitTests\")\n                .SetConfiguration(Configuration)\n                .EnableNoRestore()\n                .EnableNoBuild());\n        });\n\n    Target ArchitectureTests => _ => _\n        .DependsOn(UnitTests)\n        .Executes(() =>\n        {\n            DotNetTest(s => s\n                .SetProjectFile(Solution)\n                .SetFilter(\"ArchTests\")\n                .SetConfiguration(Configuration)\n                .EnableNoRestore()\n                .EnableNoBuild());\n        });\n\n    Target BuildAndUnitTests => _ => _\n        .Triggers(ArchitectureTests)\n        .Executes(() =>\n        {\n        });\n}\n"
  },
  {
    "path": "build/BuildIntegrationTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing Nuke.Common;\nusing Nuke.Common.IO;\nusing Nuke.Common.Tools.Docker;\nusing Nuke.Common.Tools.DotNet;\nusing Utils;\nusing static Nuke.Common.IO.FileSystemTasks;\nusing static Nuke.Common.Tools.DotNet.DotNetTasks;\n\npublic partial class Build\n{\n    static AbsolutePath WorkingDirectory => RootDirectory / \".nuke-working-directory\";\n\n    static AbsolutePath OutputDirectory => WorkingDirectory / \"output\";\n\n    static AbsolutePath OutputDbUbMigratorBuildDirectory => OutputDirectory / \"dbUpMigrator\";\n\n    static AbsolutePath InputFilesDirectory => WorkingDirectory / \"input-files\";\n\n    static AbsolutePath DatabaseDirectory =>\n        RootDirectory / \"src\" / \"Database\" / \"CompanyName.MyMeetings.Database\" / \"Scripts\";\n\n    const string CreateDatabaseScriptName = \"CreateDatabase_Linux.sql\";\n\n    const string InputFilesDirectoryName = \"input-files\";\n\n    Target PrepareInputFiles => _ => _\n        .DependsOn(Clean)\n        .Executes(() =>\n        {\n            string createDatabaseFile = DatabaseDirectory / CreateDatabaseScriptName;\n            string createDatabaseFileTarget = InputFilesDirectory / CreateDatabaseScriptName;\n            CopyFile(createDatabaseFile, createDatabaseFileTarget, FileExistsPolicy.Overwrite);\n        });\n\n    const string SqlServerPassword = \"123qwe!@#QWE\";\n\n    const string SqlServerUser = \"sa\";\n\n    const string SqlServerPort = \"1401\";\n\n    Target PrepareSqlServer => _ => _\n        .DependsOn(PrepareInputFiles)\n        .Executes(() =>\n        {\n            DockerTasks.DockerRun(s => s\n                .EnableRm()\n                .SetName(\"sql-server-db\")\n                .SetImage(\"mcr.microsoft.com/mssql/server\")\n                .SetEnv(\n                    $\"SA_PASSWORD={SqlServerPassword}\",\n                    \"ACCEPT_EULA=Y\",\n                    \"MSSQL_PID=Express\")\n                .SetPublish($\"{SqlServerPort}:1433\")\n                .SetMount($\"type=bind,source=\\\"{InputFilesDirectory}\\\",target=/{InputFilesDirectoryName},readonly\")\n                .EnableDetach());\n\n            SqlReadinessChecker.WaitForSqlSever(\n                $\"Server=127.0.0.1,{SqlServerPort};Database=master;User={SqlServerUser};Password={SqlServerPassword};Encrypt=False;\");\n        });\n\n    Target CreateDatabase => _ => _\n        .DependsOn(PrepareSqlServer)\n        .Executes(() =>\n        {\n            DockerTasks.DockerExec(s => s\n                .EnableInteractive()\n                .SetContainer(\"sql-server-db\")\n                .SetCommand(\"/bin/sh\")\n                .SetArgs(\"-c\", $\"./opt/mssql-tools/bin/sqlcmd -d master -i ./{InputFilesDirectoryName}/{CreateDatabaseScriptName} -U {SqlServerUser} -P {SqlServerPassword}\"));\n        });\n\n    Target CompileDbUpMigratorForIntegrationTests => _ => _\n        .DependsOn(CreateDatabase)\n        .Executes(() =>\n        {\n            var dbUpMigratorProject = Solution.GetAllProjects(\"DatabaseMigrator\").First();\n            DotNetBuild(s => s\n                .SetProjectFile(dbUpMigratorProject)\n                .SetConfiguration(Configuration)\n                .SetOutputDirectory(OutputDbUbMigratorBuildDirectory)\n            );\n        });\n\n    AbsolutePath DbUpMigratorPath => OutputDbUbMigratorBuildDirectory / \"DatabaseMigrator.dll\";\n\n    readonly string MyMeetingsDatabaseConnectionString = $\"Server=127.0.0.1,{SqlServerPort};Database=MyMeetings;User={SqlServerUser};Password={SqlServerPassword};Encrypt=False;\";\n\n    Target RunDatabaseMigrations => _ => _\n        .DependsOn(CompileDbUpMigratorForIntegrationTests)\n        .Executes(() =>\n        {\n            AbsolutePath migrationsPath = DatabaseDirectory / \"Migrations\";\n\n            DotNet($\"{DbUpMigratorPath} {MyMeetingsDatabaseConnectionString} {migrationsPath}\");\n        });\n\n    const string MeetingsModuleIntegrationTestsAssemblyName = \"CompanyName.MyMeetings.Modules.Meetings.IntegrationTests\";\n\n    Target BuildMeetingsModuleIntegrationTests => _ => _\n        .DependsOn(RunDatabaseMigrations)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(MeetingsModuleIntegrationTestsAssemblyName).First();\n\n            DotNetBuild(s => s\n                .SetProjectFile(integrationTest)\n                .DisableNoRestore());\n        });\n\n    const string MyMeetingsDatabaseEnvName = \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n\n    Target RunMeetingsModuleIntegrationTests => _ => _\n        .DependsOn(BuildMeetingsModuleIntegrationTests)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(MeetingsModuleIntegrationTestsAssemblyName).First();\n            Environment.SetEnvironmentVariable(\n                MyMeetingsDatabaseEnvName,\n                MyMeetingsDatabaseConnectionString);\n\n            DotNetTest(s => s\n                .EnableNoBuild()\n                .SetProjectFile(integrationTest));\n        });\n\n    const string AdministrationModuleIntegrationTestsAssemblyName = \"CompanyName.MyMeetings.Modules.Administration.IntegrationTests\";\n\n    Target BuildAdministrationModuleIntegrationTests => _ => _\n        .DependsOn(RunDatabaseMigrations)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(AdministrationModuleIntegrationTestsAssemblyName).First();\n\n            DotNetBuild(s => s\n                .SetProjectFile(integrationTest)\n                .DisableNoRestore());\n        });\n\n    Target RunAdministrationModuleIntegrationTests => _ => _\n        .DependsOn(BuildAdministrationModuleIntegrationTests)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(AdministrationModuleIntegrationTestsAssemblyName).First();\n            Environment.SetEnvironmentVariable(\n                MyMeetingsDatabaseEnvName,\n                MyMeetingsDatabaseConnectionString);\n\n            DotNetTest(s => s\n                .EnableNoBuild()\n                .SetProjectFile(integrationTest));\n        });\n\n    const string UserAccessModuleIntegrationTestsAssemblyName = \"CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests\";\n\n    Target BuildUserAccessModuleIntegrationTests => _ => _\n        .DependsOn(RunDatabaseMigrations)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(UserAccessModuleIntegrationTestsAssemblyName).First();\n\n            DotNetBuild(s => s\n                .SetProjectFile(integrationTest)\n                .DisableNoRestore());\n        });\n\n    Target RunUserAccessModuleIntegrationTests => _ => _\n        .DependsOn(BuildUserAccessModuleIntegrationTests)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(UserAccessModuleIntegrationTestsAssemblyName).First();\n            Environment.SetEnvironmentVariable(\n                MyMeetingsDatabaseEnvName,\n                MyMeetingsDatabaseConnectionString);\n\n            DotNetTest(s => s\n                .EnableNoBuild()\n                .SetProjectFile(integrationTest));\n        });\n\n    const string PaymentsModuleIntegrationTestsAssemblyName = \"CompanyName.MyMeetings.Modules.Payments.IntegrationTests\";\n\n    Target BuildPaymentsModuleIntegrationTests => _ => _\n        .DependsOn(RunDatabaseMigrations)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(PaymentsModuleIntegrationTestsAssemblyName).First();\n\n            DotNetBuild(s => s\n                .SetProjectFile(integrationTest)\n                .DisableNoRestore());\n        });\n\n    Target RunPaymentsModuleIntegrationTests => _ => _\n        .DependsOn(BuildPaymentsModuleIntegrationTests)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(PaymentsModuleIntegrationTestsAssemblyName).First();\n            Environment.SetEnvironmentVariable(\n                MyMeetingsDatabaseEnvName,\n                MyMeetingsDatabaseConnectionString);\n\n            DotNetTest(s => s\n                .EnableNoBuild()\n                .SetProjectFile(integrationTest));\n        });\n\n    const string SystemIntegrationTestsAssemblyName = \"CompanyName.MyMeetings.IntegrationTests\";\n\n    Target BuildSystemIntegrationTests => _ => _\n        .DependsOn(RunDatabaseMigrations)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(SystemIntegrationTestsAssemblyName).First();\n\n            DotNetBuild(s => s\n                .SetProjectFile(integrationTest)\n                .DisableNoRestore());\n        });\n\n    Target RunSystemIntegrationTests => _ => _\n        .DependsOn(BuildSystemIntegrationTests)\n        .Executes(() =>\n        {\n            var integrationTest = Solution.GetAllProjects(SystemIntegrationTestsAssemblyName).First();\n            Environment.SetEnvironmentVariable(\n                MyMeetingsDatabaseEnvName,\n                MyMeetingsDatabaseConnectionString);\n\n            DotNetTest(s => s\n                .EnableNoBuild()\n                .SetProjectFile(integrationTest));\n        });\n\n    Target RunAllIntegrationTests => _ => _\n        .DependsOn(\n            RunAdministrationModuleIntegrationTests,\n            RunMeetingsModuleIntegrationTests,\n            RunPaymentsModuleIntegrationTests,\n            RunUserAccessModuleIntegrationTests,\n            RunSystemIntegrationTests)\n        .Executes(() =>\n        {\n\n        });\n}"
  },
  {
    "path": "build/Configuration.cs",
    "content": "using System.ComponentModel;\nusing Nuke.Common.Tooling;\n\n[TypeConverter(typeof(TypeConverter<Configuration>))]\npublic class Configuration : Enumeration\n{\n    public static Configuration Debug = new Configuration { Value = nameof(Debug) };\n    public static Configuration Release = new Configuration { Value = nameof(Release) };\n\n    public static implicit operator string(Configuration configuration)\n    {\n        return configuration.Value;\n    }\n}\n"
  },
  {
    "path": "build/Database.cs",
    "content": "﻿using System.Linq;\nusing Nuke.Common;\nusing Nuke.Common.Tools.DotNet;\nusing static Nuke.Common.Tools.DotNet.DotNetTasks;\n\npublic partial class Build\n{\n    Target CompileDbUpMigrator => _ => _\n        .Executes(() =>\n        {\n            var dbUpMigratorProject = Solution.GetAllProjects(\"DatabaseMigrator\").First();\n           \n            DotNetBuild(s => s\n                .SetProjectFile(dbUpMigratorProject)\n                .SetConfiguration(Configuration)\n                .SetOutputDirectory(OutputDbUbMigratorBuildDirectory)\n            );\n        });\n    \n    [Parameter(\"Modular Monolith database connection string\")] readonly string DatabaseConnectionString;\n    Target MigrateDatabase => _ => _\n        .Requires(() => DatabaseConnectionString != null)\n        .DependsOn(CompileDbUpMigrator)\n        .Executes(() =>\n        {\n            var migrationsPath = DatabaseDirectory / \"Migrations\";\n\n            DotNet($\"{DbUpMigratorPath} {DatabaseConnectionString} {migrationsPath}\");\n        });\n}"
  },
  {
    "path": "build/Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- This file prevents unintended imports of unrelated MSBuild files -->\n  <!-- Uncomment to include parent Directory.Build.props file -->\n  <!--<Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />-->\n\n</Project>\n"
  },
  {
    "path": "build/Directory.Build.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- This file prevents unintended imports of unrelated MSBuild files -->\n  <!-- Uncomment to include parent Directory.Build.targets file -->\n  <!--<Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))\" />-->\n\n</Project>\n"
  },
  {
    "path": "build/SUTCreator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Nuke.Common;\nusing Nuke.Common.Tools.DotNet;\nusing static Nuke.Common.Tools.DotNet.DotNetTasks;\n\n\npublic partial class Build\n{\n    [Parameter(\"SUT creator test name to execute\")] readonly string SUTTestName;\n\n    readonly IDictionary<string, string> TestCasesMap = new Dictionary<string, string>\n    {\n        {\"CleanDatabase\", \"CompanyName.MyMeetings.SUT.TestCases.CleanDatabaseTestCase.Prepare\"},\n        {\"OnlyAdmin\", \"CompanyName.MyMeetings.SUT.TestCases.OnlyAdminTestCase.Prepare\"},\n        {\"CreateMeeting\", \"CompanyName.MyMeetings.SUT.TestCases.CreateMeeting.Prepare\"}\n    };\n    \n    Target PrepareSUT => _ => _\n        .Requires(() => SUTTestName != null)\n        .Requires(() => DatabaseConnectionString != null)\n        .Executes(() =>\n        {\n            Environment.SetEnvironmentVariable(\n                \"MyMeetings_SUTDatabaseConnectionString\", \n                DatabaseConnectionString,\n                EnvironmentVariableTarget.Process);\n           \n            var sutTestProject = Solution.GetProject(\"CompanyName.MyMeetings.SUT\");\n\n            var fullyQualifiedName = TestCasesMap[SUTTestName];\n           \n            DotNetTest(s => s\n                .SetProjectFile(sutTestProject)\n                \n                .SetFilter($\"FullyQualifiedName={fullyQualifiedName}\"));\n        });\n}"
  },
  {
    "path": "build/Utils/SqlReadinessChecker.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing Dapper;\nusing System.Data.SqlClient;\n\nnamespace Utils\n{\n    public static class SqlReadinessChecker\n    {\n        public static void WaitForSqlSever(string connectionString)\n        {\n            using var connection = new SqlConnection(connectionString);\n\n            const int maxTryCounts = 30;\n            var tryCounts = 0;\n            while (true)\n            {\n                tryCounts++;\n                try\n                {\n                    connection.QuerySingle<string>(\"SELECT @@Version\");\n                    Serilog.Log.Information(\"Sql Server started\");\n                    break;\n                }\n                catch\n                {\n                    Serilog.Log.Information(\"Sql Server not ready\");\n                    if (tryCounts > maxTryCounts)\n                    {\n                        throw new Exception(\"Sql Server cannot start.\");\n                    }\n                }\n\n                Thread.Sleep(2000);\n            }\n        }\n    }\n}"
  },
  {
    "path": "build/_build.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n    <RootNamespace></RootNamespace>\n    <NoWarn>CS0649;CS0169</NoWarn>\n    <NukeRootDirectory>..</NukeRootDirectory>\n    <NukeScriptDirectory>..</NukeScriptDirectory>\n    <NukeTelemetryVersion>1</NukeTelemetryVersion>\n    <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Dapper\" Version=\"2.1.24\" />\n    <PackageReference Include=\"Nuke.Common\" Version=\"7.0.6\" />\n    <PackageReference Include=\"System.Data.SqlClient\" Version=\"4.8.6\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "build/_build.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeInspection/Highlighting/InspectionSeverities/=HeapView_002EDelegateAllocation/@EntryIndexedValue\">DO_NOT_SHOW</s:String>\n\t<s:String x:Key=\"/Default/CodeInspection/Highlighting/InspectionSeverities/=VariableHidesOuterVariable/@EntryIndexedValue\">DO_NOT_SHOW</s:String>\n\t<s:String x:Key=\"/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassNeverInstantiated_002EGlobal/@EntryIndexedValue\">DO_NOT_SHOW</s:String>\n\t<s:String x:Key=\"/Default/CodeInspection/Highlighting/InspectionSeverities/=MemberCanBeMadeStatic_002ELocal/@EntryIndexedValue\">DO_NOT_SHOW</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_INTERNAL_MODIFIER/@EntryValue\">Implicit</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue\">Implicit</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue\">ExpressionBody</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue\">0</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue\">NEXT_LINE</s:String>\n\t<s:Boolean x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_USER_LINEBREAKS/@EntryValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_INVOCATION_LPAR/@EntryValue\">False</s:Boolean>\n\t<s:Int64 x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_ATTRIBUTE_LENGTH_FOR_SAME_LINE/@EntryValue\">120</s:Int64>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue\">IF_OWNER_IS_SINGLE_LINE</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue\">WRAP_IF_LONG</s:String>\n\t<s:Boolean x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue\">False</s:Boolean>\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue\">&lt;Policy Inspect=\"True\" Prefix=\"\" Suffix=\"\" Style=\"AaBb\" /&gt;</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue\">&lt;Policy Inspect=\"True\" Prefix=\"\" Suffix=\"\" Style=\"AaBb\" /&gt;</s:String>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>\n"
  },
  {
    "path": "build.cmd",
    "content": ":; set -eo pipefail\n:; SCRIPT_DIR=$(cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd)\n:; ${SCRIPT_DIR}/build.sh \"$@\"\n:; exit $?\n\n@ECHO OFF\npowershell -ExecutionPolicy ByPass -NoProfile -File \"%~dp0build.ps1\" %*\n"
  },
  {
    "path": "build.ps1",
    "content": "[CmdletBinding()]\nParam(\n    [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]\n    [string[]]$BuildArguments\n)\n\nWrite-Output \"PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)\"\n\nSet-StrictMode -Version 2.0; $ErrorActionPreference = \"Stop\"; $ConfirmPreference = \"None\"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }\n$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent\n\n###########################################################################\n# CONFIGURATION\n###########################################################################\n\n$BuildProjectFile = \"$PSScriptRoot\\build\\_build.csproj\"\n$TempDirectory = \"$PSScriptRoot\\\\.nuke\\temp\"\n\n$DotNetGlobalFile = \"$PSScriptRoot\\\\global.json\"\n$DotNetInstallUrl = \"https://dot.net/v1/dotnet-install.ps1\"\n$DotNetChannel = \"Current\"\n\n$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1\n$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1\n$env:DOTNET_MULTILEVEL_LOOKUP = 0\n\n###########################################################################\n# EXECUTION\n###########################################################################\n\nfunction ExecSafe([scriptblock] $cmd) {\n    & $cmd\n    if ($LASTEXITCODE) { exit $LASTEXITCODE }\n}\n\n# If dotnet CLI is installed globally and it matches requested version, use for execution\nif ($null -ne (Get-Command \"dotnet\" -ErrorAction SilentlyContinue) -and `\n     $(dotnet --version) -and $LASTEXITCODE -eq 0) {\n    $env:DOTNET_EXE = (Get-Command \"dotnet\").Path\n}\nelse {\n    # Download install script\n    $DotNetInstallFile = \"$TempDirectory\\dotnet-install.ps1\"\n    New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null\n    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n    (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)\n\n    # If global.json exists, load expected version\n    if (Test-Path $DotNetGlobalFile) {\n        $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)\n        if ($DotNetGlobal.PSObject.Properties[\"sdk\"] -and $DotNetGlobal.sdk.PSObject.Properties[\"version\"]) {\n            $DotNetVersion = $DotNetGlobal.sdk.version\n        }\n    }\n\n    # Install by channel or version\n    $DotNetDirectory = \"$TempDirectory\\dotnet-win\"\n    if (!(Test-Path variable:DotNetVersion)) {\n        ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }\n    } else {\n        ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }\n    }\n    $env:DOTNET_EXE = \"$DotNetDirectory\\dotnet.exe\"\n}\n\nWrite-Output \"Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)\"\n\nExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }\nExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }\n"
  },
  {
    "path": "build.sh",
    "content": "#!/usr/bin/env bash\n\nbash --version 2>&1 | head -n 1\n\nset -eo pipefail\nSCRIPT_DIR=$(cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd)\n\n###########################################################################\n# CONFIGURATION\n###########################################################################\n\nBUILD_PROJECT_FILE=\"$SCRIPT_DIR/build/_build.csproj\"\nTEMP_DIRECTORY=\"$SCRIPT_DIR//.nuke/temp\"\n\nDOTNET_GLOBAL_FILE=\"$SCRIPT_DIR//global.json\"\nDOTNET_INSTALL_URL=\"https://dot.net/v1/dotnet-install.sh\"\nDOTNET_CHANNEL=\"Current\"\n\nexport DOTNET_CLI_TELEMETRY_OPTOUT=1\nexport DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1\nexport DOTNET_MULTILEVEL_LOOKUP=0\n\n###########################################################################\n# EXECUTION\n###########################################################################\n\nfunction FirstJsonValue {\n    perl -nle 'print $1 if m{\"'\"$1\"'\": \"([^\"]+)\",?}' <<< \"${@:2}\"\n}\n\n# If dotnet CLI is installed globally and it matches requested version, use for execution\nif [ -x \"$(command -v dotnet)\" ] && dotnet --version &>/dev/null; then\n    export DOTNET_EXE=\"$(command -v dotnet)\"\nelse\n    # Download install script\n    DOTNET_INSTALL_FILE=\"$TEMP_DIRECTORY/dotnet-install.sh\"\n    mkdir -p \"$TEMP_DIRECTORY\"\n    curl -Lsfo \"$DOTNET_INSTALL_FILE\" \"$DOTNET_INSTALL_URL\"\n    chmod +x \"$DOTNET_INSTALL_FILE\"\n\n    # If global.json exists, load expected version\n    if [[ -f \"$DOTNET_GLOBAL_FILE\" ]]; then\n        DOTNET_VERSION=$(FirstJsonValue \"version\" \"$(cat \"$DOTNET_GLOBAL_FILE\")\")\n        if [[ \"$DOTNET_VERSION\" == \"\"  ]]; then\n            unset DOTNET_VERSION\n        fi\n    fi\n\n    # Install by channel or version\n    DOTNET_DIRECTORY=\"$TEMP_DIRECTORY/dotnet-unix\"\n    if [[ -z ${DOTNET_VERSION+x} ]]; then\n        \"$DOTNET_INSTALL_FILE\" --install-dir \"$DOTNET_DIRECTORY\" --channel \"$DOTNET_CHANNEL\" --no-path\n    else\n        \"$DOTNET_INSTALL_FILE\" --install-dir \"$DOTNET_DIRECTORY\" --version \"$DOTNET_VERSION\" --no-path\n    fi\n    export DOTNET_EXE=\"$DOTNET_DIRECTORY/dotnet\"\nfi\n\necho \"Microsoft (R) .NET Core SDK version $(\"$DOTNET_EXE\" --version)\"\n\n\"$DOTNET_EXE\" build \"$BUILD_PROJECT_FILE\" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet\n\"$DOTNET_EXE\" run --project \"$BUILD_PROJECT_FILE\" --no-build -- \"$@\"\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.4'\n\nservices:\n\n  backend:\n    container_name: mymeetings_backend\n    build:\n      context: ./src/\n    ports:\n      - \"5000:8080\"\n    networks:\n      - starfish-crm-network\n    environment:\n      - Meetings_MeetingsConnectionString=Server=mymeetingsdb,1433;Database=MyMeetings;User=sa;Password=Test@12345;Encrypt=False;\n    depends_on:\n      - migrator\n    restart: on-failure\n\n  mymeetingsdb:\n    build: ./src/Database/\n    platform: linux/amd64\n    ports:\n      - 1445:1433\n    networks:\n      - starfish-crm-network\n\n  migrator:\n    container_name: mymeetings_db_migrator\n    build:\n      context: ./src/\n      dockerfile: ./Database/Dockerfile_DatabaseMigrator\n    networks:\n      - starfish-crm-network\n    environment:\n      - ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString=Server=mymeetingsdb,1433;Database=MyMeetings;User=sa;Password=Test@12345;Encrypt=False;\n    command:\n      [\n        \"./wait-for-it.sh\",\n        \"mymeetingsdb:1433\",\n        \"--timeout=60\",\n        \"--\",\n        \"/bin/bash\",\n        \"/entrypoint_DatabaseMigrator.sh\"\n      ]\n    restart: on-failure\n\nnetworks:\n  starfish-crm-network:\n"
  },
  {
    "path": "docs/C4/c1_system_context.puml",
    "content": "@startuml C1 System Context\n!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml\n\nPerson(memberPerson, \"Member\", \"Organizer of meeting groups, meetings, member of group, meeting attendee\")\nPerson(adminPerson, \"Administrator\", \"Administrator of the system\")\n\nSystem(myMeetingsSystem, \"My Meetings\")\nSystem_Ext(emailSystem, \"Email Service\")\nSystem_Ext(paymentGatewaySystem, \"Payment Gateway\")\n\nRel(memberPerson, myMeetingsSystem, \"Organize meeting groups and participate in meetings\")\nRel(adminPerson, myMeetingsSystem, \"Manage members, meeting groups, meetings\")\nRel(myMeetingsSystem, emailSystem, \"Request email send\")\nRel(emailSystem, memberPerson, \"Send email\")\nRel(emailSystem, adminPerson, \"Send email\")\nRel(myMeetingsSystem, paymentGatewaySystem, \"Delegate the payment\")\nRel(paymentGatewaySystem, myMeetingsSystem , \"Return info about payment\")\nRel(memberPerson, paymentGatewaySystem , \"Pay in\")\n\nLAYOUT_WITH_LEGEND()\n@enduml"
  },
  {
    "path": "docs/C4/c2_container.puml",
    "content": "@startuml C2 Containers\n!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml\n\nPerson(memberPerson, \"Member\", \"Organizer of meeting groups, meetings, member of group, meeting attendee\")\nPerson(adminPerson, \"Administrator\", \"Administrator of the system\")\n\nSystem_Boundary(c1, \"My Meetings System\") {\n    Container(spa, \"SPA\", \"ReactJS\", \"GUI for the application\")\n    Container(api, \"My Meetings API\", \".NET Core\", \"Backend\")\n    ContainerDb(database, \"Database\", \"Microsoft SQL\", \"Data about meeting groups, members, meetings etc\", \"msql_server\")\n}\nSystem_Ext(emailSystem, \"Email System\", \"3rd party SMTP server\")\nSystem_Ext(paymentGateway, \"Payment Gateway\", \"3rd party payment service\")\n\nRel(memberPerson, spa, \"Uses\", \"HTTP\")\nRel(adminPerson, spa, \"Uses\", \"HTTP\")\nRel(spa, api, \"Uses\", \"HTTP\")\nRel_R(api, database, \"Reads/Writes\", \"SQL\")\nRel_L(api, emailSystem, \"Sends email using\", \"SMTP\")\nRel_D(api, paymentGateway, \"Delegate the payment\", \"HTTP\")\nRel(memberPerson, paymentGateway, \"Make payment via\", \"HTTP\")\n\nLAYOUT_WITH_LEGEND()\n\n@enduml"
  },
  {
    "path": "docs/C4/c3_components.puml",
    "content": "@startuml C3 Components\n!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml\n\nSystem_Boundary(c1, \"My Meetings System\") {\n    Container(spa, \"SPA\", \"ReactJS\", \"GUI for the application\")\n    \n    Boundary(myMeetingsApi, \"My Meetings API\") {\n        Component(api, \"API\", \".NET Core API\")\n        Component(meetingsModule, \"Meetings\", \".NET Libraries\")\n        Component(administrationModule, \"Administration\", \".NET Libraries\")\n        Component(userAccessModule, \"User Access\", \".NET Libraries\")\n        Component(paymentsModule, \"Payments\", \".NET Libraries\")\n        Component(registrationsModule, \"Registrations\", \".NET Libraries\")\n        ComponentQueue(eventsBus, \"Events Bus\", \"In memory\")\n        \n        Boundary(database, \"Database\") {\n            ComponentDb(meetingsModuleData, \"Meetings data\", \"schema\")\n            ComponentDb(administrationData, \"Administration data\", \"schema\")\n            ComponentDb(userAccessData, \"User Access data\", \"schema\")\n            ComponentDb(paymentsData, \"Payments data\", \"schema\")\n            ComponentDb(registrationsData, \"Registrations data\", \"schema\")\n        }\n    }\n}\n\nRel(spa, api, \"Uses\", \"HTTP\")\nRel(api, meetingsModule, \"Uses\")\nRel(api, administrationModule, \"Uses\")\nRel(api, userAccessModule, \"Uses\")\nRel(api, paymentsModule, \"Uses\")\nRel(api, registrationsModule, \"Uses\")\nRel(meetingsModule, eventsBus, \"Publishes event to / subscribes\")\nRel(administrationModule, eventsBus, \"Publishes event to / subscribes\")\nRel(userAccessModule, eventsBus, \"Publishes event to / subscribes\")\nRel(paymentsModule, eventsBus, \"Publishes event to / subscribes\")\nRel(registrationsModule, eventsBus, \"Publishes event to / subscribes\")\n\nRel(meetingsModule, meetingsModuleData, \"Store / retrieve\")\nRel(administrationModule, administrationData, \"Store / retrieve\")\nRel(userAccessModule, userAccessData, \"Store / retrieve\")\nRel(paymentsModule, paymentsData, \"Store / retrieve\")\nRel(registrationsModule, registrationsData, \"Store / retrieve\")\n\nRel_R(registrationsModule, userAccessModule, \"Uses\")\n\nLAYOUT_WITH_LEGEND()\n\n@enduml"
  },
  {
    "path": "docs/C4/c3_components_module.puml",
    "content": "@startuml C3 Components Module (zoom-in)\n!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml\n\nAddComponentTag(\"meetings\", $bgColor=\"#4ce065\")\nAddComponentTag(\"administration\", $bgColor=\"#e3b868\")\nAddComponentTag(\"eventsBus\", $bgColor=\"#29118a\", $fontColor=\"#ffffff\")\n\nSystem_Boundary(c1, \"My Meetings System\") {\n    Boundary(myMeetingsApi, \"My Meetings API\") {\n        Component(api, \"API\", \".NET Core API\")\n        \n        Boundary(meetingsModule, \"Meetings Module\") {\n            Component(meetingsInfrastructure, \"Meetings.Infrastructure\", \".NET Library\", $tags=\"meetings\")\n            Component(meetingsApplication, \"Meetings.Application\", \".NET Library\", $tags=\"meetings\")\n            Component(meetingsDomain, \"Meetings.Domain\", \".NET Library\", $tags=\"meetings\")\n            Component(meetingsIntegrationEvents, \"Meetings.IntegrationEvents\", \".NET Library\", $tags=\"meetings\")\n            ComponentDb(meetingsData, \"Meetings data\", \"schema\", $tags=\"meetings\")\n        }\n\n        Boundary(administrationModule, \"Administration Module\") {\n            Component(administrationInfrastructure, \"Administration.Infrastructure\", \".NET Library\", $tags=\"administration\")\n            Component(administrationApplication, \"Administration.Application\", \".NET Library\", $tags=\"administration\")\n            Component(administrationDomain, \"Administration.Domain\", \".NET Library\", $tags=\"administration\")\n            Component(administrationIntegrationEvents, \"Administration.IntegrationEvents\", \".NET Library\", $tags=\"administration\")\n            ComponentDb(administrationData, \"Administration data\", \"schema\", $tags=\"administration\")\n        }\n\n        ComponentQueue(eventsBus, \"Events Bus\", \"In memory\", $tags=\"eventsBus\")\n    }\n}\n\n\nRel(api, meetingsInfrastructure, \"Uses\")\nRel(api, meetingsApplication, \"Uses\")\nRel(meetingsInfrastructure, meetingsApplication, \"Uses\")\nRel(meetingsInfrastructure, meetingsDomain, \"Uses\")\nRel(meetingsApplication, meetingsDomain, \"Uses\")\nRel(meetingsApplication, meetingsIntegrationEvents, \"Uses\")\nRel(meetingsInfrastructure, meetingsData, \"Uses\")\nRel(meetingsInfrastructure, eventsBus, \"Uses\")\n\nRel(api, administrationInfrastructure, \"Uses\")\nRel(api, administrationApplication, \"Uses\")\nRel(administrationInfrastructure, administrationApplication, \"Uses\")\nRel(administrationInfrastructure, administrationDomain, \"Uses\")\nRel(administrationApplication, administrationDomain, \"Uses\")\nRel(administrationApplication, administrationIntegrationEvents, \"Uses\")\nRel(administrationInfrastructure, administrationData, \"Uses\")\nRel(administrationInfrastructure, eventsBus, \"Uses\")\n\nRel(administrationApplication, meetingsIntegrationEvents, \"Uses\")\nRel(meetingsApplication, administrationIntegrationEvents, \"Uses\")\n\n@enduml"
  },
  {
    "path": "docs/C4/c4_class.puml",
    "content": "@startuml C4  Code\n\npackage \"Meeting Groups Aggregate\" <<Rectangle>> {\n\n    class \"MeetingGroupId\" << VO >> {   \n\n    }\n    \n    class \"MeetingGroup\" << Entity, AR >> {\n        -string: _description\n        -DateTime: _createDate\n        -DateTime: _paymentDateTo\n        {static} MeetingGroup CreateBasedOnProposal()\n        Meeting CreateMeeting(..)\n        void SetExpirationDate(DateTime dateTo)\n        void JoinToGroupMember(MemberId memberId)\n        void LeaveGroup(MemberId memberId)\n        void EditGeneralAttributes(...)\n        bool IsMemberOfGroup(MemberId attendeeId)\n        bool IsOrganizer(MemberId memberId)\n    }\n\n    class \"MeetingGroupLocation\" << VO >> {\n        string City\n        string CountryCode\n        {static} MeetingGroupLocation Create(...)\n\n    }\n\n    class \"MeetingGroupMember\" << Entity >> {\n        ~DateTime JoinedDate\n        -bool _isActive\n        -DateTime? _leaveDate\n        {static} MeetingGroupMember CreateNew(...)\n        void Leave()\n        ~bool IsMember(MemberId memberId)\n        ~bool IsOrganizer(MemberId memberId)\n    }\n\n    class \"MemberId\" << VO >> {\n\n    }\n\n    class \"MeetingGroupMemberRole\" << VO >> {\n        string Value\n    }\n}\n\nclass \"Member\" << Entity, AR >> {\n\n}\n\n\"MeetingGroup\" *-- \"MeetingGroupId\" : of\n\"MeetingGroup\" *-- \"MeetingGroupLocation\" : for\n\"MeetingGroup\" \"1\" *-- \"0..*\" \"MeetingGroupMember\" : member of\n\"MeetingGroupMember\" *-- \"MemberId\" : assigned to\n\"MeetingGroupMemberRole\" --* \"MeetingGroupMember\" : is assigned to\n\n\"Member\" o-- \"MemberId\" : of\n\n@enduml"
  },
  {
    "path": "docs/PlantUML/Commenting_Conceptual_Model.puml",
    "content": "@startuml\n\nobject \"Meeting\" as Meeting\nobject \"Member\" as Member\nobject \"Meeting Commenting Configuration\" as MeetingCommentingConfiguration\nobject \"Meeting Comment\" as MeetingComment\nobject \"Meeting Member Comment Like\" as MeetingMemberCommentLike\n\nMeeting \"1\"-->\"0..*\" MeetingComment : has\nMeetingCommentingConfiguration \"1\"-->\"1\" Meeting : enables\\ncommenting\\nof\nMeetingComment \"1\"-->\"0..*\" MeetingMemberCommentLike : has\nMeetingComment \"1\"-->\"0..*\" MeetingComment : is reply to\nMember --> Meeting : comments\nMember --> MeetingComment : replies to,\\nlikes\nMember --> MeetingCommentingConfiguration : configures\n\n@enduml"
  },
  {
    "path": "docs/PlantUML/Conceptual_Model.puml",
    "content": "@startuml\nscale max 2000 width\n\npackage \"User Access\" #f3e8f8 {\nobject Permission\nobject \"User Role\" as UserRole\nobject User\nobject \"User Registration\" as UserRegistration\nenum \"User Registration Status\" as UserRegistrationStatus\n{\n  WaitingForConfirmation\n  Confirmed\n  Expired\n}\n\nUser \"1\"-->\"0..*\" UserRole : has\nUser --> UserRegistration : created for\nUserRole \"1..*\"-->\"1..*\" Permission : has\nUserRegistration --> UserRegistrationStatus : is in\n\n}\n\npackage \"Administration\" #ffeddb {\n\nobject Administrator\nobject \"Meeting Group Proposal\" as Administration.MeetingGroupProposal\nenum \"Meeting Group Proposal Decision\" as MeetingGroupProposalDecision\n{\n  Accept\n  Reject\n}\nenum \"Meeting Group Proposal Status\" as Administration.MeetingGroupProposalDecisionStatus\n{\n  Accepted\n  InVerification\n  Rejected\n}\n\nAdministrator \"1\"-->\"0..*\" MeetingGroupProposalDecision : makes\nMeetingGroupProposalDecision --> Administration.MeetingGroupProposal : for\nAdministration.MeetingGroupProposal --> Administration.MeetingGroupProposalDecisionStatus: is in\n\n\nAdministrator --> User : is a\n\n}\n\n\npackage \"Meetings\" #e4f7e4 {\n\nobject \"Meeting\" as Meeting\nobject \"Member\" as Member\nobject \"Meeting Group Proposal\" as Meeting.MeetingGroupProposal\nobject \"Meeting Attendee\" as MeetingAttendee\nobject \"Meeting Group\" as MeetingGroup\nobject \"Meeting Not Attendee\" as MeetingNotAttendee\nobject \"Meeting Waitlist Member\" as MeetingWaitlistMember\nobject \"Meeting Location\" as MeetingLocation\nobject \"Member Subscription\" as Meeting.MemberSubscription\nenum \"Meeting Group Proposal Status\" as Meeting.MeetingGroupProposalStatus\n{\n  InVerification\n  Accepted\n  Rejected\n}\n\nMember --> Meeting.MeetingGroupProposal : proposes\nMember \"1\"-->\"0..*\" MeetingAttendee : is a\nMember \"1\"-->\"0..*\" MeetingNotAttendee : is a\nMember \"1\"-->\"0..*\" MeetingWaitlistMember : is a\nMember --> Meeting.MemberSubscription : has\n\nMeeting \"1\"-->\"1..*\" MeetingAttendee : attendees\nMeeting \"1\"-->\"0..*\" MeetingNotAttendee : not attendees\nMeeting --> MeetingLocation : has\n\nMeeting.MeetingGroupProposal --> Meeting.MeetingGroupProposalStatus : is in\nMeetingGroup \"1\"-->\"0..*\" Meetings : organizes\nMeetingGroup \"0..1\"-->\"1\" Meeting.MeetingGroupProposal : created after acceptance of\n\nMeetingWaitlistMember \"0..*\"-->\"1\" Meeting : waits for place for\n\nMeeting.MemberSubscription --> MeetingGroup : covers\n\n\nMember --> User: is a\nMeeting.MeetingGroupProposal --> Administration.MeetingGroupProposal : sent to verification\n\n}\n\n\npackage \"Payments\" #ffc1c1 {\n\nobject \"Payer\" as Payer\nobject \"Meeting Fee\" as MeetingFee\nobject \"Meeting Fee Payment\" as MeetingFeePayment\nobject \"Subscription\" as Payments.Subscription\nobject \"Subscription Payment\" as SubscriptionPayment\nobject \"Subscription Renewal Payment\" as SubscriptionRenewalPayment\nobject \"Price List\" as PriceList\nobject \"Price List Item\" as PriceListItem\n\nenum \"Subscription Status\" as SubscriptionStatus\n{\n  Active\n  Expired\n}\nenum \"Subscription Payment Status\" as SubscriptionPaymentStatus\n{\n  WaitingForPayment\n  Paid\n  Expired\n}\nenum \"Subscription Renewal Payment Status\" as SubscriptionRenewalPaymentStatus\n{\n  WaitingForPayment\n  Paid\n  Expired\n}\nenum \"Meeting Fee Payment Status\" as MeetingFeePaymentStatus\n{\n  WaitingForPayment\n  Paid\n  Expired\n}\nenum \"Price List Item Category\" as PriceListItemCategory\n{\n  New\n  Renewal\n}\nenum \"Subscription Period\" as SubscriptionPeriod\n{\n  Month\n  HalfYear\n}\n\n\n\nPayer \"1\"-->\"0..*\" MeetingFee : pays for\nPayer \"1\"--> \"0..*\" Payments.Subscription : buys\n\nMeetingFeePayment \"0..*\"-->\"1\" MeetingFee : for\nMeetingFeePayment --> MeetingFeePaymentStatus : is in\n\nPayments.Subscription \"1\"-->\"0..*\" SubscriptionRenewalPayment: extended by\nPayments.Subscription --> SubscriptionStatus : is in\nPayments.Subscription --> SubscriptionPeriod : is for\n\nSubscriptionPayment \"1..*\"-->\"1\" Payments.Subscription : is for\nSubscriptionPayment --> SubscriptionPaymentStatus : is in\nSubscriptionPayment --> SubscriptionPeriod : is for\n\nSubscriptionRenewalPayment --> SubscriptionRenewalPaymentStatus: is in\nSubscriptionRenewalPayment --> SubscriptionPeriod : is for\n\nPriceListItem --> SubscriptionPeriod : is for\nPriceListItem \"0..*\"-->\"1\" Country: is for\nPriceListItem --> PriceListItemCategory : is for\n\nPriceList \"1\"-->\"1..*\" PriceListItem : contains\n\n\nPayer --> Member: is a\nPayer --> User: is a\n\nPayments.Subscription -- Meeting.MemberSubscription\n}\n@enduml\n"
  },
  {
    "path": "docs/architecture-decision-log/0001-record-architecture-decisions.md",
    "content": "# 1.  Record architecture decisions\n\nDate: 2019-10-28\n\n## Status\n\nAccepted\n\n## Context\n\nAs the project is an example of a more advanced monolith architecture, it is necessary to save all architectural decisions in one place.\n\n## Decision\n\nFor all architectural decisions Architecture Decision Log (ADL) is created. All decisions will be recorded as Architecture Decision Records (ADR). \n\nEach ADR will be recorded using [Michael Nygard template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions), which contains following sections: Status, Context, Decision and Consequences.\n\n## Consequences\n\nAll architectural decisions should be recorded in log. Old decisions should be recorded as well with an approximate decision date. New decisions should be recorded on a regular basis."
  },
  {
    "path": "docs/architecture-decision-log/0002-use_modular-monolith-system-architecture.md",
    "content": "# 2.  Use Modular Monolith System Architecture\n\nDate: 2019-07-01\n\nLog date: 2019-10-28\n\n## Status\n\nAccepted\n\n## Context\n\nAn advanced example of Modular Monolith architecture and tactical DDD implementation in .NET is missing on the internet.\n\n## Decision\n\nI decided to create nontrivial application using Modular Monolith architecture and Domain-Driven Design tactical patterns.\n\n## Consequences\n\n- All modules must run in one single process as single application (Monolith)\n- All modules should have maximum autonomy (Modular)\n- DDD Bounded Contexts will be used to divide monolith into modules\n- DDD tactical patterns will be used to implement most of modules"
  },
  {
    "path": "docs/architecture-decision-log/0003-use_dotnetcore_and_csharp.md",
    "content": "# 3.  Use .NET Core and C# language\n\nDate: 2019-07-01\n\nLog date: 2019-10-28\n\n## Status\n\nAccepted\n\n## Context\n\nAs it is monolith, only one language (or platform) must be selected for implementation.\n\n## Decision\n\nI decided to use:\n\n- .NET Core platform - it is new generation multi-platform, fully supported by Microsoft and open-source community, optimized and designed to replace old .NET Framework\n- C# language - most popuplar language in .NET ecosystem, I have 12 years commercial experience\n- F# will not be used, I don't have commercial experience with it\n\n## Consequences\n\n- Whole application will be implemented in C# object-oriented language in .NET Core framework\n- .NET Core applications can be executed on Windows, MacOS, Linux"
  },
  {
    "path": "docs/architecture-decision-log/0004-divide-the-system-into-4-modules.md",
    "content": "# 4.   Divide the system into 4 modules \n\nDate: 2019-07-01\n\nLog date: 2019-11-02\n\n## Status\n\nAccepted\n\n## Context\n\nThe MyMeetings domain contains 4 main subdomains: Meetings (core domain), Administration (supporting subdomain), Payments (supporting subdomain) and User Access (generic domain).\n\nWe use Modular Monolith architecture so we need to implement one application which solves all requirements from all domains listed above.\n\nWe need to modularize our system.\n\n## Possible solutions\n1. Create one \"MyMeetings\" module and divide it into sub-modules. This solution is simpler to implement at the beginning. We do not have to set module boundaries and think how to communicate between them. On the other hand, this causes a lack of autonomy and can lead to Big Ball Of Mud anti-pattern.\n2. Create 4 modules based on Bounded Contexts which in this scenario maps 1:1 to domains. This solution is more difficult at the beginning. We need to set modules boundaries, communication strategy between modules and have more advanced infrastructure code. It is a more complex solution. On the other hand, it supports autonomy, maintainability, readability. We can develop our Domain Models in all of the Bounded Contexts independently.\n\n## Decision\n\nSolution 2.\n\nWe created 4 modules: Meetings, Administration, Payments, User Access. The key factor here is module autonomy and maintainability. We want to develop each module independently. This is more cleaner solution. It involves more work at the beginning but we want to invest.\n\n## Consequences\n- We can implement each module/Bounded Context independently.\n- We need to set clear boundaries between modules and communication strategy between modules (and implement them)\n- We need to define the API of each module\n- The API/GUI layer needs to know about all of the modules\n- We need to create shared libraries/classes to limit boilerplate code which will be the same in all modules\n- Complexity of the whole solution will increase\n- Complexity of each module will decrease\n- We will have clear separation of concerns\n- In addition to the application, we must divide the data\n- We will have business concepts modeled in a proper way - without \"godclasses\" which do everything\n- We can delegate development of particular module to defined team, work should be done without any conflicts on codebase"
  },
  {
    "path": "docs/architecture-decision-log/0005-create-one-rest-api-module.md",
    "content": "# 5.   Create one REST API module\n\nDate: 2019-07-01\n\nLog date: 2019-11-04\n\n## Status\n\nAccepted\n\n## Context\n\nWe need to expose the API of our application to the outside world. For now, we expect one client of our application - FrontEnd SPA application.\n\n## Possible solutions\n1. Create one .NET Core MVC host application which contains all endpoints. This host application will have references to all business modules and communicates with them directly:</br>\n\nHost/API references:</br>\nAdministration module</br>\nMeetings module</br>\nPayments module</br>\nUser Access module</br>\n\n2. Create one .NET Core MVC host application and multiple APIs projects per module. Each API project should have endpoints which are handled by particular business module:</br> \n\nHost references:</br>\nAdministration API references Administration module</br>\nMeetings API references Meetings module</br>\nPayments API references Payments module</br>\nUser Access API references User Access module</br>\n\n## Decision\n\nSolution 1.\n\nCreating separate API projects for each module will add complexity and little value. Grouping endpoints for a particular business module in a special directory is enough. Another layer on top of the module is unnecessary.\n\n## Consequences\n- We will have only one API layer/module\n- Each controller has responsibility to delegate Command/Query processing to appropriate module\n- We don't need to scan other projects than host for controllers, routes and other MVC mechanisms\n- API configuration is easier\n- Overall complexity of API layer is lower\n- Complexity of each controller is a little bit higher\n- Build time will be shorter (less projects)"
  },
  {
    "path": "docs/architecture-decision-log/0006-create-facade-between-api-and-business-module.md",
    "content": "# 6. Create façade between API and business module\n\nDate: 2019-07-01\n\nLog date: 2019-11-04\n\n## Status\n\nAccepted\n\n## Context\n\nOur API layer should communicate with business modules to fulfill client requests. To support the maximum level of autonomy, each module should expose a minimal set of operations (the module API/contract/interface).\n\n## Decision\n\nEach module will provide implementation for one interface with 3 methods:</br>\n\n```csharp\nTask<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\nTask ExecuteCommandAsync(ICommand command);\n\nTask<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n```\n\nThis interface will act as a façade (Façade pattern) between API and module. Only Commands, Queries and returned objects (which are part of this interface) should be visible to the API. Everything else should be hidden behind the façade (module encapsulation).\n\n## Consequences\n- API can communicate with the module only by façade (the interface).\n- Implementation of API is simpler\n- We can change module implementation and API does not require change if the interface is not changed\n- We need to focus on module encapsulation, sometimes it involves additional work (like instantiation using internal constructors)"
  },
  {
    "path": "docs/architecture-decision-log/0007-use-cqrs-architectural-style.md",
    "content": "# 7. Use CQRS architectural style\n\nDate: 2019-07-01\n\nLog date: 2019-11-04\n\n## Status\n\nAccepted\n\n## Context\n\nOur application should handle 2 types of requests - reading and writing. </br>\n\nFor now, it looks like:</br>\n\n- for reading, we need data model in relational form to return data in tabular/flattened way (tables, lists, dictionaries).\n- for writing, we need to have a graph of objects to perform more sophisticated work like validations, business rules checks, calculations.\n\n## Decision\n\nWe applied the CQRS architectural style/pattern for each business module. Each module will have a separate model for reading and writing. For now, it will be the simplest CQRS implementation when the read model is immediate consistent. This kind of separation is useful even in simple modules like User Access.\n\n## Consequences\n- Façade method of each module should take as parameter only Command or Query object\n- We have optimized models for writes and reads (SRP principle).\n- We can process Commands and Queries in different ways\n- As Command or Query is an object, we can easily serialize them and save/log them."
  },
  {
    "path": "docs/architecture-decision-log/0008-allow-return-result-after-command-processing.md",
    "content": "# 8. Allow return result after command processing\n\nDate: 2019-07-01\n\nLog date: 2019-11-04\n\n## Status\n\nAccepted\n\n## Context\n\nThe theory of the CQRS and the CQS principle says that we should not return any information as the result of Command processing. The result should be always \"void\". However, sometimes we need to return some data immediately as part of the same request.\n\n## Decision\n\nWe decided to allow in some cases return results after command processing. Especially, when we create something and we need to return the ID of created object or don't know if request is Command or Query (like Authentication).\n\n## Consequences\n- We will have two definitions of Commands and CommandHandlers - with and without result\n- It will add some complexity to processing commands (like implementation of decorators)\n- We can immediately return the ID of created object/resource. We don't need a second call (query) to retrieve this ID.\n- We should be careful to not overuse this approach (sticking as much as possible to the CQRS)"
  },
  {
    "path": "docs/architecture-decision-log/0009-use-2-layered-architectural-style-for-reads.md",
    "content": "# 9. Use 2 layered architectural style for reads\n\nDate: 2019-07-01\n\nLog date: 2019-11-04\n\n## Status\n\nAccepted\n\n## Context\n\nWe applied the CQRS style (see [ADR 7. Use CQRS architectural style](007-use-cqrs-architectural-style.md)), now we need to decide how to handle reading (querying) requests.\n\n## Decision\n\nWe will use 2 layered architecture to handle queries: API layer and Application Service layer. As we applied the CQRS and created a separated read model, querying should be straightforward so 2 layers are enough. The API layer is responsible for Query creation based on HTTP request and the module Application layer is responsible for query handling.\n\n## Consequences\n- Whole query handling logic is in Application Service layer\n- Application Service layer is coupled to the database and querying framework\n- Solution is simple, easy to understand\n- We don't abstract over database\n- Performance is better (no object mapping between layers, querying database almost immediately)"
  },
  {
    "path": "docs/architecture-decision-log/0010-use-clean-architecture-for-writes.md",
    "content": "# 10. Use Clean Architecture for writes\n\nDate: 2019-07-01\n\nLog date: 2019-11-05\n\n## Status\n\nAccepted\n\n## Context\n\nWe applied the CQRS style (see [ADR #7](0007-use-cqrs-architectural-style.md)), now we need to decide how to handle writing operations (Commands).\n\n## Decision\n\nWe will use **Clean Architecture** to handle commands with 4 layers: **API layer**, **Application Service layer**, **Infrastructure layer** and **Domain layer**. </br>\nWe need to add Domain layer because domain logic will be complex and we want to isolate this logic from other stuff like infrastructure or API. Isolation of domain logic supports testing, maintainability and readability.\n\n## Consequences\n- Complexity of the whole solution is higher - we need to add two more layers - domain and infrastructure\n- Complexity of implementation of business logic will be smaller - we can focus only on business concerns on this layer\n- Complexity of implementation of infrastructure will be smaller - we can focus only on infrastructure concerns on this layer\n- Business logic will be testable (no references to other layers)\n- Business logic will be independent of persistence (to some level)\n- In the Domain layer, we will have the same level of abstraction (close to business)\n- Application layer will have louse coupling to the Domain layer and Infrastructure layer (depend  on abstractions only)\n- We use one of the most popular application architecture - developers are familiar with it\n"
  },
  {
    "path": "docs/architecture-decision-log/0011-create-rich-domain-models.md",
    "content": "# 11. Create rich Domain Models\n\nDate: 2019-07-01\n\nLog date: 2019-11-05\n\n## Status\n\nAccepted\n\n## Context\n\nWe need to create Domain Models for all of the modules. Each Domain Model should represent a solution that solves a particular set of Domain problems (implements business logic).\n\n## Possible solutions\n1. Create Anemic Domain Model (Data Model) and implement *Transaction Script* pattern together with *Active Record* pattern\n2. Put all business logic to database in stored procedures\n3. Create a Rich Domain Model\n\n## Decision\n\nSolution number 3 - Rich Domain Model</br>\n\n1 - no, because the procedural style of coding will not be enough. We want to focus on behavior, not on the data.</br>\n2 - no, keeping business logic in the database is not a good idea in that case, object-oriented programming is better than T-SQL to model our domain and we don't have performance architectural drivers to resign from OOD.</br>\n\nWe expect complex business logic with different rules, calculations and processing so we want to get as much as possible from Object-Oriented Design principles like abstraction, encapsulation, polymorphism. We want to mutate the state of our objects only through methods (abstraction) to encapsulate all logic and hide implementation details from the client (the Application Service Layer and Unit Tests).</br>\n\n## Consequences\n- All objects should be encapsulated (private by default principle) \n- Encapsulation of objects implies more work in infrastructure (mapping to private fields, collections is harder)\n- Encapsulation of objects decreases to some level testability of these objects (Object-Oriented Design vs Testable Design)\n- All public methods of domain objects create Domain Model API\n- Implementation details of business logic are hidden\n- Clients of Domain Model are easier to implement\n- Better object-oriented programming skills are required to implement Rich Domain Model\n- Is easier to protect business rules/invariants using Rich Domain Model"
  },
  {
    "path": "docs/architecture-decision-log/0012-use-domain-driven-design-tactical-patterns.md",
    "content": "# 12. Use Domain-Driven Design tactical patterns\n\nDate: 2019-07-01\n\nLog date: 2019-11-05\n\n## Status\n\nAccepted\n\n## Context\n\nWe decided to use the Clean Architecture ([ADR #10](0010-use-clean-architecture-for-writes.md)) and create Rich Domain Models ([ADR #11](0011-create-rich-domain-models.md)) for each module. We need to define or use some construction elements / building blocks to implement our architecture and business logic.\n\n## Decision\n\nWe decided to use **Domain-Driven Design** tactical patterns. They focus on the Domain Model implementation. Especially we will use the following building blocks:\n\n- Command - public method on Aggregate (behavior)\n- Domain Event - the immutable class which represents important fact occurred on a special point of time (behavior)\n- Entity - class with identity (identity cannot change) with mutable attributes which represents concept from domain\n- Value Object - immutable class without an identity which represents concept from domain\n- Aggregate - cluster of domain objects (Entities, Value Objects) with one class entry point (Entity as Aggregate Root) which defines the boundary of transaction/consistency and protects business rules and invariants\n- Repository - collection-like abstraction to persist and load particular Aggregate\n- Domain Service - stateless service to execute some business logic which does not belong to any of Entity/Value Object\n\n## Consequences\n- We need to define entities and value objects\n- We need to define aggregates boundaries\n- We need to add repositories for each aggregate\n- We can invoke only public methods on Aggregate Roots, everything else should be hidden\n- Developers need to be familiar with DDD tactical patterns"
  },
  {
    "path": "docs/architecture-decision-log/0013-protect-business-invariants-using-exceptions.md",
    "content": "# 13. Protect business invariants using exceptions\n\nDate: 2019-07-01\n\nLog date: 2019-11-05\n\n## Status\n\nAccepted\n\n## Context\n\nAggregates should check business invariants. When the invariant is broken, we should stop processing and return an error immediately to the client.\n\n## Possible solutions\n\n### 1. Use exceptions\n#### Pros\n- we can stop processing immediately (fail-fast)\n-  popular approach in C# \n-  we don't need to check the result of each method (if-else statements)\n-   we can catch all Business Exceptions in one place and translate them (for example in the API layer to some HTTP response code). \n#### Cons\n- indirection \n- little performance impact \n- for special cases, we need to add a specific catch.\n### 2. Return Result object\n#### Pros \n- no indirection\n- no performance impact\n- signature method is more descriptive. \n### Cons \n- we need to add checks result of each method (if-else statements)\n- approach is less-known in the C# world \n- it needs a library or more coding to support Results\n\n## Decision\n\nSolution number 1 - Use exceptions. </br>\n\nPerformance cost of throwing an exception is irrelevant, we don't want too many if/else statements in entities, more familiar with exceptions approach.\n\n## Consequences\n- We need to add special *BusinessException* class to separate business rules validation exceptions from other exceptions\n- We need to create different business exceptions for each business rule\n- We will have a small performance impact (throwing exceptions)\n- We will have generic mechanism which catches *BusinessException*\n- We will not have a lot of if/else statements in Entities/Value Objects to check method results\n- Some monitoring tools logs automatically each exception. If we want to use one of this tool we should be aware of this and figure it out proper solution"
  },
  {
    "path": "docs/architecture-decision-log/0014-event-driven-communication-between-modules.md",
    "content": "# 14. Event-driven communication between modules\n\nDate: 2019-07-15\n\nLog date: 2019-11-09\n\n## Status\n\nAccepted\n\n## Context\n\nEach module should be autonomous. However, communication between them must take place. We have to decide what will be the preferred way of communication and integration between modules.\n\n## Possible solutions\n\n### 1. Direct method call (synchronous)\n\nEach Module will expose a set of methods (interface, module API) which can be called by other modules directly.\n\n#### Pros\n- easier implementation\n- no indirection\n- more natural in the monolith architecture\n- supports immediate consistency\n#### Cons\n- less autonomy\n- strong coupling between modules\n- direct method call is blocking\n- module has a dependency on another module\n\n### 2. Event-driven (asynchronous)\n\nEach module will publish a specific set of events. Other modules can subscribe to specific events. It is the implementation of _Publish/Subscribe_ pattern.\n\n#### Pros\n- more autonomy\n- coupling is only to middleware/broker of events\n- no blocking communication\n- stronger modules boundaries\n- module does not have a dependency on another module\n#### Cons\n- indirection\n- more complex solution\n- middleware/broker is needed\n- does not support immediate consistency\n\n## Decision\n\nSolution number 2 - Event-driven (asynchronous)</br>\n\nWe want to achieve the maximum level of autonomy and loose coupling between modules. Moreover, we don't want dependencies between modules. We allow direct calls in the future, but this should be an exception, not a rule.\n\n## Consequences\n- We need to implement the Publish/Subscribe pattern\n- Solution will be more complex\n- Modules will have more autonomy\n- Modules will have coupling to broker/middleware\n- During modules integration, eventual consistency will occur (asynchronous communication)\n- Events become Published Language of our Bounded Contexts (modules)\n- Events structure should be stable as much as possible"
  },
  {
    "path": "docs/architecture-decision-log/0015-use-in-memory-events-bus.md",
    "content": "# 15. Use In-Memory Events Bus\n\nDate: 2019-07-15\n\nLog date: 2019-11-09\n\n## Status\n\nAccepted\n\n## Context\n\nAs we want to base inter-modular communication on asynchronous communication in the form of event-driven architecture, we need some \"events bus\" to do that.\n\n## Possible solutions\n\n### 1. In Memory Events Bus\n\nIn memory Publish/Subscribe implementation without any external component.\n\n#### Pros\n- very easy to implement\n- no network communication needed\n- performance (it depends)\n- no need to learn anything\n- simple solution\n#### Cons\n- does not support more advanced integration scenarios, everything needs to be implemented\n- does not have configuration\n- does not have other features (who have messaging brokers)\n\n### 2. Message Broker\n\nExternal middleware component. It could be a low-level broker (like RabbitMQ) or a high-level broker (like MassTransit, NServiceBus). \n\n#### Pros\n- only integration with platform code needed\n- more advanced integration scenarios\n- richness of configuration\n- a lot of features\n#### Cons\n- complex solution\n- network communication\n- new platform learning needed\n- performance (it depends)\n\n## Decision\n\nSolution number 1 - In Memory Events Bus</br>\n\nAt that moment we don't see more advanced integration scenarios in our system than simple publish/subscribe scenario. We decided to follow the simplest scenario and if it will be necessary - move to more advanced.\n\n## Consequences\n- We need to implement Publish/Subscribe in memory\n- All modules will have dependency to In Memory Events Bus to publish events/subscribe to events\n- if we ever want to separate a module to another process (microservices architecture), we will need to switch to middleware"
  },
  {
    "path": "docs/architecture-decision-log/0016-create-ioc-container-per-module.md",
    "content": "# 16. Create an IoC Container per module\n\nDate: 2019-07-15\n\nLog date: 2019-11-09\n\n## Status\n\nAccepted\n\n## Context\n\nFor each module, when we process particular Command or Query, we need to resolve a graph of objects. We need to decide how dependencies of objects will be resolved.\n\n## Possible solutions\n\n### 1. One IoC Container for whole application\n\nOne IoC container located in the host project.\n\n#### Pros\n- standard approach\n- dependencies configured in one place\n#### Cons\n- couples host application with all of projects, libraries\n- modules autonomy decreases\n- strong coupling\n\n### 2. IoC Container per module\n\nMultiple IoC containers per modules.\n\n#### Pros\n- module autonomy\n- loose coupling \n- host application has dependency only to Application Service Layer\n#### Cons\n- duplicated code\n- non-standard approach\n\n## Decision\n\nSolution number 2 - IoC Container per module</br>\n\nIoC Container per module supports the autonomy of the module and louse coupling so this is a more important aspect for us than duplicated code in some places.\n\n## Consequences\n- Create and maintain an IoC Container for each module\n- Implementation is not standard, but still acceptable easy\n- We can add dependencies to module and other modules are intact"
  },
  {
    "path": "docs/architecture-decision-log/0017-implement-archictecture-tests.md",
    "content": "# 17. Implement Architecture Tests\n\nDate: 2019-11-16\n\n## Status\n\nAccepted\n\n## Context\n\nIn some cases it is not possible to enforce the application architecture, design or established conventions using compiler (compile-time). For this reason, code implementations can diverge from the original design and architecture. We want to minimize this behavior, not only by code review.\n\n## Decision\n\nWe decided to implement Unit Tests for our architecture. </br>\nWe will implement tests for each module separately and one tests library for general architecture. We will use _NetArchTest_ library which was created exactly for this purpose.\n\n## Consequences\n- We will have quick feedback about breaking the design rules\n- Unit tests for architecture are documenting our architecture to some level\n- We will have dependency to external library\n- We need to implement some _\"reflection-based\"_ code to check some rules, because library does not provide everything what we need\n- This kind of tests are a bit slower than normal unit tests (because of reflection)\n- More tests to maintain"
  },
  {
    "path": "docs/catalog-of-terms/Aggregate-DDD/README.md",
    "content": "# Aggregate (DDD)\n\n## Definition\n\n*Cluster ENTITES and VALUE OBJECTS into AGGREGATES and define boundaries around each. Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change.*\n\nSource: [Domain-Driven Design: Tackling Complexity in the Heart of Software, Eric Evans](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/FOx13i8m34FlV0LyG9Sxfo7rHx8cTDFQPaeJJV3rT1SkjcpPqfkxePhNSdjiBHKdTYttrUpeJm35SygRhRvuPqtIZ9jDIIhiMR-VXNUeGbvGGvKcPKp3UGaHGSLkh42IEYGqB9A3lCFeQeTNpiePZKEC4V2Vnd4wBfoP6mt_0G00)\n\n### Code\n\n```csharp\n\npublic class MeetingGroup : Entity, IAggregateRoot\n{\n    public MeetingGroupId Id { get; private set; }\n\n    private string _name;\n\n    private string _description;\n\n    private MeetingGroupLocation _location;\n\n    private MemberId _creatorId;\n\n    private List<MeetingGroupMember> _members;\n\n    private DateTime _createDate;\n\n    private DateTime? _paymentDateTo;\n\n    internal static MeetingGroup CreateBasedOnProposal(\n        MeetingGroupProposalId meetingGroupProposalId,\n        string name,\n        string description,\n        MeetingGroupLocation location,\n        MemberId creatorId)\n    {\n        return new MeetingGroup(meetingGroupProposalId, name, description, location, creatorId);\n    }\n\n    private MeetingGroup()\n    {\n        // Only for EF.\n    }\n\n    private MeetingGroup(MeetingGroupProposalId meetingGroupProposalId, string name, string description, MeetingGroupLocation location, MemberId creatorId)\n    {\n        this.Id = new MeetingGroupId(meetingGroupProposalId.Value);\n        this._name = name;\n        this._description = description;\n        this._creatorId = creatorId;\n        this._location = location;\n        this._createDate = SystemClock.Now;\n\n        this.AddDomainEvent(new MeetingGroupCreatedDomainEvent(this.Id, creatorId));\n\n        this._members = new List<MeetingGroupMember>();\n        this._members.Add(MeetingGroupMember.CreateNew(this.Id, this._creatorId, MeetingGroupMemberRole.Organizer));\n    }\n\n    public void EditGeneralAttributes(string name, string description, MeetingGroupLocation location)\n    {\n        this._name = name;\n        this._description = description;\n        this._location = location;\n\n        this.AddDomainEvent(new MeetingGroupGeneralAttributesEditedDomainEvent(this._name, this._description, this._location));\n    }\n\n    public void JoinToGroupMember(MemberId memberId)\n    {\n        this.CheckRule(new MeetingGroupMemberCannotBeAddedTwiceRule(_members, memberId));\n\n        this._members.Add(MeetingGroupMember.CreateNew(this.Id, memberId, MeetingGroupMemberRole.Member));\n    }\n\n    public void LeaveGroup(MemberId memberId)\n    {\n        this.CheckRule(new NotActualGroupMemberCannotLeaveGroupRule(_members, memberId));\n\n        var member = this._members.Single(x => x.IsMember(memberId));\n\n        member.Leave();\n    }\n\n    public void SetExpirationDate(DateTime dateTo)\n    {\n        _paymentDateTo = dateTo;\n\n        this.AddDomainEvent(new MeetingGroupPaymentInfoUpdatedDomainEvent(this.Id, _paymentDateTo.Value));\n    }\n\n    public Meeting CreateMeeting(\n        string title,\n        MeetingTerm term,\n        string description,\n        MeetingLocation location,\n        int? attendeesLimit,\n        int guestsLimit,\n        Term rsvpTerm,\n        MoneyValue eventFee,\n        List<MemberId> hostsMembersIds,\n        MemberId creatorId)\n    {\n        this.CheckRule(new MeetingCanBeOrganizedOnlyByPayedGroupRule(_paymentDateTo));\n\n        this.CheckRule(new MeetingHostMustBeAMeetingGroupMemberRule(creatorId, hostsMembersIds, _members));\n\n        return Meeting.CreateNew(\n            this.Id,\n            title,\n            term,\n            description,\n            location,\n            MeetingLimits.Create(attendeesLimit, guestsLimit),\n            rsvpTerm,\n            eventFee,\n            hostsMembersIds,\n            creatorId);\n    }\n\n    internal bool IsMemberOfGroup(MemberId attendeeId)\n    {\n        return _members.Any(x => x.IsMember(attendeeId));\n    }\n\n    internal bool IsOrganizer(MemberId memberId)\n    {\n        return _members.Any(x => x.IsOrganizer(memberId));\n    }\n}\n\n```\n\n### Description\n\nClasses `MeetingGroup`, `MeetingGroupLocation`, `MeetingGroupId`, `MeetingGroupMember', 'MeetingGroupMemberRole` form the **Aggregate**. `MeetingGroup` acts as the **AggregateRoot** (*Choose one ENTITY to be the root of each AGGREGATE*). AggregateRoot has a global identifier (`Id`) and public methods to change state of the *Aggregate*. The rest is encapsulated (*Because the root controls access, it cannot be blindsided by changes to the internals*). For each public method, the invariants are checked first (`CheckRule`) (*This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change*).\n\n## Additional References\n\n- [DDD_Aggregate (Martin Fowler)](https://martinfowler.com/bliki/DDD_Aggregate.html)"
  },
  {
    "path": "docs/catalog-of-terms/Aggregate-DDD/aggregate-ddd.puml",
    "content": "@startuml Aggregate\n\npackage \"Meeting Groups Aggregate\" <<Rectangle>> {\n\n    class \"MeetingGroupId\" << VO >> {   \n\n    }\n    \n    class \"MeetingGroup\" << Entity, AR >> {\n        -string: _description\n        -DateTime: _createDate\n        -DateTime: _paymentDateTo\n        {static} MeetingGroup CreateBasedOnProposal()\n        Meeting CreateMeeting(..)\n        void SetExpirationDate(DateTime dateTo)\n        void JoinToGroupMember(MemberId memberId)\n        void LeaveGroup(MemberId memberId)\n        void EditGeneralAttributes(...)\n        bool IsMemberOfGroup(MemberId attendeeId)\n        bool IsOrganizer(MemberId memberId)\n    }\n\n    class \"MeetingGroupLocation\" << VO >> {\n        string City\n        string CountryCode\n        {static} MeetingGroupLocation Create(...)\n\n    }\n\n    class \"MeetingGroupMember\" << Entity >> {\n        ~DateTime JoinedDate\n        -bool _isActive\n        -DateTime? _leaveDate\n        {static} MeetingGroupMember CreateNew(...)\n        void Leave()\n        ~bool IsMember(MemberId memberId)\n        ~bool IsOrganizer(MemberId memberId)\n    }\n\n    class \"MemberId\" << VO >> {\n\n    }\n\n    class \"MeetingGroupMemberRole\" << VO >> {\n        string Value\n    }\n}\n\nclass \"Member\" << Entity, AR >> {\n\n}\n\n\"MeetingGroup\" *-- \"MeetingGroupId\" : of\n\"MeetingGroup\" *-- \"MeetingGroupLocation\" : for\n\"MeetingGroup\" \"1\" *-- \"0..*\" \"MeetingGroupMember\" : member of\n\"MeetingGroupMember\" *-- \"MemberId\" : assigned to\n\"MeetingGroupMemberRole\" --* \"MeetingGroupMember\" : is assigned to\n\n\"Member\" o-- \"MemberId\" : of\n\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Command/README.md",
    "content": "# Command\n\n## Definition\n\n*A command is a request made to do something. A command represents the intention of a system’s user regarding what the system will do to change its state.*\n\n*Command characteristics:*\n\n- *The result of a command can be either success or failure; the result is an [Event(s)](../Event/)*\n\n- *In case of success, state change(s) must have occurred somewhere (otherwise nothing happened)*\n\n- *Commands should be named with a verb, in the present tense or infinitive, and a nominal group coming from the domain (entity of aggregate type)*\n\nSource: [Open Agile Architecture](https://pubs.opengroup.org/architecture/o-aa-standard/#KLP-EDA-event-command)\n\n\n## Example\n\n### Model\n\n### Code\n\n`Meeting` class in [Domain Model](../Domain-Model/):\n\n```csharp\n\npublic void Cancel(MemberId cancelMemberId)\n{\n    this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n    if (!_isCanceled)\n    {\n        _isCanceled = true;\n        _cancelDate = SystemClock.Now;\n        _cancelMemberId = cancelMemberId;\n\n        this.AddDomainEvent(new MeetingCanceledDomainEvent(this.Id, _cancelMemberId, _cancelDate.Value));\n    }\n}\n\n```\n\n`CancelMeetingCommand` class in [Application Layer](../Application-Layer/)\n\n```csharp\n\npublic class CancelMeetingCommand : CommandBase\n{\n    public CancelMeetingCommand(Guid meetingId)\n    {\n        MeetingId = meetingId;\n    }\n\n    public Guid MeetingId { get; }\n}\n\ninternal class CancelMeetingCommandHandler : ICommandHandler<CancelMeetingCommand>\n{\n    private readonly IMeetingRepository _meetingRepository;\n    private readonly IMemberContext _memberContext;\n\n    internal CancelMeetingCommandHandler(IMeetingRepository meetingRepository, IMemberContext memberContext)\n    {\n        _meetingRepository = meetingRepository;\n        _memberContext = memberContext;\n    }\n\n    public async Task<Unit> Handle(CancelMeetingCommand request, CancellationToken cancellationToken)\n    {\n        var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\n\n        meeting.Cancel(_memberContext.MemberId);\n\n        return Unit.Value;\n    }\n}\n\n```\n\n### Description\n\nIn the example above, we can distinguish between 2 types of Commands:\n- as an object in the application layer [Parameter Object Pattern](../Parameter-Object-Pattern/)\n- in the form of a method on the object (in DDD on the [Aggregate](../Aggregate-DDD/)\n\nThe most important thing is that the Command can be rejected until the state changes. In both the `CommandHandler` (invalid MeetingId) and the `Cancel` method (business rule broken), an exception can be thrown and the Command is then rejected and all uncomitted changes are rolled back (state does not change). "
  },
  {
    "path": "docs/catalog-of-terms/Command/command.puml",
    "content": "@startuml Command\n\nclass CancelMeetingCommand {\n    MeetingGroupId: Id\n}\n\nnote top of CancelMeetingCommand : Command as part of Application Layer\n\nclass Meeting {\n    void Cancel(MemberId cancelMemberId)\n}\n\nnote top of Meeting : Command defined in Domain Model (on an Aggregate)\n\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Decorator-Pattern/README.md",
    "content": "# Decorator Pattern\n\n## Definition\n\n*In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the [Single Responsibility Principle](../Single-Responsibility-Principle/), as it allows functionality to be divided between classes with unique areas of concern.*\n\nSource: [Wikipedia](https://en.wikipedia.org/wiki/Decorator_pattern)\n\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/bPFDhjCm48NtVehPqGitVO3eghfLMO044eA-W1jF4Wjx9h8dL8YVPyVDJqL9g66HHMRE-Sx46Jz7qK5wxrJbT8pm7b4iDV70986Tmm3V5BpQ6pDrzY981d7paCeVqVCNN7P-g0ctz1tOUqrcwgy2Pibr96Ery3Z8fwGO0om9XbfN26ydmvlqE0nFbk0ubNQ3QMnivk8Z73HLw9mMotJapqW3yMTcved_EtAfpMSilpiRSq-UINh7JPDCj-pNM76udEdJyVQ4Lc5G9CZc0IvKOa5mM0jmdM6NPUehW0yOQWu-WXlbZt3g1GnZf1UI-bMhgK5e-GmZ0hZ3HC2ea0nS4fLghK50tybNyEXF6A9IAxjQ63vJiRlkJ0cMXl3_4wkvD6l-lXGbnFGQbuxbFrkQL7RNYhwxdzuEmgZck3niLEPu-T6smJQjRB_l_ho09LZVEVH84Y4_sB-ZrFs5Wss6aFE_N0UOKO1HFIEPthjV)\n\n### Code\n\n```csharp\n\ninternal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T> where T:ICommand\n{\n    private readonly ILogger _logger;\n    private readonly IExecutionContextAccessor _executionContextAccessor;\n    private readonly ICommandHandler<T> _decorated;\n\n    public LoggingCommandHandlerDecorator(\n        ILogger logger,\n        IExecutionContextAccessor executionContextAccessor,\n        ICommandHandler<T> decorated)\n    {\n        _logger = logger;\n        _executionContextAccessor = executionContextAccessor;\n        _decorated = decorated;\n    }\n    public async Task<Unit> Handle(T command, CancellationToken cancellationToken)\n    {\n        if (command is IRecurringCommand)\n        {\n            return await _decorated.Handle(command, cancellationToken);\n        }\n        using (\n            LogContext.Push(\n                new RequestLogEnricher(_executionContextAccessor),\n                new CommandLogEnricher(command)))\n        {\n            try\n            {\n                this._logger.Information(\n                    \"Executing command {Command}\",\n                    command.GetType().Name);\n\n                var result = await _decorated.Handle(command, cancellationToken);\n\n                this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\n\n                return result;\n            }\n            catch (Exception exception)\n            {\n                this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\n                throw;\n            }\n        }\n    }\n\n    private class CommandLogEnricher : ILogEventEnricher\n    {\n        private readonly ICommand _command;\n\n        public CommandLogEnricher(ICommand command)\n        {\n            _command = command;\n        }\n        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n        {\n            logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n        }\n    }\n\n    private class RequestLogEnricher : ILogEventEnricher\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n        {\n            _executionContextAccessor = executionContextAccessor;\n        }\n        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n        {\n            if (_executionContextAccessor.IsAvailable)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\n            }\n        }\n    }\n}\n\n```\n### Description\n\nThe Logging decorator logs execution, arguments and processing of each Command. This way each log inside a processor has the log context of the processing command.\n\nA unique trade of a decorator is that it does both:\n* It implements  `ICommandHandler<T>` (known also as the *component*).\n* It accepts an <u>implementation</u> of `ICommandHandler<T>` (known also as the *concrete component*). Usually that is done via [Dependency Injection](../Dependency-Injection/).\n\nThe decorator builds on top of existing functionality provided by the injected `ICommandHandler<T>`, but it does not change the behavior of it.\n\n---\n\nDecorator should not be confused with [Strategy](../Strategy-Pattern/)!!!\n*A decorator lets you change the skin of an object, while Strategy lets you change the guts.*"
  },
  {
    "path": "docs/catalog-of-terms/Decorator-Pattern/decorator-pattern.puml",
    "content": "@startuml\nclass MeetingsController {\n +AddMeetingAttendee()\n +RemoveMeetingAttendee()\n}\n\nclass AddMeetingAttendeeCommand\nclass RemoveMeetingAttendeeCommand\n\nclass Mediator {\n +Send()\n}\n\ninterface ICommandHandler<in TCommand> {\n +Handle(TCommand, CancellationToken)\n}\n\n~class AddMeetingAttendeeCommandHandler {\n +Handle(AddMeetingAttendeeCommand, CancellationToken)\n}\n\n~class RemoveMeetingAttendeeCommandHandler {\n +Handle(RemoveMeetingAttendeeCommand, CancellationToken)\n}\n\n~class LoggingCommandHandlerDecorator<T> {\n +Handle(T, CancellationToken)\n -Log() \n}\n\nnote left of LoggingCommandHandlerDecorator::Log\n  Performs logging, but doesn't\n  change how Handle operates\nend note\n\nhide empty members\n\nMeetingsController -down-> Mediator: informs\nMeetingsController -down-> Mediator: informs\n\nMediator -down-> AddMeetingAttendeeCommand: sends\nMediator -down-> RemoveMeetingAttendeeCommand: sends\n\nAddMeetingAttendeeCommandHandler -up-> AddMeetingAttendeeCommand: handles\nRemoveMeetingAttendeeCommandHandler -up-> RemoveMeetingAttendeeCommand: handles\n\nAddMeetingAttendeeCommandHandler .right.|> ICommandHandler: implements \nRemoveMeetingAttendeeCommandHandler .right.|> ICommandHandler: implements \n\nLoggingCommandHandlerDecorator ..|> ICommandHandler: implements\nLoggingCommandHandlerDecorator *..|> ICommandHandler: decorates\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Dependency-Injection/README.md",
    "content": "# Dependency Injection\n\n## Definition\n\n*Dependency Injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.*\n\nSource: [Wikipedia](https://en.wikipedia.org/wiki/Dependency_injection)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/HSun3i8m30NGdLF00LBlJ1rOE4PgcpOqiIl7KLLEJpeWbl-bfp_yiNeqRoLVRaamD-9c-RguR_KEO74VvkHBcrfbGnLdyG6rm3hRvvXuXQBKShHGL3JtQTZF828eiJeRa685Z1wppa5VeLkfyE2DXLZm24zvCtfI0VfZ-k6mdUV6xhs_)\n\n### Code\n\n```csharp\n\ninternal class CancelMeetingCommandHandler : ICommandHandler<CancelMeetingCommand>\n{\n    private readonly IMeetingRepository _meetingRepository;\n    private readonly IMemberContext _memberContext;\n\n    internal CancelMeetingCommandHandler(IMeetingRepository meetingRepository, IMemberContext memberContext)\n    {\n        _meetingRepository = meetingRepository;\n        _memberContext = memberContext;\n    }\n\n    public async Task<Unit> Handle(CancelMeetingCommand request, CancellationToken cancellationToken)\n    {\n        var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\n\n        meeting.Cancel(_memberContext.MemberId);\n\n        return Unit.Value;\n    }\n}\n\n```\n### Description\n\nA `CancelMeetingCommandHandler` needs two collaborators (dependencies) to fulfill its job - repository of meetings (`IMeetingRepository`) and information about member context (`IMemberContext`). It doesn't instance implementation of these interfaces itself - they are provided (injected) via construction (*Constructor Injection*)."
  },
  {
    "path": "docs/catalog-of-terms/Dependency-Injection/dependency-injection.puml",
    "content": "@startuml Dependency Injection\n\nclass \"CancelMeetingCommandHandler\" {\nCancelMeetingCommandHandler(IMeetingRepository meetingRepository, IMemberContext memberContext)\n}\n\ninterface \"IMeetingRepository\" {\n\n}\n\ninterface \"IMemberContext\" {\n\n}\n\n\"CancelMeetingCommandHandler\" -> \"IMeetingRepository\" : uses\n\"CancelMeetingCommandHandler\" -> \"IMemberContext\" : uses\n\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Domain-Event/README.md",
    "content": "# Domain Event\n\n## Definition\n\n*An event is something that has happened in the past. A **domain event** is, something that happened in the domain that you want other parts of the same domain (in-process) to be aware of. The notified parts usually react somehow to the events.*\n\nSource: [Domain events: design and implementation](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/ZL31Ii0m3BttAtgN_S3mC9mUTfemy1xR28Ks7Kag3lNVZMC7BHwyb9UyrvV7cqI1jPNiGWOHlxLd2PnsJPKUuIX8EZE2Ohol1H8zlDh6lpj_yuToYROtZ6oeKo2d6kSQqOYvDb8-hcbJq2O6dY2tasxCIE5mdrUe7wVlGD0bKkGN2EYNFjLvU0tXsoAkP1Rkb-RsOnXwlz6dicSiDehhkFF3_rePFRufKXGtsMkLVW40)\n\n### Code\n\n```csharp\n\npublic class SubscriptionPaymentCreatedDomainEvent : DomainEventBase\n{\n    public SubscriptionPaymentCreatedDomainEvent(\n        Guid subscriptionPaymentId,\n        Guid payerId,\n        string subscriptionPeriodCode,\n        string countryCode,\n        string status,\n        decimal value,\n        string currency)\n    {\n        SubscriptionPaymentId = subscriptionPaymentId;\n        PayerId = payerId;\n        SubscriptionPeriodCode = subscriptionPeriodCode;\n        CountryCode = countryCode;\n        Status = status;\n        Value = value;\n        Currency = currency;\n    }\n\n    public Guid SubscriptionPaymentId { get; }\n    public Guid PayerId { get; }\n    public string SubscriptionPeriodCode { get; }\n    public string CountryCode { get; }\n    public string Status { get; }\n    public decimal Value { get; }\n    public string Currency { get; }\n}\n\npublic class DomainEventBase : IDomainEvent\n{\n    public Guid Id { get; }\n    public DateTime OccurredOn { get; }\n\n    public DomainEventBase()\n    {\n        this.Id = Guid.NewGuid();\n        this.OccurredOn = DateTime.UtcNow;\n    }\n}\n\n```\n### Description\n\nA `SubscriptionPaymentCreatedDomainEvent` gets fired within the `SubscriptionPayment` aggregate root. This happens whenever a `Member` who is also a `Payer`, issues a command to buy a `Subscription`. \n\nAll properties are `get` only, because an event is something that has happened in the past, and you can not change the past.\n\nEvent details:\n* `SubscriptionPaymentId` - Auto generated unique Id for the subscription payment.\n* `PayerId` - The Id of the payer wanting to buy a subscription.\n* `SubscriptionPeriodCode` - The period of validity for this subscription:\n  * 1 Month\n  * 6 Months\n  * Custom\n* `CountryCode` - The code of the country that the payer is issuing from.\n* `Status` - Automatically set to *WaitingForPayment*.\n* `Value` - The amount to be paid for the chosen subscription period.\n* `Currecy` - The currency of choice of the payer.\n\n---\nBusiness domain events extend `DomainEventBase` which in-turn implements the `IDomainEvent` interface.\n\nBase event details:\n* `Id` - Auto generated unique Id for the event itself.\n* `OccurredOn` - The point-in-time when the event happened. "
  },
  {
    "path": "docs/catalog-of-terms/Domain-Event/domain-event.puml",
    "content": "@startuml\nclass SubscriptionPaymentCreatedDomainEvent {\n +SubscriptionPaymentId\n +PayerId\n +SubscriptionPeriodCode\n +CountryCode\n +Status\n +Value\n +Currency\n}\nclass DomainEventBase\ninterface IDomainEvent {\n +Id\n +OccurredOn\n}\n\nIDomainEvent <|-- DomainEventBase: implements\nDomainEventBase <|-- SubscriptionPaymentCreatedDomainEvent: extends\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Entity-DDD/README.md",
    "content": "# Entity (DDD)\n\n## Definition\n\n*When an object is distinguished by its identity, rather than its attributes, make this primary to its definition in the model. Keep the class definition simple and focused on life cycle continuity and identity. Define a means of distinguishing each object regardless of its form or history.*\n\nSource: [Domain-Driven Design: Tackling Complexity in the Heart of Software, Eric Evans](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/7OunieCm34JxVugV0nZrgIZ8GOob08DjCV9g67Bwu3IxM-oRUMD3D7Z9Vu-jfkmiRlb_1Oxs9B9u3ik6rMTlOaahf698McXVx7FDibDHzXmj5AsQxsiuUp0pbTWWHgofKOg8MPUWxm2nqkXLiU4AqpIH_6P7XgEBZ5BvxYy0)\n\n### Code\n\n```csharp\n\npublic class MeetingGroup : Entity, IAggregateRoot\n{\n    public MeetingGroupId Id { get; private set; }\n\n    private string _name;\n\n    private string _description;\n\n    private MeetingGroupLocation _location;\n\n    private MemberId _creatorId;\n\n    private List<MeetingGroupMember> _members;\n\n    private DateTime _createDate;\n\n    private DateTime? _paymentDateTo;\n\n    internal static MeetingGroup CreateBasedOnProposal(\n        MeetingGroupProposalId meetingGroupProposalId,\n        string name,\n        string description,\n        MeetingGroupLocation location,\n        MemberId creatorId)\n    {\n        return new MeetingGroup(meetingGroupProposalId, name, description, location, creatorId);\n    }\n\n    private MeetingGroup()\n    {\n        // Only for EF.\n    }\n\n    private MeetingGroup(MeetingGroupProposalId meetingGroupProposalId, string name, string description, MeetingGroupLocation location, MemberId creatorId)\n    {\n        this.Id = new MeetingGroupId(meetingGroupProposalId.Value);\n        this._name = name;\n        this._description = description;\n        this._creatorId = creatorId;\n        this._location = location;\n        this._createDate = SystemClock.Now;\n\n        this.AddDomainEvent(new MeetingGroupCreatedDomainEvent(this.Id, creatorId));\n\n        this._members = new List<MeetingGroupMember>();\n        this._members.Add(MeetingGroupMember.CreateNew(this.Id, this._creatorId, MeetingGroupMemberRole.Organizer));\n    }\n\n    public void EditGeneralAttributes(string name, string description, MeetingGroupLocation location)\n    {\n        this._name = name;\n        this._description = description;\n        this._location = location;\n\n        this.AddDomainEvent(new MeetingGroupGeneralAttributesEditedDomainEvent(this._name, this._description, this._location));\n    }\n\n    public void JoinToGroupMember(MemberId memberId)\n    {\n        this.CheckRule(new MeetingGroupMemberCannotBeAddedTwiceRule(_members, memberId));\n\n        this._members.Add(MeetingGroupMember.CreateNew(this.Id, memberId, MeetingGroupMemberRole.Member));\n    }\n\n    public void LeaveGroup(MemberId memberId)\n    {\n        this.CheckRule(new NotActualGroupMemberCannotLeaveGroupRule(_members, memberId));\n\n        var member = this._members.Single(x => x.IsMember(memberId));\n\n        member.Leave();\n    }\n\n    public void SetExpirationDate(DateTime dateTo)\n    {\n        _paymentDateTo = dateTo;\n\n        this.AddDomainEvent(new MeetingGroupPaymentInfoUpdatedDomainEvent(this.Id, _paymentDateTo.Value));\n    }\n\n    public Meeting CreateMeeting(\n        string title,\n        MeetingTerm term,\n        string description,\n        MeetingLocation location,\n        int? attendeesLimit,\n        int guestsLimit,\n        Term rsvpTerm,\n        MoneyValue eventFee,\n        List<MemberId> hostsMembersIds,\n        MemberId creatorId)\n    {\n        this.CheckRule(new MeetingCanBeOrganizedOnlyByPayedGroupRule(_paymentDateTo));\n\n        this.CheckRule(new MeetingHostMustBeAMeetingGroupMemberRule(creatorId, hostsMembersIds, _members));\n\n        return Meeting.CreateNew(\n            this.Id,\n            title,\n            term,\n            description,\n            location,\n            MeetingLimits.Create(attendeesLimit, guestsLimit),\n            rsvpTerm,\n            eventFee,\n            hostsMembersIds,\n            creatorId);\n    }\n\n    internal bool IsMemberOfGroup(MemberId attendeeId)\n    {\n        return _members.Any(x => x.IsMember(attendeeId));\n    }\n\n    internal bool IsOrganizer(MemberId memberId)\n    {\n        return _members.Any(x => x.IsOrganizer(memberId));\n    }\n}\n\n```\n\n### Description\n\nA *Meeting Group* is something we want to follow in time (it has a life cycle). For this reason, it has its unique identifier (`Id`). Is should be fully encapsulated - you can only mutate its state via exposed *behavior* (no setters)."
  },
  {
    "path": "docs/catalog-of-terms/Entity-DDD/entity-ddd.puml",
    "content": "@startuml Entity\n\nclass \"MeetingGroup\" << Entity >> {\n    MeetingGroupId: Id\n    -string: _description\n    -DateTime: _createDate\n    -DateTime: _paymentDateTo\n    {static} MeetingGroup CreateBasedOnProposal()\n    Meeting CreateMeeting(..)\n    void SetExpirationDate(DateTime dateTo)\n    void JoinToGroupMember(MemberId memberId)\n    void LeaveGroup(MemberId memberId)\n    void EditGeneralAttributes(...)\n    bool IsMemberOfGroup(MemberId attendeeId)\n    bool IsOrganizer(MemberId memberId)\n}\n\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/Event/README.md",
    "content": "# Event\n\n## Definition\n\n*An event is something that has happened in the past.*\n\nSource: [Domain events: design and implementation](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation)\n\n## Example\n\nFor examples, see specific kind of events: \n- [Domain Event](../Domain-Event/)\n- [Integration Event](../Integration-Event/)\n\n## Related\n\n- [Event Driven Architecture](../Event-Driven-Architecture/)\n- [Event Storming](../Event-Storming/)\n- [Event Sourcing](../Event-Sourcing/)"
  },
  {
    "path": "docs/catalog-of-terms/Event-Driven-Architecture/README.md",
    "content": "# Event Driven Architecture\n\nTODO"
  },
  {
    "path": "docs/catalog-of-terms/Event-Sourcing/README.md",
    "content": "# Event Sourcing\n\nTODO"
  },
  {
    "path": "docs/catalog-of-terms/Event-Storming/README.md",
    "content": "# Event Storming\n\nTODO"
  },
  {
    "path": "docs/catalog-of-terms/Integration-Event/README.md",
    "content": "# Integration Event\n\nTODO"
  },
  {
    "path": "docs/catalog-of-terms/README.md",
    "content": "# Catalog of terms\n\n- Act/Arrange/Assert\n- Actor (Event Storming)\n- API\n- Application Layer\n- [Aggregate (DDD)](Aggregate-DDD/)\n- Architecture Decision Record (ADR)\n- Architecture Test\n- Asynchronous Communication\n- Audit Log/Trail\n- Authentication\n- Authorization\n- Bounded Context (DDD)\n- C4 Model\n- Chain Of Command Pattern\n- [Command](Command/)\n- Composition Root\n- Continuous Integration\n- Contract\n- CQRS\n- Database Change Management\n- [Decorator Pattern](Decorator-Pattern/)\n- [Dependency Injection](Dependency-Injection/)\n- Dependency Inversion\n- Diagram as text\n- Domain Centric Architecture\n- [Domain Event](Domain-Event/)\n- Domain Layer\n- Domain Model\n- Domain Primitive\n- Domain Services (DDD)\n- Don't Repeat Yourself Principle\n- Encapsulation\n- [Entity (DDD)](Entity-DDD/)\n- [Event](Event/)\n- Eventual Consistency\n- [Event Driven Architecture](Event-Driven-Architecture/)\n- [Event Sourcing](Event-Sourcing/)\n- [Event Storming](Event-Storming/)\n- Events Stream\n- External System (Event Storming)\n- Facade Pattern\n- Factory Pattern\n- Given When Then\n- Layered Architecture\n- Mediator Pattern\n- Message (Messaging)\n- Mock\n- Modularity\n- Module\n- Monolith\n- Idempotency\n- Immediate Consistency\n- Immutability\n- Infrastructure Layer\n- [Integration Event](Integration-Event/)\n- Interface\n- Interface Segregation Principle\n- Inversion Of Control\n- Integration Test\n- Outbox Pattern (aka Store And Forward)\n- Parameter Object Pattern\n- Persistence Ignorance\n- POCO\n- Policy (EventStorming)\n- Projection (EventSourcing)\n- Pure Function\n- Rich Domain Model\n- Role-based Access Control\n- Query\n- Read Model\n- Repositories (DDD)\n- Single Responsibility Principle\n- [Strategy Pattern](Strategy-Pattern/)\n- Stub\n- Synchronous Communication\n- Transaction (Database)\n- Ubiquitous Language (DDD)\n- Unit Of Work Pattern\n- Unit Test\n- Write Model\n- [ValueObject (DDD)](ValueObject-DDD/)"
  },
  {
    "path": "docs/catalog-of-terms/Strategy-Pattern/README.md",
    "content": "# Strategy Pattern\n\n## Definition\n\n*The strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.*\n\nSource: [Wikipedia](https://en.wikipedia.org/wiki/Strategy_pattern)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/jLDDQnin4BtFhnZIYzFQsxin9lM6f8KU38PUYooDNL5z66cMPd7wtwlrHifs3Oqfs63GpBpvUBFpxYABm8qrS13ofzWJtZoIew3b3RwxF_tm2DA86B4scXmd4sSelMDwOlWDETWx-cZa89ZsBU07ZCIR5tEI_RTTGFd9RPUlKsBO2KcOSNZiulH4ic7gGQM93CIKWPykHgxEaGbREA-QTjDiempwmDgxS-uZGEsj5KvzJdz3eQp4aUoYdRKEMj9N7Vb1IFQXhUf0Wgcu9w_mmTWbt9VyVaYsTllDO9zzdObcid6A1J1Ox2FngKvgqJWERUqLJJ4EnbzJq5vDKNP9QRZHT_Yo_hig7l-tR25shmD9_YPCGm_1syBpgfskKJoUqaXTbKhgzqChGh87Rj6ItLA802y2d2d_oysUbrbpaBNtVZOh6e8on-8vkS-KyqPy1U0y4nhQCVfTRZMVAu-0jJ0cucAxp8AkYh0M7xTB8AUmImU0Vmkdfx9ylNl8hvxD-19Xw2ZJltLTbsTVc73v5OpMM63pURwCuJh7Ug_A-LHLDLhjNNerrlm1)\n\n### Code\n\n```csharp\n\ninternal class BuySubscriptionCommandHandler : ICommandHandler<BuySubscriptionCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        private readonly IPayerContext _payerContext;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        internal BuySubscriptionCommandHandler(\n            IAggregateStore aggregateStore,\n            IPayerContext payerContext,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _aggregateStore = aggregateStore;\n            _payerContext = payerContext;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<Guid> Handle(BuySubscriptionCommand command, CancellationToken cancellationToken)\n        {\n            var priceList = await PriceListFactory.CreatePriceList(_sqlConnectionFactory.GetOpenConnection());\n\n            var subscription = SubscriptionPayment.Buy(\n                _payerContext.PayerId,\n                SubscriptionPeriod.Of(command.SubscriptionTypeCode),\n                command.CountryCode,\n                MoneyValue.Of(command.Value, command.Currency),\n                priceList);\n\n            _aggregateStore.AppendChanges(subscription);\n\n            return subscription.Id;\n        }\n    }\n\npublic static class PriceListFactory\n    {\n        public static async Task<PriceList> CreatePriceList(IDbConnection connection)\n        {\n            var priceListItemList = await GetPriceListItems(connection);\n\n            var priceListItems = priceListItemList\n                .Select(x =>\n                    new PriceListItemData(\n                        x.CountryCode,\n                        SubscriptionPeriod.Of(x.SubscriptionPeriodCode),\n                        MoneyValue.Of(x.MoneyValue, x.MoneyCurrency),\n                        PriceListItemCategory.Of(x.CategoryCode)))\n                .ToList();\n\n            // This is place for selecting pricing strategy based on provided data and the system state.\n            IPricingStrategy pricingStrategy = new DirectValueFromPriceListPricingStrategy(priceListItems);\n\n            return PriceList.Create(\n                priceListItems,\n                pricingStrategy);\n        }\n\n        public static async Task<List<PriceListItemDto>> GetPriceListItems(IDbConnection connection)\n        {\n            var priceListItems = await connection.QueryAsync<PriceListItemDto>(\"SELECT \" +\n$\"[PriceListItem].[CountryCode] AS [{nameof(PriceListItemDto.CountryCode)}], \" +\n$\"[PriceListItem].[SubscriptionPeriodCode] AS [{nameof(PriceListItemDto.SubscriptionPeriodCode)}], \" +\n$\"[PriceListItem].[MoneyValue] AS [{nameof(PriceListItemDto.MoneyValue)}], \" +\n$\"[PriceListItem].[MoneyCurrency] AS [{nameof(PriceListItemDto.MoneyCurrency)}], \" +\n$\"[PriceListItem].[CategoryCode] AS [{nameof(PriceListItemDto.CategoryCode)}] \" +\n\"FROM [payments].[PriceListItems] AS [PriceListItem] \" +\n\"WHERE [PriceListItem].[IsActive] = 1\");\n\n            var priceListItemList = priceListItems.AsList();\n            return priceListItemList;\n        }\n    }\n\npublic class PriceList : ValueObject\n    {\n        private readonly List<PriceListItemData> _items;\n\n        private readonly IPricingStrategy _pricingStrategy;\n\n        private PriceList(\n            List<PriceListItemData> items,\n            IPricingStrategy pricingStrategy)\n        {\n            _items = items;\n            _pricingStrategy = pricingStrategy;\n        }\n\n        public static PriceList Create(\n            List<PriceListItemData> items,\n            IPricingStrategy pricingStrategy)\n        {\n            return new PriceList(items, pricingStrategy);\n        }\n\n        public MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category)\n        {\n            CheckRule(new PriceForSubscriptionMustBeDefinedRule(countryCode, subscriptionPeriod, _items, category));\n\n            return _pricingStrategy.GetPrice(countryCode, subscriptionPeriod, category);\n        }\n    }\n\npublic interface IPricingStrategy\n    {\n        MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category);\n    }\n\npublic class DiscountedValueFromPriceListPricingStrategy : IPricingStrategy\n    {\n        private readonly List<PriceListItemData> _items;\n\n        private readonly MoneyValue _discountValue;\n\n        public DiscountedValueFromPriceListPricingStrategy(\n            List<PriceListItemData> items,\n            MoneyValue discountValue)\n        {\n            _items = items;\n            _discountValue = discountValue;\n        }\n\n        public MoneyValue GetPrice(string countryCode, SubscriptionPeriod subscriptionPeriod, PriceListItemCategory category)\n        {\n            var priceListItem = _items.Single(x =>\n                x.CountryCode == countryCode && x.SubscriptionPeriod == subscriptionPeriod &&\n                x.Category == category);\n\n            return priceListItem.Value - _discountValue;\n        }\n    }\n\n public class DirectValuePricingStrategy : IPricingStrategy\n    {\n        private readonly MoneyValue _directValue;\n\n        public DirectValuePricingStrategy(MoneyValue directValue)\n        {\n            _directValue = directValue;\n        }\n\n        public MoneyValue GetPrice(string countryCode, SubscriptionPeriod subscriptionPeriod, PriceListItemCategory category)\n        {\n            return _directValue;\n        }\n    }\n\npublic class DirectValueFromPriceListPricingStrategy : IPricingStrategy\n    {\n        private readonly List<PriceListItemData> _items;\n\n        public DirectValueFromPriceListPricingStrategy(List<PriceListItemData> items)\n        {\n            _items = items;\n        }\n\n        public MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category)\n        {\n            var priceListItem = _items.Single(x =>\n                x.CountryCode == countryCode && x.SubscriptionPeriod == subscriptionPeriod &&\n                x.Category == category);\n\n            return priceListItem.Value;\n        }\n    }\n```\n### Description\n\nLet's introduce the concepts of the strategy pattern, so we can understand how the above example fits this pattern.\n\n* **Client** - The calling code.\n* **Context** - An object which maintains a reference to one of the *concrete strategies* and communicates with the *client*.\n* **Strategy interface** - An interface or abstract class that the *client* can use to set a concrete strategy at run-time, through the *context*.\n* **Concrete strategies** - One or more implementations of the *strategy interface*.\n\n---\n\nIf we have a close look at our example of buying a `Subscription`, we can notice the elements of the strategy pattern.\n\n* `BuySubscriptionCommandHandler` is the calling code! Also the handler, indirectly via the `PriceListFactory` sets the current *strategy* of `PriceList`, so their combined interaction represents the **Client**. \n* `PriceList` is the object which maintains a reference to a pricing strategy, so it represents the **Context**. \n* `IPricingStrategy` represents the **Strategy interface**.\n* `DiscountedValueFromPriceListPricingStrategy`, `DirectValueFromPriceListPricingStrategy` and `DirectValuePricingStrategy` are the implementations of `IPricingStrategy` so they represent the **Concrete strategies**.\n\n---\n\n The interaction of the `BuySubscriptionCommandHandler` and `PriceListFactory` is a good example of leveraging multiple design patterns. Check out [Factory Pattern](../Factory-Pattern/) to learn more.\n\nStrategy should not be confused with [Decorator](../Decorator-Pattern/)!!!\n*A strategy lets you change the guts of an object, while decorator lets you change the skin.*"
  },
  {
    "path": "docs/catalog-of-terms/Strategy-Pattern/strategy-pattern.puml",
    "content": "@startuml\npackage \"Generic\" #DDDDDD {\nclass Client {\n - context\n}\n\nclass Context {\n - strategy\n + setStrategy(strategy)\n + do()\n}\n\ninterface Strategy {\n + execute()\n}\n\nclass ConcreteStrategyA {\n + execute()\n}\n\nclass ConcreteStrategyB {\n + execute()\n}\n}\n\npackage \"BuySubscription\" #DDDDDD {\nclass BuySubscriptionCommandHandler {\n - connection\n - PriceListFactory.CreatePriceList(connection)\n}\n\nclass PriceList {\n - _pricingStrategy\n + Create(items, pricingStrategy)\n + GetPrice(countryCode, subscriptionPeriod, category)\n}\n\ninterface IPricingStrategy {\n + GetPrice(countryCode, subscriptionPeriod, category)\n}\n\nclass DirectValueFromPriceListPricingStrategy {\n + GetPrice(countryCode, subscriptionPeriod, category)\n}\n\nclass DirectValuePricingStrategy {\n + GetPrice(countryCode, subscriptionPeriod, category)\n}\n\nclass DiscountedValueFromPriceListPricingStrategy {\n + GetPrice(countryCode, subscriptionPeriod, category)\n}\n}\n\nhide empty members\n\nClient -down-|> Context\nContext *-- Strategy\nStrategy <|-- ConcreteStrategyA\nStrategy <|-- ConcreteStrategyB\n\nnote left of Context::do \n Calls <b>strategy.execute()</b>\nend note\n\n\nBuySubscriptionCommandHandler -down-> PriceList\nPriceList *-- IPricingStrategy\nIPricingStrategy <|-- DirectValueFromPriceListPricingStrategy\nIPricingStrategy <|-- DirectValuePricingStrategy\nIPricingStrategy <|-- DiscountedValueFromPriceListPricingStrategy\n\nnote left of PriceList::GetPrice \n Calls <b>_pricingStrategy.GetPrice(...)</b>\nend note\n@enduml"
  },
  {
    "path": "docs/catalog-of-terms/ValueObject-DDD/README.md",
    "content": "# ValueObject (DDD)\n\n## Definition\n\n*When you care only about the attributes of an element of the model, classify it as a VALUE OBJECT. Make it express the meaning of the attributes it conveys and give it related functionality. Treat the VALUE OBJECT as immutable. Don't give it any identity and avoid the design complexities necessary to maintain ENTITIES.*\n\nSource: [Domain-Driven Design: Tackling Complexity in the Heart of Software, Eric Evans](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215)\n\n## Example\n\n### Model\n\n![](http://www.plantuml.com/plantuml/png/7OwnSiCm34FtVaNx0JBtJXwyT-jEYupjc19z51bVylMniW27Ty0TnkPe7aM-VhQQ9OZ3v7jrFzelWE4vB9klCKTZorgTgmzP2-oBlPupxr2KGj1IqQfoLTFPXOYWO7Cs8CqDCZgABablwMAbmJzAyDzyv-nfcYPuz9pq0_fwEFgdaIjT_WO0)\n\n### Code\n\n```csharp\n\npublic class MoneyValue : ValueObject\n{\n    public decimal Value { get; }\n\n    public string Currency { get; }\n\n    private MoneyValue(decimal value, string currency)\n    {\n        this.Value = value;\n        this.Currency = currency;\n    }\n\n    public static MoneyValue Of(decimal value, string currency)\n    {\n        CheckRule(new ValueOfMoneyMustNotBeNegativeRule(value));\n\n        return new MoneyValue(value, currency);\n    }\n\n    public static bool operator >(decimal left, MoneyValue right) => left > right.Value;\n\n    public static bool operator <(decimal left, MoneyValue right) => left < right.Value;\n\n    public static bool operator >=(decimal left, MoneyValue right) => left >= right.Value;\n\n    public static bool operator <=(decimal left, MoneyValue right) => left <= right.Value;\n\n    public static bool operator >(MoneyValue left, decimal right) => left.Value > right;\n\n    public static bool operator <(MoneyValue left, decimal right) => left.Value < right;\n\n    public static bool operator >=(MoneyValue left, decimal right) => left.Value >= right;\n\n    public static bool operator <=(MoneyValue left, decimal right) => left.Value <= right;\n}\n\n```\n\n### Description\n\nA *Money Value* class represents concept of money. In our Domain, we don't want to follow money in time (it does not have a life cycle). It does not have an identity either. Whole object is **immutable** (`Value` and `Currency` defined as readonly). The comparison is done by comparing attribute values, not identifiers (see `ValueObject` abstract class)."
  },
  {
    "path": "docs/catalog-of-terms/ValueObject-DDD/value-object-ddd.puml",
    "content": "@startuml ValueObject\n\nclass \"MeetingGroup\" << ValueObject >> {\n    decimal: Value {readonly}\n    string: Currency {readonly}\n}\n\n@enduml"
  },
  {
    "path": "docs/mutation-tests-reports/mutation-report.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"UTF-8\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n        <script>/*! For license information please see mutation-test-elements.js.LICENSE.txt */\n(()=>{var e={8986:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\":host{background-color:var(--bs-body-bg);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1rem;font-weight:400;line-height:1.15;line-height:1.5;margin:0;text-align:left}.container-fluid{background-color:var(--bs-body-bg)}.display-4 small{font-weight:300}.theme-switch{float:right;margin-left:1em;margin-right:1em;padding-top:.5em;position:sticky;top:var(--top-offset,0);z-index:20}.nav-link{outline:none}\",\"\"]);const a=s},3704:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>v});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i),a=r(8991),l=r.n(a),c=new URL(r(7327),r.b),d=new URL(r(3726),r.b),u=new URL(r(6076),r.b),h=new URL(r(5605),r.b),b=s()(o()),p=l()(c),g=l()(d),f=l()(u),m=l()(h);b.push([e.id,\"/*!\\n * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)\\n * Copyright 2011-2021 The Bootstrap Authors\\n * Copyright 2011-2021 Twitter, Inc.\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\\n */*,:after,:before{box-sizing:border-box}@media(prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}h1,h5,h6{font-weight:500;line-height:1.2;margin-bottom:.5rem;margin-top:0}h1{font-size:calc(1.375rem + 1.5vw)}@media(min-width:1200px){h1{font-size:2.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}ol,ul{margin-bottom:1rem;margin-top:0;padding-left:2rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}b{font-weight:bolder}small{font-size:.875em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,pre{direction:ltr;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;unicode-bidi:bidi-override}pre{display:block;font-size:.875em;margin-bottom:1rem;margin-top:0;overflow:auto}pre code{color:inherit;font-size:inherit;word-break:normal}code{word-wrap:break-word;color:#d63384;font-size:.875em}a>code{color:inherit}img,svg{vertical-align:middle}table{border-collapse:collapse;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,th,thead,tr{border:0 solid;border-color:inherit}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button{text-transform:none}[role=button]{cursor:pointer}[type=button],button{-webkit-appearance:button}[type=button]:not(:disabled),button:not(:disabled){cursor:pointer}legend{float:left;font-size:calc(1.275rem + .3vw);line-height:inherit;margin-bottom:.5rem;padding:0;width:100%}@media(min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}summary{cursor:pointer;display:list-item}progress{vertical-align:baseline}:host{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-caution:#fd7e14;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41}:host(:not([theme=dark])){--bs-link-color:#0d6efd;--bs-link-hover-color:#0a58ca;--bs-breadcrumb-bg:#e9ecef;--bs-breadcrumb-active-color:#6c757d;--bs-body-bg:#fff;--bs-body-color:#212529;--bs-card-bg:#fff;--bs-card-border-color:rgba(0,0,0,.125);--bs-card-cap-bg:#e9ecef;--bs-list-group-hover-bg:#f8f9fa;--bs-list-group-bg:#fff;--bs-list-group-border-color:rgba(0,0,0,.125);--bs-list-group-action-hover-color:#495057;--bs-list-group-action-active-color:#212529;--bs-list-group-action-active-bg:#e9ecef;--bs-list-group-action-color:#495057;--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;--bs-table-border-color:#dee2e6;--bs-table-bg-hover:rgba(0,0,0,.075);--bs-progress-bg:#e9ecef;--bs-table-caution-hover-bg:#f57102;--bs-badge-caution-color:#000;--bs-btn-caution-color:#000;--bs-btn-caution-hover-color:#000;--bs-caution-bg:#fd7e14;--bs-caution-bg-light:rgba(253,126,20,.25);--bs-table-primary-hover-bg:#0262ef;--bs-badge-primary-color:#fff;--bs-btn-primary-color:#fff;--bs-btn-primary-hover-color:#fff;--bs-primary-bg:#0d6efd;--bs-primary-bg-light:rgba(13,110,253,.25);--bs-table-secondary-hover-bg:#60686f;--bs-badge-secondary-color:#fff;--bs-btn-secondary-color:#fff;--bs-btn-secondary-hover-color:#fff;--bs-secondary-bg:#6c757d;--bs-secondary-bg-light:hsla(208,7%,46%,.25);--bs-table-success-hover-bg:#157147;--bs-badge-success-color:#fff;--bs-btn-success-color:#fff;--bs-btn-success-hover-color:#fff;--bs-success-bg:#198754;--bs-success-bg-light:rgba(25,135,84,.25);--bs-table-info-hover-bg:#0cb6d8;--bs-badge-info-color:#000;--bs-btn-info-color:#000;--bs-btn-info-hover-color:#000;--bs-info-bg:#0dcaf0;--bs-info-bg-light:rgba(13,202,240,.25);--bs-table-warning-hover-bg:#edb100;--bs-badge-warning-color:#000;--bs-btn-warning-color:#000;--bs-btn-warning-hover-color:#000;--bs-warning-bg:#ffc107;--bs-warning-bg-light:rgba(255,193,7,.25);--bs-table-danger-hover-bg:#d32535;--bs-badge-danger-color:#fff;--bs-btn-danger-color:#fff;--bs-btn-danger-hover-color:#fff;--bs-danger-bg:#dc3545;--bs-danger-bg-light:rgba(220,53,69,.25);--bs-table-light-hover-bg:#e9ecef;--bs-badge-light-color:#000;--bs-btn-light-color:#000;--bs-btn-light-hover-color:#000;--bs-light-bg:#f8f9fa;--bs-light-bg-light:rgba(248,249,250,.25);--bs-table-dark-hover-bg:#16181b;--bs-badge-dark-color:#fff;--bs-btn-dark-color:#fff;--bs-btn-dark-hover-color:#fff;--bs-dark-bg:#212529;--bs-dark-bg-light:rgba(33,37,41,.25);--bs-anchor:#f5f6f7;--bs-nav-tabs-link-hover-border-color:#e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color:#495057;--bs-nav-tabs-link-active-bg:#fff;--bs-nav-tabs-link-active-border-color:#dee2e6 #dee2e6 #fff;--bs-nav-tabs-border-color:#dee2e6}:host([theme=dark]){--bs-link-color:#538ce9;--bs-link-hover-color:#1b62d4;--bs-breadcrumb-bg:#242526;--bs-breadcrumb-active-color:#dadde1;--bs-body-bg:#18191a;--bs-body-color:#f5f6f7;--bs-card-bg:#1c1e21;--bs-card-border-color:rgba(0,0,0,.125);--bs-card-cap-bg:#1c1e21;--bs-list-group-hover-bg:#606770;--bs-list-group-bg:#242526;--bs-list-group-border-color:#1c1e21;--bs-list-group-action-hover-color:#f5f6f7;--bs-list-group-action-active-color:#f5f6f7;--bs-list-group-action-active-bg:#606770;--bs-list-group-action-color:#f5f6f7;--bs-list-group-active-color:#f5f6f7;--bs-list-group-active-bg:#3578e5;--bs-list-group-active-border-color:#3578e5;--bs-table-border-color:#606770;--bs-table-bg-hover:#242526;--bs-progress-bg:#242526;--bs-table-primary-bg:#3578e5;--bs-table-primary-hover-bg:#1e69e2;--bs-badge-primary-color:#000;--bs-btn-primary-color:#000;--bs-btn-primary-hover-color:#fff;--bs-primary-bg:#3578e5;--bs-primary-bg-light:rgba(53,120,229,.25);--bs-table-secondary-bg:#242526;--bs-table-secondary-hover-bg:#181819;--bs-badge-secondary-color:#fff;--bs-btn-secondary-color:#fff;--bs-btn-secondary-hover-color:#fff;--bs-secondary-bg:#242526;--bs-secondary-bg-light:rgba(36,37,38,.25);--bs-table-success-bg:#009400;--bs-table-success-hover-bg:#007b00;--bs-badge-success-color:#000;--bs-btn-success-color:#000;--bs-btn-success-hover-color:#fff;--bs-success-bg:#009400;--bs-success-bg-light:rgba(0,148,0,.25);--bs-table-info-bg:#54c7ec;--bs-table-info-hover-bg:#3dbfe9;--bs-badge-info-color:#000;--bs-btn-info-color:#000;--bs-btn-info-hover-color:#000;--bs-info-bg:#54c7ec;--bs-info-bg-light:rgba(84,199,236,.25);--bs-table-warning-bg:#ffc426;--bs-table-warning-hover-bg:#ffbd0d;--bs-badge-warning-color:#000;--bs-btn-warning-color:#000;--bs-btn-warning-hover-color:#000;--bs-warning-bg:#ffc426;--bs-warning-bg-light:rgba(255,196,38,.25);--bs-table-danger-bg:#e13238;--bs-table-danger-hover-bg:#da2026;--bs-badge-danger-color:#000;--bs-btn-danger-color:#000;--bs-btn-danger-hover-color:#fff;--bs-danger-bg:#e13238;--bs-danger-bg-light:rgba(225,50,56,.25);--bs-table-light-bg:#8d949e;--bs-table-light-hover-bg:#7f8792;--bs-badge-light-color:#000;--bs-btn-light-color:#000;--bs-btn-light-hover-color:#000;--bs-light-bg:#8d949e;--bs-light-bg-light:hsla(215,8%,59%,.25);--bs-table-caution-bg:#ff8b26;--bs-table-caution-hover-bg:#ff7d0d;--bs-badge-caution-color:#000;--bs-btn-caution-color:#000;--bs-btn-caution-hover-color:#000;--bs-caution-bg:#ff8b26;--bs-caution-bg-light:rgba(255,139,38,.25);--bs-table-dark-bg:#1c1e21;--bs-table-dark-hover-bg:#101113;--bs-badge-dark-color:#fff;--bs-btn-dark-color:#fff;--bs-btn-dark-hover-color:#fff;--bs-dark-bg:#1c1e21;--bs-dark-bg-light:rgba(28,30,33,.25);--bs-nav-tabs-link-hover-border-color:#242526 #242526 transparent;--bs-nav-tabs-link-active-color:#f5f6f7;--bs-nav-tabs-link-active-bg:#242526;--bs-nav-tabs-link-active-border-color:#242526 #242526 transparent;--bs-nav-tabs-border-color:#242526}:host(:not([theme=dark])){--prism-maintext:#393a34;--prism-background:#f6f8fa;--prism-border:#ddd;--prism-operator:var(--prism-maintext);--prism-punctuation:var(--prism-maintext);--prism-atrule:#00a4db;--prism-attr:var(--prism-atrule);--prism-selector:var(--prism-atrule);--prism-cdata:#998;--prism-comment:var(--prism-cdata);--prism-doctype:var(--prism-cdata);--prism-prolog:var(--prism-cdata);--prism-deleted:#6f42c1;--prism-function:var(--prism-deleted);--prism-tag:var(--prism-deleted);--prism-boolean:#36acaa;--prism-constant:var(--prism-boolean);--prism-entity:var(--prism-boolean);--prism-inserted:var(--prism-boolean);--prism-number:var(--prism-boolean);--prism-property:var(--prism-boolean);--prism-regex:var(--prism-boolean);--prism-symbol:var(--prism-boolean);--prism-url:var(--prism-boolean);--prism-variable:var(--prism-boolean);--prism-attr:#e3116c;--prism-string:var(--prism-attr);--prism-keyword:#00009f;--prism-selector:var(--prism-keyword);--prism-tag:var(--prism-keyword)}:host([theme=dark]){--prism-maintext:#d3d0c8;--prism-background:#2d2d2d;--prism-border:#393939;--prism-cdata:#747369;--prism-comment:var(--prism-cdata);--prism-doctype:var(--prism-cdata);--prism-prolog:var(--prism-cdata);--prism-punctuation:#d3d0c8;--prism-attr-name:#f99157;--prism-boolean:var(--prism-attr-name);--prism-number:var(--prism-attr-name);--prism-operator:var(--prism-attr-name);--prism-property:#fc6;--prism-placeholder:#69c;--prism-tag:var(--prism-placeholder);--prism-variable:var(--prism-placeholder);--prism-selector:#c9c;--prism-keyword:var(--prism-selector);--prism-atrule:#6cc;--prism-entity:var(--prism-atrule);--prism-regex:var(--prism-atrule);--prism-statement:var(--prism-atrule);--prism-string:var(--prism-atrule);--prism-url:var(--prism-atrule);--prism-attr-value:#9c9;--prism-control:var(--prism-attr-value);--prism-directive:var(--prism-attr-value);--prism-unit:var(--prism-attr-value);--prism-important:#ab4642}:host(:not([theme=dark])){--mut-file-ts-color:#498ba7;--mut-file-ts-test-color:#b7b73b;--mut-file-scala-color:#b8383d;--mut-file-java-color:#b8383d;--mut-file-js-color:#b7b73b;--mut-file-js-test-color:#cc6d2e;--mut-file-php-color:#9068b0;--mut-file-html-color:#498ba7;--mut-file-csharp-color:#498ba7;--mut-file-vue-color:#7fae42;--mut-file-gherkin-color:#00a818}:host([theme=dark]){--mut-file-ts-color:#519aba;--mut-file-ts-test-color:#cbcb41;--mut-file-scala-color:#cc3e44;--mut-file-java-color:#cc3e44;--mut-file-js-color:#cbcb41;--mut-file-js-test-color:#e37933;--mut-file-php-color:#a074c4;--mut-file-html-color:#519aba;--mut-file-csharp-color:#519aba;--mut-file-vue-color:#8dc149;--mut-file-gherkin-color:#10b828}:host(:not([theme=dark])){--mut-octicon-icon-color:#498ba7;--mut-line-number:#6e7781;--mut-diff-add-bg:#e6ffec;--mut-diff-add-bg-line-number:#ccffd8;--mut-diff-add-line-number:#24292f;--mut-diff-del-bg:#ffebe9;--mut-diff-del-bg-line-number:#ffd7d5;--mut-diff-del-line-number:var(--mut-diff-add-line-number);--mut-badge-info-bg:#54c6ec;--mut-badge-info:#212529;--mut-code-lense:#919191;--mut-squiggly-danger:url(\"+p+\");--mut-squiggly-caution:url(\"+g+\")}:host([theme=dark]){--mut-octicon-icon-color:#519aba;--mut-line-number:#484f58;--mut-diff-add-bg:rgba(46,160,67,.15);--mut-diff-add-bg-line-number:rgba(63,185,80,.3);--mut-diff-add-line-number:#c9d1d9;--mut-diff-del-bg:rgba(248,81,73,.15);--mut-diff-del-bg-line-number:rgba(248,81,73,.3);--mut-diff-del-line-number:#c9d1d9;--mut-badge-info-bg:#17a3b8;--mut-badge-info:#fff;--mut-code-lense:#999;--mut-squiggly-danger:url(\"+f+\");--mut-squiggly-caution:url(\"+m+\")}\",\"\"]);const v=b},371:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\".list-group-item{background-color:var(--bs-card-cap-bg);color:inherit}\",\"\"]);const a=s},4642:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\".list-group-item{background-color:var(--bs-card-cap-bg);color:inherit}\",\"\"]);const a=s},9483:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\":host{background-color:var(--bs-card-cap-bg);bottom:0;left:0;overflow:hidden;position:fixed;transition:height .2s cubic-bezier(.4,0,.2,1);width:100%;z-index:3}header{border-bottom:1px;padding:1rem;width:100%}header h5{margin:0;padding:0}:host([mode=closed]){height:0}:host([mode=half]){height:120px}:host([mode=open]){height:50%}.summary{overflow:auto}\",\"\"]);const a=s},8847:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\"svg.cs{fill:var(--mut-file-csharp-color)}svg.html{fill:var(--mut-file-html-color)}svg.java{fill:var(--mut-file-java-color)}svg.javascript{fill:var(--mut-file-js-color)}svg.scala{fill:var(--mut-file-scala-color)}svg.typescript{fill:var(--mut-file-ts-color)}svg.php{fill:var(--mut-file-php-color)}svg.vue{fill:var(--mut-file-vue-color)}svg.octicon{fill:var(--mut-octicon-icon-color)}svg.javascript.test,svg.typescript.test{fill:var(--mut-file-js-test-color)}svg.gherkin{fill:var(--mut-file-gherkin-color)}svg{vertical-align:middle}\",\"\"]);const a=s},5545:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,'/*!\\n * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)\\n * Copyright 2011-2021 The Bootstrap Authors\\n * Copyright 2011-2021 Twitter, Inc.\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\\n */*,:after,:before{box-sizing:border-box}@media(prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}h1,h5,h6{font-weight:500;line-height:1.2;margin-bottom:.5rem;margin-top:0}h1{font-size:calc(1.375rem + 1.5vw)}@media(min-width:1200px){h1{font-size:2.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}ol,ul{margin-bottom:1rem;margin-top:0;padding-left:2rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}b{font-weight:bolder}small{font-size:.875em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,pre{direction:ltr;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;unicode-bidi:bidi-override}pre{display:block;font-size:.875em;margin-bottom:1rem;margin-top:0;overflow:auto}pre code{color:inherit;font-size:inherit;word-break:normal}code{word-wrap:break-word;color:#d63384;font-size:.875em}a>code{color:inherit}img,svg{vertical-align:middle}table{border-collapse:collapse;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,th,thead,tr{border:0 solid;border-color:inherit}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button{text-transform:none}[role=button]{cursor:pointer}[type=button],button{-webkit-appearance:button}[type=button]:not(:disabled),button:not(:disabled){cursor:pointer}legend{float:left;font-size:calc(1.275rem + .3vw);line-height:inherit;margin-bottom:.5rem;padding:0;width:100%}@media(min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}summary{cursor:pointer;display:list-item}progress{vertical-align:baseline}:host{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-caution:#fd7e14;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41}#report-code-block{background:var(--prism-background);border:1px solid var(--prism-border);overflow:visible}.line-numbers{counter-reset:mte-line-number}.line .line-number{color:var(--mut-line-number);counter-increment:mte-line-number;padding:0 10px 0 15px;text-align:right}.line .line-number:before{content:counter(mte-line-number)}.line-marker:before{content:\" \";padding:0 5px}.mte-selected-Killed .mutant.Killed{border-bottom:2px solid;border-color:var(--bs-success);cursor:pointer}svg.mutant-dot.Killed{fill:var(--bs-success)}svg.mutant-dot.NoCoverage{fill:var(--bs-caution)}svg.mutant-dot.Survived{fill:var(--bs-danger)}.mte-selected-Timeout .mutant.Timeout{border-bottom:2px solid;border-color:var(--bs-warning);cursor:pointer}svg.mutant-dot.Timeout{fill:var(--bs-warning)}.mte-selected-CompileError .mutant.CompileError{border-bottom:2px solid;border-color:var(--bs-secondary);cursor:pointer}svg.mutant-dot.CompileError{fill:var(--bs-secondary)}.mte-selected-RuntimeError .mutant.RuntimeError{border-bottom:2px solid;border-color:var(--bs-secondary);cursor:pointer}svg.mutant-dot.RuntimeError{fill:var(--bs-secondary)}svg.mutant-dot.selected{fill:var(--bs-info)}.mte-selected-Survived .mutant.Survived{border-bottom-style:solid;border-image-outset:3px;border-image-repeat:repeat;border-image-slice:0 0 4 0;border-image-source:var(--mut-squiggly-danger);border-image-width:4px;cursor:pointer}.mte-selected-Survived .mutant.Survived .mutant.NoCoverage,.mte-selected-Survived .mutant.Survived .mutant.Survived{border-bottom-style:none;border-image:none}.mte-selected-NoCoverage .mutant.NoCoverage{border-bottom-style:solid;border-image-outset:3px;border-image-repeat:repeat;border-image-slice:0 0 4 0;border-image-source:var(--mut-squiggly-caution);border-image-width:4px;cursor:pointer}.mte-selected-NoCoverage .mutant.NoCoverage .mutant.NoCoverage,.mte-selected-NoCoverage .mutant.NoCoverage .mutant.Survived{border-bottom-style:none;border-image:none}.mutant-dot{cursor:pointer}svg.mutant-dot{margin:1px 2px}.diff-old{background-color:var(--mut-diff-del-bg)}.diff-focus{background-color:var(--mut-diff-add-bg-line-number)}.diff-old .line-number{background-color:var(--mut-diff-del-bg-line-number);color:var(--mut-diff-del-line-number)}.diff-old .line-marker:before{content:\"-\"}.diff-new{background-color:var(--mut-diff-add-bg)}.diff-new .empty-line-number{background-color:var(--mut-diff-add-bg-line-number);color:var(--mut-diff-add-line-number)}.diff-new .line-marker:before{content:\"+\"}',\"\"]);const a=s},8469:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\".table a{display:block}th.rotate{height:96px;padding-bottom:10px;white-space:nowrap}th.rotate>div{transform:translate(27px) rotate(325deg);width:30px}table td.icon{padding-left:10px;padding-right:2px}a.info-icon{float:right}a.info-icon,a:not(:hover){text-decoration:none}\",\"\"]);const a=s},3813:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\"main{padding-bottom:120px}\",\"\"]);const a=s},1276:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\".legend{background:var(--bs-body-bg);margin-bottom:.5rem;margin-top:.5rem;padding-bottom:.5rem;padding-top:.5rem;position:sticky;top:var(--top-offset,0);z-index:10}.badge{cursor:pointer;font-size:1em}\",\"\"]);const a=s},5110:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,'#report-code-block{background:var(--prism-background);border:1px solid var(--prism-border);overflow:visible}.line-numbers{counter-reset:mte-line-number}.line .line-number{color:var(--mut-line-number);counter-increment:mte-line-number;padding:0 10px 0 15px;text-align:right}.line .line-number:before{content:counter(mte-line-number)}.line-marker:before{content:\" \";padding:0 5px}svg.test-dot.Killing{fill:var(--bs-success)}svg.test-dot.Covering{fill:var(--bs-warning)}svg.test-dot.NotCovering{fill:var(--bs-caution)}svg.test-dot.selected{fill:var(--bs-info)}.test-dot{cursor:pointer}svg.test-dot{margin:1px 2px}',\"\"]);const a=s},9827:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\"main{padding-bottom:120px}\",\"\"]);const a=s},4835:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,'#darkTheme{position:absolute;right:100vw}#darkTheme+label{--i:0;--j:calc(1 - var(--i));grid-gap:.15em .06em;background:hsl(199,98%,calc(var(--j)*48%));border-radius:.75em;color:transparent;cursor:pointer;display:grid;height:1.5em;overflow:hidden;padding:.15em;transition:.3s;user-select:none}#darkTheme+label:after,#darkTheme+label:before{content:\"\";height:1.2em;transition:inherit;width:1.2em}#darkTheme+label:before{--poly:polygon(44.133707561% 12.9616872277%,50% 0%,55.866292439% 12.9616872277%,59.7057141913% 13.7777815142%,63.4387981079% 14.9907340064%,67.0246437402% 16.5872553429%,79.3892626146% 9.5491502813%,76.5165042945% 23.4834957055%,79.1429735546% 26.4004853356%,81.450146298% 29.5760361869%,83.4127446571% 32.9753562598%,97.5528258148% 34.5491502813%,87.0383127723% 44.133707561%,87.4486075533% 48.0374016409%,87.4486075533% 51.9625983591%,87.0383127723% 55.866292439%,97.5528258148% 65.4508497187%,83.4127446571% 67.0246437402%,81.450146298% 70.4239638131%,79.1429735546% 73.5995146644%,76.5165042945% 76.5165042945%,79.3892626146% 90.4508497187%,67.0246437402% 83.4127446571%,63.4387981079% 85.0092659936%,59.7057141913% 86.2222184858%,55.866292439% 87.0383127723%,50% 100%,44.133707561% 87.0383127723%,40.2942858087% 86.2222184858%,36.561201892% 85.0092659936%,32.9753562598% 83.4127446571%,20.6107373854% 90.4508497187%,23.4834957055% 76.5165042945%,20.8570264454% 73.5995146644%,18.5498537021% 70.4239638131%,16.587255343% 67.0246437402%,2.4471741856% 65.4508497188%,12.9616872286% 55.8662924391%,12.5513924487% 51.9625983594%,12.5513924508% 48.0374016414%,12.961687236% 44.1337075622%,2.4471742159% 34.5491502859%,16.587255404% 32.9753562694%,18.5498538164% 29.5760362054%,20.8570266557% 26.4004853707%,23.4834960862% 23.4834957706%,20.6107385856% 9.5491504949%,32.97535832% 16.5872557238%,36.5612054098% 14.9907346728%,40.2942917387% 13.7777826649%);background:#ff0;-webkit-clip-path:var(--poly);clip-path:var(--poly);transform:translate(calc(var(--i)*(100% + .06em))) scale(calc(1 - var(--i)*.8));transform-origin:20% 20%}#darkTheme+label:after{background:radial-gradient(circle at 19% 19%,transparent 41%,#fff 43%);border-radius:50%;grid-column:2;transform:translatey(calc(var(--i)*(-130% - .15em)))}#darkTheme:checked+label{--i:1}.check-box-container{width:2.9em}',\"\"]);const a=s},5465:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\".tooltip{cursor:help;text-decoration:underline dotted}\",\"\"]);const a=s},2420:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>p});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i),a=r(8991),l=r.n(a),c=new URL(r(5322),r.b),d=new URL(r(388),r.b),u=s()(o()),h=l()(c),b=l()(d);u.push([e.id,'/*!\\n * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)\\n * Copyright 2011-2021 The Bootstrap Authors\\n * Copyright 2011-2021 Twitter, Inc.\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\\n */:host{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-caution:#fd7e14;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41}/*!\\n * Bootstrap v5.1.0 (https://getbootstrap.com/)\\n * Copyright 2011-2021 The Bootstrap Authors\\n * Copyright 2011-2021 Twitter, Inc.\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-caution:#fd7e14;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41;--bs-font-sans-serif:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;--bs-gradient:linear-gradient(180deg,hsla(0,0%,100%,.15),hsla(0,0%,100%,0));--bs-body-font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,:after,:before{box-sizing:border-box}@media(prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}.h1,.h5,.h6,h1,h5,h6{font-weight:500;line-height:1.2;margin-bottom:.5rem;margin-top:0}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media(min-width:1200px){.h1,h1{font-size:2.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}ol,ul{margin-bottom:1rem;margin-top:0;padding-left:2rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}b{font-weight:bolder}.small,small{font-size:.875em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,pre{direction:ltr;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;unicode-bidi:bidi-override}pre{display:block;font-size:.875em;margin-bottom:1rem;margin-top:0;overflow:auto}pre code{color:inherit;font-size:inherit;word-break:normal}code{word-wrap:break-word;color:#d63384;font-size:.875em}a>code{color:inherit}img,svg{vertical-align:middle}table{border-collapse:collapse;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,th,thead,tr{border:0 solid;border-color:inherit}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button{text-transform:none}[role=button]{cursor:pointer}[type=button],button{-webkit-appearance:button}[type=button]:not(:disabled),button:not(:disabled){cursor:pointer}legend{float:left;font-size:calc(1.275rem + .3vw);line-height:inherit;margin-bottom:.5rem;padding:0;width:100%}@media(min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}summary{cursor:pointer;display:list-item}progress{vertical-align:baseline}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width:1200px){.display-4{font-size:3.5rem}}.container-fluid{margin-left:auto;margin-right:auto;padding-left:var(--bs-gutter-x,.75rem);padding-right:var(--bs-gutter-x,.75rem);width:100%}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-left:calc(var(--bs-gutter-x)*-.5);margin-right:calc(var(--bs-gutter-x)*-.5);margin-top:calc(var(--bs-gutter-y)*-1)}.row>*{flex-shrink:0;margin-top:var(--bs-gutter-y);max-width:100%;padding-left:calc(var(--bs-gutter-x)*.5);padding-right:calc(var(--bs-gutter-x)*.5);width:100%}.col{flex:1 0 0%}@media(min-width:576px){.col-sm-11{flex:0 0 auto;width:91.66666667%}}@media(min-width:768px){.col-md-12{flex:0 0 auto;width:100%}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0,0,0,.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0,0,0,.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0,0,0,.075);border-color:#dee2e6;color:#212529;margin-bottom:1rem;vertical-align:top;width:100%}.table>:not(caption)>*>*{background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg);padding:.5rem}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.form-check{display:block;margin-bottom:.125rem;min-height:1.5rem;padding-left:1.5em}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{appearance:none;background-color:#fff;background-position:50%;background-repeat:no-repeat;background-size:contain;border:1px solid rgba(0,0,0,.25);color-adjust:exact;height:1em;margin-top:.25em;vertical-align:top;width:1em}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);outline:0}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url('+h+\")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;background-image:url(\"+b+');border-color:#0d6efd}.form-check-input:disabled{filter:none;opacity:.5;pointer-events:none}.form-check-input:disabled~.form-check-label{opacity:.5}.form-check-inline{display:inline-block;margin-right:1rem}.btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;color:#212529;cursor:pointer;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;user-select:none;vertical-align:middle}@media(prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.25);outline:0}.btn:disabled{opacity:.65;pointer-events:none}.btn-secondary{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary:focus,.btn-secondary:hover{background-color:#5c636a;border-color:#565e64;color:#fff}.btn-secondary:focus{box-shadow:0 0 0 .25rem hsla(208,6%,54%,.5)}.btn-secondary.active,.btn-secondary:active{background-color:#565e64;border-color:#51585e;color:#fff}.btn-secondary.active:focus,.btn-secondary:active:focus{box-shadow:0 0 0 .25rem hsla(208,6%,54%,.5)}.btn-secondary:disabled{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-sm{border-radius:.2rem;font-size:.875rem;padding:.25rem .5rem}.nav{display:flex;flex-wrap:wrap;list-style:none;margin-bottom:0;padding-left:0}.nav-link{color:#0d6efd;display:block;padding:.5rem 1rem;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{background:none;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem;margin-bottom:-1px}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.active{background-color:#fff;border-color:#dee2e6 #dee2e6 #fff;color:#495057}.breadcrumb{display:flex;flex-wrap:wrap;list-style:none;margin-bottom:1rem;padding:0}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item:before{color:#6c757d;content:var(--bs-breadcrumb-divider,\"/\");float:left;padding-right:.5rem}.breadcrumb-item.active{color:#6c757d}.badge{border-radius:.25rem;color:#fff;display:inline-block;font-size:.75em;font-weight:700;line-height:1;padding:.35em .65em;text-align:center;vertical-align:baseline;white-space:nowrap}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{border:1px solid transparent;border-radius:.25rem;margin-bottom:1rem;padding:1rem;position:relative}.alert-danger{background-color:#f8d7da;border-color:#f5c2c7;color:#842029}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{background-color:#e9ecef;border-radius:.25rem;font-size:.75rem;height:1rem}.progress,.progress-bar{display:flex;overflow:hidden}.progress-bar{background-color:#0d6efd;color:#fff;flex-direction:column;justify-content:center;text-align:center;transition:width .6s ease;white-space:nowrap}@media(prefers-reduced-motion:reduce){.progress-bar{transition:none}}.list-group{border-radius:.25rem;display:flex;flex-direction:column;margin-bottom:0;padding-left:0}.list-group-item-action{color:#495057;text-align:inherit;width:100%}.list-group-item-action:focus,.list-group-item-action:hover{background-color:#f8f9fa;color:#495057;text-decoration:none;z-index:1}.list-group-item-action:active{background-color:#e9ecef;color:#212529}.list-group-item{background-color:#fff;border:1px solid rgba(0,0,0,.125);color:#212529;display:block;padding:.5rem 1rem;position:relative;text-decoration:none}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.list-group-item:disabled{background-color:#fff;color:#6c757d;pointer-events:none}.list-group-item.active{background-color:#0d6efd;border-color:#0d6efd;color:#fff;z-index:2}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{border-top-width:1px;margin-top:-1px}.tooltip{word-wrap:break-word;display:block;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:.875rem;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;margin:0;opacity:0;position:absolute;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;z-index:1080}@keyframes spinner-border{to{transform:rotate(1turn)}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-wave{to{mask-position:-200% 0}}.align-middle{vertical-align:middle!important}.overflow-auto{overflow:auto!important}.d-flex{display:flex!important}.border-bottom-0{border-bottom:0!important}.h-100{height:100%!important}.align-items-center{align-items:center!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.pe-4{padding-right:1.5rem!important}.fw-bold{font-weight:700!important}.text-center{text-align:center!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.rounded{border-radius:.25rem!important}:host{background-color:var(--bs-body-bg);color:var(--bs-body-color)}.bg-caution{background-color:var(--bs-caution-bg)!important}.bg-secondary{background-color:var(--bs-secondary-bg)!important}.bg-success{background-color:var(--bs-success-bg)!important}.bg-info{background-color:var(--bs-info-bg)!important}.bg-warning{background-color:var(--bs-warning-bg)!important}.bg-danger{background-color:var(--bs-danger-bg)!important}.btn,.btn:hover{color:var(--bs-body-color)}.btn:hover{text-decoration:none}.btn-secondary{color:var(--bs-btn-secondary-color)}.btn-secondary:hover{color:var(--bs-btn-secondary-hover-color)}.badge.bg-caution{color:var(--bs-badge-caution-color)}.badge.bg-secondary{color:var(--bs-badge-secondary-color)}.badge.bg-success{color:var(--bs-badge-success-color)}.badge.bg-info{color:var(--bs-badge-info-color)}.badge.bg-warning{color:var(--bs-badge-warning-color)}.badge.bg-danger{color:var(--bs-badge-danger-color)}.list-group-item{background-color:var(--bs-list-group-bg);border-color:var(--bs-list-group-border-color)}.list-group-item-action:focus,.list-group-item-action:hover{background-color:var(--bs-list-group-hover-bg);color:var(--bs-list-group-action-hover-color)}.list-group-item-action:active{background-color:var(--bs-list-group-action-active-bg);color:var(--bs-list-group-action-active-color)}.list-group-item-action{color:var(--bs-list-group-action-color)}.list-group-item.active{background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color);color:var(--bs-list-group-active-color)}a{color:var(--bs-link-color)}a:hover{color:var(--bs-link-hover-color)}.table{color:var(--bs-body-color)}.table-hover tbody tr:hover{background-color:var(--bs-table-bg-hover);color:var(--bs-body-color)}.table tbody,.table td,.table th,.table thead{border-color:var(--bs-table-border-color)}.progress{background-color:var(--bs-progress-bg)}.progress .progress-bar.bg-caution{color:var(--bs-badge-caution-color)}.progress .progress-bar.bg-secondary{color:var(--bs-badge-secondary-color)}.progress .progress-bar.bg-success{color:var(--bs-badge-success-color)}.progress .progress-bar.bg-info{color:var(--bs-badge-info-color)}.progress .progress-bar.bg-warning{color:var(--bs-badge-warning-color)}.progress .progress-bar.bg-danger{color:var(--bs-badge-danger-color)}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:var(--bs-link-color)}.nav-tabs{border-color:var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link:hover:focus{border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus{background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color);color:var(--bs-nav-tabs-link-active-color)}.breadcrumb a{color:var(--bs-link-color)}.breadcrumb{background-color:var(--bs-breadcrumb-bg);padding:.75rem 1rem}.breadcrumb-item.active,.breadcrumb-item:before{color:var(--bs-breadcrumb-active-color)}',\"\"]);const p=u},5043:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\"\",\"\"]);const a=s},6773:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>d});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i),a=r(5863),l=r(4163),c=s()(o());c.i(a.Z),c.i(l.Z),c.push([e.id,\"\",\"\"]);const d=c},4163:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,'pre[class*=\"language-\"].line-numbers {\\n\\tposition: relative;\\n\\tpadding-left: 3.8em;\\n\\tcounter-reset: linenumber;\\n}\\n\\npre[class*=\"language-\"].line-numbers > code {\\n\\tposition: relative;\\n\\twhite-space: inherit;\\n}\\n\\n.line-numbers .line-numbers-rows {\\n\\tposition: absolute;\\n\\tpointer-events: none;\\n\\ttop: 0;\\n\\tfont-size: 100%;\\n\\tleft: -3.8em;\\n\\twidth: 3em; /* works for line-numbers below 1000 lines */\\n\\tletter-spacing: -1px;\\n\\tborder-right: 1px solid #999;\\n\\n\\t-webkit-user-select: none;\\n\\t-moz-user-select: none;\\n\\t-ms-user-select: none;\\n\\tuser-select: none;\\n\\n}\\n\\n\\t.line-numbers-rows > span {\\n\\t\\tdisplay: block;\\n\\t\\tcounter-increment: linenumber;\\n\\t}\\n\\n\\t\\t.line-numbers-rows > span:before {\\n\\t\\t\\tcontent: counter(linenumber);\\n\\t\\t\\tcolor: #999;\\n\\t\\t\\tdisplay: block;\\n\\t\\t\\tpadding-right: 0.8em;\\n\\t\\t\\ttext-align: right;\\n\\t\\t}\\n',\"\"]);const a=s},5863:(e,t,r)=>{\"use strict\";r.d(t,{Z:()=>a});var n=r(9601),o=r.n(n),i=r(2609),s=r.n(i)()(o());s.push([e.id,\"/**\\n * GHColors theme by Avi Aryan (http://aviaryan.in)\\n * Inspired by Github syntax coloring\\n */\\n\\ncode[class*='language-'],\\npre[class*='language-'] {\\n  color: var(--prism-maintext);\\n  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;\\n  direction: ltr;\\n  font-size: 1em;\\n  text-align: left;\\n  white-space: pre;\\n  word-spacing: normal;\\n  word-break: normal;\\n  line-height: 1.5;\\n\\n  -moz-tab-size: 4;\\n  -o-tab-size: 4;\\n  tab-size: 4;\\n\\n  -webkit-hyphens: none;\\n  -moz-hyphens: none;\\n  -ms-hyphens: none;\\n  hyphens: none;\\n}\\n\\npre > code[class*='language-'] {\\n  font-size: 1em;\\n}\\n\\n/* Code blocks */\\npre[class*='language-'] {\\n  padding: 1em;\\n  margin: 0.5em 0;\\n  overflow: auto;\\n  border: 1px solid var(--prism-border);\\n  border-radius: 0.25rem;\\n}\\n\\n:not(pre) > code[class*='language-'],\\npre[class*='language-'] {\\n  background: var(--prism-background);\\n}\\n\\n.token.comment,\\n.token.prolog,\\n.token.doctype,\\n.token.italic,\\n.token.cdata {\\n  font-style: italic;\\n}\\n\\n.token.important,\\n.token.function,\\n.token.bold {\\n  font-weight: bold;\\n}\\n\\n.token.namespace {\\n  opacity: 0.7;\\n}\\n\\n.token.atrule {\\n  color: var(--prism-atrule);\\n}\\n.token.attr {\\n  color: var(--prism-attr);\\n}\\n.token.attr-name {\\n  color: var(--prism-attr-name);\\n}\\n.token.boolean {\\n  color: var(--prism-boolean);\\n}\\n.token.builtin {\\n  color: var(--prism-builtin);\\n}\\n.token.cdata {\\n  color: var(--prism-cdata);\\n}\\n.token.changed {\\n  color: var(--prism-changed);\\n}\\n.token.char {\\n  color: var(--prism-char);\\n}\\n.token.comment {\\n  color: var(--prism-comment);\\n}\\n.token.constant {\\n  color: var(--prism-constant);\\n}\\n.token.deleted {\\n  color: var(--prism-deleted);\\n}\\n.token.doctype {\\n  color: var(--prism-doctype);\\n}\\n.token.entity {\\n  color: var(--prism-entity);\\n}\\n.token.function {\\n  color: var(--prism-function);\\n}\\n.token.inserted {\\n  color: var(--prism-inserted);\\n}\\n.token.keyword {\\n  color: var(--prism-keyword);\\n}\\n.token.number {\\n  color: var(--prism-number);\\n}\\n.token.operator {\\n  color: var(--prism-operator);\\n}\\n.token.prolog {\\n  color: var(--prism-prolog);\\n}\\n.token.property {\\n  color: var(--prism-property);\\n}\\n.token.punctuation {\\n  color: var(--prism-punctuation);\\n}\\n.token.regex {\\n  color: var(--prism-regex);\\n}\\n.token.selector {\\n  color: var(--prism-selector);\\n}\\n.token.string {\\n  color: var(--prism-string);\\n}\\n.token.symbol {\\n  color: var(--prism-symbol);\\n}\\n.token.tag {\\n  color: var(--prism-tag);\\n}\\n.token.url {\\n  color: var(--prism-url);\\n}\\n.token.variable {\\n  color: var(--prism-variable);\\n}\\n.token.placeholder {\\n  color: var(--prism-placeholder);\\n}\\n.token.statement {\\n  color: var(--prism-statement);\\n}\\n.token.attr-value {\\n  color: var(--prism-attr-value);\\n}\\n.token.control {\\n  color: var(--prism-control);\\n}\\n.token.directive {\\n  color: var(--prism-directive);\\n}\\n.token.unit {\\n  color: var(--prism-unit);\\n}\\n.token.important {\\n  color: var(--prism-important);\\n}\\n\",\"\"]);const a=s},2609:e=>{\"use strict\";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var r=\"\",n=void 0!==t[5];return t[4]&&(r+=\"@supports (\".concat(t[4],\") {\")),t[2]&&(r+=\"@media \".concat(t[2],\" {\")),n&&(r+=\"@layer\".concat(t[5].length>0?\" \".concat(t[5]):\"\",\" {\")),r+=e(t),n&&(r+=\"}\"),t[2]&&(r+=\"}\"),t[4]&&(r+=\"}\"),r})).join(\"\")},t.i=function(e,r,n,o,i){\"string\"==typeof e&&(e=[[null,e,void 0]]);var s={};if(n)for(var a=0;a<this.length;a++){var l=this[a][0];null!=l&&(s[l]=!0)}for(var c=0;c<e.length;c++){var d=[].concat(e[c]);n&&s[d[0]]||(void 0!==i&&(void 0===d[5]||(d[1]=\"@layer\".concat(d[5].length>0?\" \".concat(d[5]):\"\",\" {\").concat(d[1],\"}\")),d[5]=i),r&&(d[2]?(d[1]=\"@media \".concat(d[2],\" {\").concat(d[1],\"}\"),d[2]=r):d[2]=r),o&&(d[4]?(d[1]=\"@supports (\".concat(d[4],\") {\").concat(d[1],\"}\"),d[4]=o):d[4]=\"\".concat(o)),t.push(d))}},t}},8991:e=>{\"use strict\";e.exports=function(e,t){return t||(t={}),e?(e=String(e.__esModule?e.default:e),/^['\"].*['\"]$/.test(e)&&(e=e.slice(1,-1)),t.hash&&(e+=t.hash),/[\"'() \\t\\n]|(%20)/.test(e)||t.needQuotes?'\"'.concat(e.replace(/\"/g,'\\\\\"').replace(/\\n/g,\"\\\\n\"),'\"'):e):e}},9601:e=>{\"use strict\";e.exports=function(e){return e[1]}},5433:()=>{Prism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/(\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,boolean:/\\b(?:true|false)\\b/,function:/\\b\\w+(?=\\()/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/,punctuation:/[{}[\\];(),.:]/}},8325:(e,t,r)=>{var n=function(e){var t=/\\blang(?:uage)?-([\\w-]+)\\b/i,r=0,n={},o={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof i?new i(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++r}),e.__id},clone:function e(t,r){var n,i;switch(r=r||{},o.util.type(t)){case\"Object\":if(i=o.util.objId(t),r[i])return r[i];for(var s in n={},r[i]=n,t)t.hasOwnProperty(s)&&(n[s]=e(t[s],r));return n;case\"Array\":return i=o.util.objId(t),r[i]?r[i]:(n=[],r[i]=n,t.forEach((function(t,o){n[o]=e(t,r)})),n);default:return t}},getLanguage:function(e){for(;e&&!t.test(e.className);)e=e.parentElement;return e?(e.className.match(t)||[,\"none\"])[1].toLowerCase():\"none\"},currentScript:function(){if(\"undefined\"==typeof document)return null;if(\"currentScript\"in document)return document.currentScript;try{throw new Error}catch(n){var e=(/at [^(\\r\\n]*\\((.*):[^:]+:[^:]+\\)$/i.exec(n.stack)||[])[1];if(e){var t=document.getElementsByTagName(\"script\");for(var r in t)if(t[r].src==e)return t[r]}return null}},isActive:function(e,t,r){for(var n=\"no-\"+t;e;){var o=e.classList;if(o.contains(t))return!0;if(o.contains(n))return!1;e=e.parentElement}return!!r}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var r=o.util.clone(o.languages[e]);for(var n in t)r[n]=t[n];return r},insertBefore:function(e,t,r,n){var i=(n=n||o.languages)[e],s={};for(var a in i)if(i.hasOwnProperty(a)){if(a==t)for(var l in r)r.hasOwnProperty(l)&&(s[l]=r[l]);r.hasOwnProperty(a)||(s[a]=i[a])}var c=n[e];return n[e]=s,o.languages.DFS(o.languages,(function(t,r){r===c&&t!=e&&(this[t]=s)})),s},DFS:function e(t,r,n,i){i=i||{};var s=o.util.objId;for(var a in t)if(t.hasOwnProperty(a)){r.call(t,a,t[a],n||a);var l=t[a],c=o.util.type(l);\"Object\"!==c||i[s(l)]?\"Array\"!==c||i[s(l)]||(i[s(l)]=!0,e(l,r,a,i)):(i[s(l)]=!0,e(l,r,null,i))}}},plugins:{},highlightAll:function(e,t){o.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,r){var n={callback:r,container:e,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};o.hooks.run(\"before-highlightall\",n),n.elements=Array.prototype.slice.apply(n.container.querySelectorAll(n.selector)),o.hooks.run(\"before-all-elements-highlight\",n);for(var i,s=0;i=n.elements[s++];)o.highlightElement(i,!0===t,n.callback)},highlightElement:function(r,n,i){var s=o.util.getLanguage(r),a=o.languages[s];r.className=r.className.replace(t,\"\").replace(/\\s+/g,\" \")+\" language-\"+s;var l=r.parentElement;l&&\"pre\"===l.nodeName.toLowerCase()&&(l.className=l.className.replace(t,\"\").replace(/\\s+/g,\" \")+\" language-\"+s);var c={element:r,language:s,grammar:a,code:r.textContent};function d(e){c.highlightedCode=e,o.hooks.run(\"before-insert\",c),c.element.innerHTML=c.highlightedCode,o.hooks.run(\"after-highlight\",c),o.hooks.run(\"complete\",c),i&&i.call(c.element)}if(o.hooks.run(\"before-sanity-check\",c),(l=c.element.parentElement)&&\"pre\"===l.nodeName.toLowerCase()&&!l.hasAttribute(\"tabindex\")&&l.setAttribute(\"tabindex\",\"0\"),!c.code)return o.hooks.run(\"complete\",c),void(i&&i.call(c.element));if(o.hooks.run(\"before-highlight\",c),c.grammar)if(n&&e.Worker){var u=new Worker(o.filename);u.onmessage=function(e){d(e.data)},u.postMessage(JSON.stringify({language:c.language,code:c.code,immediateClose:!0}))}else d(o.highlight(c.code,c.grammar,c.language));else d(o.util.encode(c.code))},highlight:function(e,t,r){var n={code:e,grammar:t,language:r};return o.hooks.run(\"before-tokenize\",n),n.tokens=o.tokenize(n.code,n.grammar),o.hooks.run(\"after-tokenize\",n),i.stringify(o.util.encode(n.tokens),n.language)},tokenize:function(e,t){var r=t.rest;if(r){for(var n in r)t[n]=r[n];delete t.rest}var o=new l;return c(o,o.head,e),a(e,o,t,o.head,0),function(e){for(var t=[],r=e.head.next;r!==e.tail;)t.push(r.value),r=r.next;return t}(o)},hooks:{all:{},add:function(e,t){var r=o.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=o.hooks.all[e];if(r&&r.length)for(var n,i=0;n=r[i++];)n(t)}},Token:i};function i(e,t,r,n){this.type=e,this.content=t,this.alias=r,this.length=0|(n||\"\").length}function s(e,t,r,n){e.lastIndex=t;var o=e.exec(r);if(o&&n&&o[1]){var i=o[1].length;o.index+=i,o[0]=o[0].slice(i)}return o}function a(e,t,r,n,l,u){for(var h in r)if(r.hasOwnProperty(h)&&r[h]){var b=r[h];b=Array.isArray(b)?b:[b];for(var p=0;p<b.length;++p){if(u&&u.cause==h+\",\"+p)return;var g=b[p],f=g.inside,m=!!g.lookbehind,v=!!g.greedy,y=g.alias;if(v&&!g.pattern.global){var w=g.pattern.toString().match(/[imsuy]*$/)[0];g.pattern=RegExp(g.pattern.source,w+\"g\")}for(var k=g.pattern||g,$=n.next,x=l;$!==t.tail&&!(u&&x>=u.reach);x+=$.value.length,$=$.next){var S=$.value;if(t.length>e.length)return;if(!(S instanceof i)){var A,_=1;if(v){if(!(A=s(k,x,e,m)))break;var M=A.index,C=A.index+A[0].length,E=x;for(E+=$.value.length;M>=E;)E+=($=$.next).value.length;if(x=E-=$.value.length,$.value instanceof i)continue;for(var T=$;T!==t.tail&&(E<C||\"string\"==typeof T.value);T=T.next)_++,E+=T.value.length;_--,S=e.slice(x,E),A.index-=x}else if(!(A=s(k,0,S,m)))continue;M=A.index;var P=A[0],z=S.slice(0,M),j=S.slice(M+P.length),F=x+S.length;u&&F>u.reach&&(u.reach=F);var N=$.prev;if(z&&(N=c(t,N,z),x+=z.length),d(t,N,_),$=c(t,N,new i(h,f?o.tokenize(P,f):P,y,P)),j&&c(t,$,j),_>1){var O={cause:h+\",\"+p,reach:F};a(e,t,r,$.prev,x,O),u&&O.reach>u.reach&&(u.reach=O.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,r){var n=t.next,o={value:r,prev:t,next:n};return t.next=o,n.prev=o,e.length++,o}function d(e,t,r){for(var n=t.next,o=0;o<r&&n!==e.tail;o++)n=n.next;t.next=n,n.prev=t,e.length-=o}if(e.Prism=o,i.stringify=function e(t,r){if(\"string\"==typeof t)return t;if(Array.isArray(t)){var n=\"\";return t.forEach((function(t){n+=e(t,r)})),n}var i={type:t.type,content:e(t.content,r),tag:\"span\",classes:[\"token\",t.type],attributes:{},language:r},s=t.alias;s&&(Array.isArray(s)?Array.prototype.push.apply(i.classes,s):i.classes.push(s)),o.hooks.run(\"wrap\",i);var a=\"\";for(var l in i.attributes)a+=\" \"+l+'=\"'+(i.attributes[l]||\"\").replace(/\"/g,\"&quot;\")+'\"';return\"<\"+i.tag+' class=\"'+i.classes.join(\" \")+'\"'+a+\">\"+i.content+\"</\"+i.tag+\">\"},!e.document)return e.addEventListener?(o.disableWorkerMessageHandler||e.addEventListener(\"message\",(function(t){var r=JSON.parse(t.data),n=r.language,i=r.code,s=r.immediateClose;e.postMessage(o.highlight(i,o.languages[n],n)),s&&e.close()}),!1),o):o;var u=o.util.currentScript();function h(){o.manual||o.highlightAll()}if(u&&(o.filename=u.src,u.hasAttribute(\"data-manual\")&&(o.manual=!0)),!o.manual){var b=document.readyState;\"loading\"===b||\"interactive\"===b&&u&&u.defer?document.addEventListener(\"DOMContentLoaded\",h):window.requestAnimationFrame?window.requestAnimationFrame(h):window.setTimeout(h,16)}return o}(\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=n),void 0!==r.g&&(r.g.Prism=n)},9016:()=>{!function(e){function t(e,t){return e.replace(/<<(\\d+)>>/g,(function(e,r){return\"(?:\"+t[+r]+\")\"}))}function r(e,r,n){return RegExp(t(e,r),n||\"\")}function n(e,t){for(var r=0;r<t;r++)e=e.replace(/<<self>>/g,(function(){return\"(?:\"+e+\")\"}));return e.replace(/<<self>>/g,\"[^\\\\s\\\\S]\")}var o=\"bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void\",i=\"class enum interface record struct\",s=\"add alias and ascending async await by descending from(?=\\\\s*(?:\\\\w|$)) get global group into init(?=\\\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\\\s*{)\",a=\"abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield\";function l(e){return\"\\\\b(?:\"+e.trim().replace(/ /g,\"|\")+\")\\\\b\"}var c=l(i),d=RegExp(l(o+\" \"+i+\" \"+s+\" \"+a)),u=l(i+\" \"+s+\" \"+a),h=l(o+\" \"+i+\" \"+a),b=n(/<(?:[^<>;=+\\-*/%&|^]|<<self>>)*>/.source,2),p=n(/\\((?:[^()]|<<self>>)*\\)/.source,2),g=/@?\\b[A-Za-z_]\\w*\\b/.source,f=t(/<<0>>(?:\\s*<<1>>)?/.source,[g,b]),m=t(/(?!<<0>>)<<1>>(?:\\s*\\.\\s*<<1>>)*/.source,[u,f]),v=/\\[\\s*(?:,\\s*)*\\]/.source,y=t(/<<0>>(?:\\s*(?:\\?\\s*)?<<1>>)*(?:\\s*\\?)?/.source,[m,v]),w=t(/[^,()<>[\\];=+\\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[b,p,v]),k=t(/\\(<<0>>+(?:,<<0>>+)+\\)/.source,[w]),$=t(/(?:<<0>>|<<1>>)(?:\\s*(?:\\?\\s*)?<<2>>)*(?:\\s*\\?)?/.source,[k,m,v]),x={keyword:d,punctuation:/[<>()?,.:[\\]]/},S=/'(?:[^\\r\\n'\\\\]|\\\\.|\\\\[Uux][\\da-fA-F]{1,8})'/.source,A=/\"(?:\\\\.|[^\\\\\"\\r\\n])*\"/.source,_=/@\"(?:\"\"|\\\\[\\s\\S]|[^\\\\\"])*\"(?!\")/.source;e.languages.csharp=e.languages.extend(\"clike\",{string:[{pattern:r(/(^|[^$\\\\])<<0>>/.source,[_]),lookbehind:!0,greedy:!0},{pattern:r(/(^|[^@$\\\\])<<0>>/.source,[A]),lookbehind:!0,greedy:!0},{pattern:RegExp(S),greedy:!0,alias:\"character\"}],\"class-name\":[{pattern:r(/(\\busing\\s+static\\s+)<<0>>(?=\\s*;)/.source,[m]),lookbehind:!0,inside:x},{pattern:r(/(\\busing\\s+<<0>>\\s*=\\s*)<<1>>(?=\\s*;)/.source,[g,$]),lookbehind:!0,inside:x},{pattern:r(/(\\busing\\s+)<<0>>(?=\\s*=)/.source,[g]),lookbehind:!0},{pattern:r(/(\\b<<0>>\\s+)<<1>>/.source,[c,f]),lookbehind:!0,inside:x},{pattern:r(/(\\bcatch\\s*\\(\\s*)<<0>>/.source,[m]),lookbehind:!0,inside:x},{pattern:r(/(\\bwhere\\s+)<<0>>/.source,[g]),lookbehind:!0},{pattern:r(/(\\b(?:is(?:\\s+not)?|as)\\s+)<<0>>/.source,[y]),lookbehind:!0,inside:x},{pattern:r(/\\b<<0>>(?=\\s+(?!<<1>>|with\\s*\\{)<<2>>(?:\\s*[=,;:{)\\]]|\\s+(?:in|when)\\b))/.source,[$,h,g]),inside:x}],keyword:d,number:/(?:\\b0(?:x[\\da-f_]*[\\da-f]|b[01_]*[01])|(?:\\B\\.\\d+(?:_+\\d+)*|\\b\\d+(?:_+\\d+)*(?:\\.\\d+(?:_+\\d+)*)?)(?:e[-+]?\\d+(?:_+\\d+)*)?)(?:ul|lu|[dflmu])?\\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\\1|~|\\?\\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\\?\\.?|::|[{}[\\];(),.:]/}),e.languages.insertBefore(\"csharp\",\"number\",{range:{pattern:/\\.\\./,alias:\"operator\"}}),e.languages.insertBefore(\"csharp\",\"punctuation\",{\"named-parameter\":{pattern:r(/([(,]\\s*)<<0>>(?=\\s*:)/.source,[g]),lookbehind:!0,alias:\"punctuation\"}}),e.languages.insertBefore(\"csharp\",\"class-name\",{namespace:{pattern:r(/(\\b(?:namespace|using)\\s+)<<0>>(?:\\s*\\.\\s*<<0>>)*(?=\\s*[;{])/.source,[g]),lookbehind:!0,inside:{punctuation:/\\./}},\"type-expression\":{pattern:r(/(\\b(?:default|typeof|sizeof)\\s*\\(\\s*(?!\\s))(?:[^()\\s]|\\s(?!\\s)|<<0>>)*(?=\\s*\\))/.source,[p]),lookbehind:!0,alias:\"class-name\",inside:x},\"return-type\":{pattern:r(/<<0>>(?=\\s+(?:<<1>>\\s*(?:=>|[({]|\\.\\s*this\\s*\\[)|this\\s*\\[))/.source,[$,m]),inside:x,alias:\"class-name\"},\"constructor-invocation\":{pattern:r(/(\\bnew\\s+)<<0>>(?=\\s*[[({])/.source,[$]),lookbehind:!0,inside:x,alias:\"class-name\"},\"generic-method\":{pattern:r(/<<0>>\\s*<<1>>(?=\\s*\\()/.source,[g,b]),inside:{function:r(/^<<0>>/.source,[g]),generic:{pattern:RegExp(b),alias:\"class-name\",inside:x}}},\"type-list\":{pattern:r(/\\b((?:<<0>>\\s+<<1>>|record\\s+<<1>>\\s*<<5>>|where\\s+<<2>>)\\s*:\\s*)(?:<<3>>|<<4>>|<<1>>\\s*<<5>>|<<6>>)(?:\\s*,\\s*(?:<<3>>|<<4>>|<<6>>))*(?=\\s*(?:where|[{;]|=>|$))/.source,[c,f,g,$,d.source,p,/\\bnew\\s*\\(\\s*\\)/.source]),lookbehind:!0,inside:{\"record-arguments\":{pattern:r(/(^(?!new\\s*\\()<<0>>\\s*)<<1>>/.source,[f,p]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:d,\"class-name\":{pattern:RegExp($),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\\t ]*)#.*/m,lookbehind:!0,alias:\"property\",inside:{directive:{pattern:/(#)\\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\\b/,lookbehind:!0,alias:\"keyword\"}}}});var M=A+\"|\"+S,C=t(/\\/(?![*/])|\\/\\/[^\\r\\n]*[\\r\\n]|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|<<0>>/.source,[M]),E=n(t(/[^\"'/()]|<<0>>|\\(<<self>>*\\)/.source,[C]),2),T=/\\b(?:assembly|event|field|method|module|param|property|return|type)\\b/.source,P=t(/<<0>>(?:\\s*\\(<<1>>*\\))?/.source,[m,E]);e.languages.insertBefore(\"csharp\",\"class-name\",{attribute:{pattern:r(/((?:^|[^\\s\\w>)?])\\s*\\[\\s*)(?:<<0>>\\s*:\\s*)?<<1>>(?:\\s*,\\s*<<1>>)*(?=\\s*\\])/.source,[T,P]),lookbehind:!0,greedy:!0,inside:{target:{pattern:r(/^<<0>>(?=\\s*:)/.source,[T]),alias:\"keyword\"},\"attribute-arguments\":{pattern:r(/\\(<<0>>*\\)/.source,[E]),inside:e.languages.csharp},\"class-name\":{pattern:RegExp(m),inside:{punctuation:/\\./}},punctuation:/[:,]/}}});var z=/:[^}\\r\\n]+/.source,j=n(t(/[^\"'/()]|<<0>>|\\(<<self>>*\\)/.source,[C]),2),F=t(/\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}/.source,[j,z]),N=n(t(/[^\"'/()]|\\/(?!\\*)|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|<<0>>|\\(<<self>>*\\)/.source,[M]),2),O=t(/\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}/.source,[N,z]);function R(t,n){return{interpolation:{pattern:r(/((?:^|[^{])(?:\\{\\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{\"format-string\":{pattern:r(/(^\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\}$)/.source,[n,z]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\\{|\\}$/,expression:{pattern:/[\\s\\S]+/,alias:\"language-csharp\",inside:e.languages.csharp}}},string:/[\\s\\S]+/}}e.languages.insertBefore(\"csharp\",\"string\",{\"interpolation-string\":[{pattern:r(/(^|[^\\\\])(?:\\$@|@\\$)\"(?:\"\"|\\\\[\\s\\S]|\\{\\{|<<0>>|[^\\\\{\"])*\"/.source,[F]),lookbehind:!0,greedy:!0,inside:R(F,j)},{pattern:r(/(^|[^@\\\\])\\$\"(?:\\\\.|\\{\\{|<<0>>|[^\\\\\"{])*\"/.source,[O]),lookbehind:!0,greedy:!0,inside:R(O,N)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp},9472:()=>{!function(e){var t=/(?:\\r?\\n|\\r)[ \\t]*\\|.+\\|(?:(?!\\|).)*/.source;e.languages.gherkin={pystring:{pattern:/(\"\"\"|''')[\\s\\S]+?\\1/,alias:\"string\"},comment:{pattern:/(^[ \\t]*)#.*/m,lookbehind:!0},tag:{pattern:/(^[ \\t]*)@\\S*/m,lookbehind:!0},feature:{pattern:/((?:^|\\r?\\n|\\r)[ \\t]*)(?:Ability|Ahoy matey!|Arwedd|Aspekt|Besigheid Behoefte|Business Need|Caracteristica|Característica|Egenskab|Egenskap|Eiginleiki|Feature|Fīča|Fitur|Fonctionnalité|Fonksyonalite|Funcionalidade|Funcionalitat|Functionalitate|Funcţionalitate|Funcționalitate|Functionaliteit|Fungsi|Funkcia|Funkcija|Funkcionalitāte|Funkcionalnost|Funkcja|Funksie|Funktionalität|Funktionalitéit|Funzionalità|Hwaet|Hwæt|Jellemző|Karakteristik|laH|Lastnost|Mak|Mogucnost|Mogućnost|Moznosti|Možnosti|OH HAI|Omadus|Ominaisuus|Osobina|Özellik|perbogh|poQbogh malja'|Potrzeba biznesowa|Požadavek|Požiadavka|Pretty much|Qap|Qu'meH 'ut|Savybė|Tính năng|Trajto|Vermoë|Vlastnosť|Właściwość|Značilnost|Δυνατότητα|Λειτουργία|Могућност|Мөмкинлек|Особина|Свойство|Үзенчәлеклелек|Функционал|Функционалност|Функция|Функціонал|תכונה|خاصية|خصوصیت|صلاحیت|کاروبار کی ضرورت|وِیژگی|रूप लेख|ਖਾਸੀਅਤ|ਨਕਸ਼ ਨੁਹਾਰ|ਮੁਹਾਂਦਰਾ|గుణము|ಹೆಚ್ಚಳ|ความต้องการทางธุรกิจ|ความสามารถ|โครงหลัก|기능|フィーチャ|功能|機能):(?:[^:\\r\\n]+(?:\\r?\\n|\\r|$))*/,lookbehind:!0,inside:{important:{pattern:/(:)[^\\r\\n]+/,lookbehind:!0},keyword:/[^:\\r\\n]+:/}},scenario:{pattern:/(^[ \\t]*)(?:Abstract Scenario|Abstrakt Scenario|Achtergrond|Aer|Ær|Agtergrond|All y'all|Antecedentes|Antecedents|Atburðarás|Atburðarásir|Awww, look mate|B4|Background|Baggrund|Bakgrund|Bakgrunn|Bakgrunnur|Beispiele|Beispiller|Bối cảnh|Cefndir|Cenario|Cenário|Cenario de Fundo|Cenário de Fundo|Cenarios|Cenários|Contesto|Context|Contexte|Contexto|Conto|Contoh|Contone|Dæmi|Dasar|Dead men tell no tales|Delineacao do Cenario|Delineação do Cenário|Dis is what went down|Dữ liệu|Dyagram senaryo|Dyagram Senaryo|Egzanp|Ejemplos|Eksempler|Ekzemploj|Enghreifftiau|Esbozo do escenario|Escenari|Escenario|Esempi|Esquema de l'escenari|Esquema del escenario|Esquema do Cenario|Esquema do Cenário|Examples|EXAMPLZ|Exempel|Exemple|Exemples|Exemplos|First off|Fono|Forgatókönyv|Forgatókönyv vázlat|Fundo|Geçmiş|ghantoH|Grundlage|Hannergrond|Háttér|Heave to|Istorik|Juhtumid|Keadaan|Khung kịch bản|Khung tình huống|Kịch bản|Koncept|Konsep skenario|Kontèks|Kontekst|Kontekstas|Konteksts|Kontext|Konturo de la scenaro|Latar Belakang|lut|lut chovnatlh|lutmey|Lýsing Atburðarásar|Lýsing Dæma|Menggariskan Senario|MISHUN|MISHUN SRSLY|mo'|Náčrt Scenára|Náčrt Scénáře|Náčrt Scenáru|Oris scenarija|Örnekler|Osnova|Osnova Scenára|Osnova scénáře|Osnutek|Ozadje|Paraugs|Pavyzdžiai|Példák|Piemēri|Plan du scénario|Plan du Scénario|Plan senaryo|Plan Senaryo|Plang vum Szenario|Pozadí|Pozadie|Pozadina|Príklady|Příklady|Primer|Primeri|Primjeri|Przykłady|Raamstsenaarium|Reckon it's like|Rerefons|Scenár|Scénář|Scenarie|Scenarij|Scenarijai|Scenarijaus šablonas|Scenariji|Scenārijs|Scenārijs pēc parauga|Scenarijus|Scenario|Scénario|Scenario Amlinellol|Scenario Outline|Scenario Template|Scenariomal|Scenariomall|Scenarios|Scenariu|Scenariusz|Scenaro|Schema dello scenario|Se ðe|Se the|Se þe|Senario|Senaryo|Senaryo deskripsyon|Senaryo Deskripsyon|Senaryo taslağı|Shiver me timbers|Situācija|Situai|Situasie|Situasie Uiteensetting|Skenario|Skenario konsep|Skica|Structura scenariu|Structură scenariu|Struktura scenarija|Stsenaarium|Swa|Swa hwaer swa|Swa hwær swa|Szablon scenariusza|Szenario|Szenariogrundriss|Tapaukset|Tapaus|Tapausaihio|Taust|Tausta|Template Keadaan|Template Senario|Template Situai|The thing of it is|Tình huống|Variantai|Voorbeelde|Voorbeelden|Wharrimean is|Yo-ho-ho|You'll wanna|Założenia|Παραδείγματα|Περιγραφή Σεναρίου|Σενάρια|Σενάριο|Υπόβαθρο|Кереш|Контекст|Концепт|Мисаллар|Мисоллар|Основа|Передумова|Позадина|Предистория|Предыстория|Приклади|Пример|Примери|Примеры|Рамка на сценарий|Скица|Структура сценарија|Структура сценария|Структура сценарію|Сценарий|Сценарий структураси|Сценарийның төзелеше|Сценарији|Сценарио|Сценарій|Тарих|Үрнәкләр|דוגמאות|רקע|תבנית תרחיש|תרחיש|الخلفية|الگوی سناریو|امثلة|پس منظر|زمینه|سناریو|سيناريو|سيناريو مخطط|مثالیں|منظر نامے کا خاکہ|منظرنامہ|نمونه ها|उदाहरण|परिदृश्य|परिदृश्य रूपरेखा|पृष्ठभूमि|ਉਦਾਹਰਨਾਂ|ਪਟਕਥਾ|ਪਟਕਥਾ ਢਾਂਚਾ|ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਿਛੋਕੜ|ఉదాహరణలు|కథనం|నేపథ్యం|సన్నివేశం|ಉದಾಹರಣೆಗಳು|ಕಥಾಸಾರಾಂಶ|ವಿವರಣೆ|ಹಿನ್ನೆಲೆ|โครงสร้างของเหตุการณ์|ชุดของตัวอย่าง|ชุดของเหตุการณ์|แนวคิด|สรุปเหตุการณ์|เหตุการณ์|배경|시나리오|시나리오 개요|예|サンプル|シナリオ|シナリオアウトライン|シナリオテンプレ|シナリオテンプレート|テンプレ|例|例子|剧本|剧本大纲|劇本|劇本大綱|场景|场景大纲|場景|場景大綱|背景):[^:\\r\\n]*/m,lookbehind:!0,inside:{important:{pattern:/(:)[^\\r\\n]*/,lookbehind:!0},keyword:/[^:\\r\\n]+:/}},\"table-body\":{pattern:RegExp(\"(\"+t+\")(?:\"+t+\")+\"),lookbehind:!0,inside:{outline:{pattern:/<[^>]+>/,alias:\"variable\"},td:{pattern:/\\s*[^\\s|][^|]*/,alias:\"string\"},punctuation:/\\|/}},\"table-head\":{pattern:RegExp(t),inside:{th:{pattern:/\\s*[^\\s|][^|]*/,alias:\"variable\"},punctuation:/\\|/}},atrule:{pattern:/(^[ \\t]+)(?:'ach|'a|'ej|7|a|A také|A taktiež|A tiež|A zároveň|Aber|Ac|Adott|Akkor|Ak|Aleshores|Ale|Ali|Allora|Alors|Als|Ama|Amennyiben|Amikor|Ampak|an|AN|Ananging|And y'all|And|Angenommen|Anrhegedig a|An|Apabila|Atès|Atesa|Atunci|Avast!|Aye|A|awer|Bagi|Banjur|Bet|Biết|Blimey!|Buh|But at the end of the day I reckon|But y'all|But|BUT|Cal|Când|Cando|Cand|Ce|Cuando|Če|Ða ðe|Ða|Dadas|Dada|Dados|Dado|DaH ghu' bejlu'|dann|Dann|Dano|Dan|Dar|Dat fiind|Data|Date fiind|Date|Dati fiind|Dati|Daţi fiind|Dați fiind|Dato|DEN|Den youse gotta|Dengan|De|Diberi|Diyelim ki|Donada|Donat|Donitaĵo|Do|Dun|Duota|Ðurh|Eeldades|Ef|Eğer ki|Entao|Então|Entón|Entonces|En|Epi|E|És|Etant donnée|Etant donné|Et|Étant données|Étant donnée|Étant donné|Etant données|Etant donnés|Étant donnés|Fakat|Gangway!|Gdy|Gegeben seien|Gegeben sei|Gegeven|Gegewe|ghu' noblu'|Gitt|Given y'all|Given|Givet|Givun|Ha|Cho|I CAN HAZ|In|Ir|It's just unbelievable|I|Ja|Jeśli|Jeżeli|Kadar|Kada|Kad|Kai|Kaj|Když|Keď|Kemudian|Ketika|Khi|Kiedy|Ko|Kuid|Kui|Kun|Lan|latlh|Le sa a|Let go and haul|Le|Lè sa a|Lè|Logo|Lorsqu'<|Lorsque|mä|Maar|Mais|Mając|Majd|Maka|Manawa|Mas|Ma|Menawa|Men|Mutta|Nalikaning|Nalika|Nanging|Når|När|Nato|Nhưng|Niin|Njuk|O zaman|Og|Och|Oletetaan|Onda|Ond|Oraz|Pak|Pero|Però|Podano|Pokiaľ|Pokud|Potem|Potom|Privzeto|Pryd|qaSDI'|Quando|Quand|Quan|Så|Sed|Se|Siis|Sipoze ke|Sipoze Ke|Sipoze|Si|Şi|Și|Soit|Stel|Tada|Tad|Takrat|Tak|Tapi|Ter|Tetapi|Tha the|Tha|Then y'all|Then|Thì|Thurh|Toda|Too right|ugeholl|Und|Un|Và|vaj|Vendar|Ve|wann|Wanneer|WEN|Wenn|When y'all|When|Wtedy|Wun|Y'know|Yeah nah|Yna|Youse know like when|Youse know when youse got|Y|Za predpokladu|Za předpokladu|Zadani|Zadano|Zadan|Zadate|Zadato|Zakładając|Zaradi|Zatati|Þa þe|Þa|Þá|Þegar|Þurh|Αλλά|Δεδομένου|Και|Όταν|Τότε|А також|Агар|Але|Али|Аммо|А|Әгәр|Әйтик|Әмма|Бирок|Ва|Вә|Дадено|Дано|Допустим|Если|Задате|Задати|Задато|И|І|К тому же|Када|Кад|Когато|Когда|Коли|Ләкин|Лекин|Нәтиҗәдә|Нехай|Но|Онда|Припустимо, що|Припустимо|Пусть|Также|Та|Тогда|Тоді|То|Унда|Һәм|Якщо|אבל|אזי|אז|בהינתן|וגם|כאשר|آنگاه|اذاً|اگر|اما|اور|با فرض|بالفرض|بفرض|پھر|تب|ثم|جب|عندما|فرض کیا|لكن|لیکن|متى|هنگامی|و|अगर|और|कदा|किन्तु|चूंकि|जब|तथा|तदा|तब|परन्तु|पर|यदि|ਅਤੇ|ਜਦੋਂ|ਜਿਵੇਂ ਕਿ|ਜੇਕਰ|ਤਦ|ਪਰ|అప్పుడు|ఈ పరిస్థితిలో|కాని|చెప్పబడినది|మరియు|ಆದರೆ|ನಂತರ|ನೀಡಿದ|ಮತ್ತು|ಸ್ಥಿತಿಯನ್ನು|กำหนดให้|ดังนั้น|แต่|เมื่อ|และ|그러면<|그리고<|단<|만약<|만일<|먼저<|조건<|하지만<|かつ<|しかし<|ただし<|ならば<|もし<|並且<|但し<|但是<|假如<|假定<|假設<|假设<|前提<|同时<|同時<|并且<|当<|當<|而且<|那么<|那麼<)(?=[ \\t])/m,lookbehind:!0},string:{pattern:/\"(?:\\\\.|[^\"\\\\\\r\\n])*\"|'(?:\\\\.|[^'\\\\\\r\\n])*'/,inside:{outline:{pattern:/<[^>]+>/,alias:\"variable\"}}},outline:{pattern:/<[^>]+>/,alias:\"variable\"}}}(Prism)},2503:()=>{!function(e){var t=/\\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\\b/,r=/(^|[^\\w.])(?:[a-z]\\w*\\s*\\.\\s*)*(?:[A-Z]\\w*\\s*\\.\\s*)*/.source,n={pattern:RegExp(r+/[A-Z](?:[\\d_A-Z]*[a-z]\\w*)?\\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\\w*(?:\\s*\\.\\s*[a-z]\\w*)*(?:\\s*\\.)?/,inside:{punctuation:/\\./}},punctuation:/\\./}};e.languages.java=e.languages.extend(\"clike\",{\"class-name\":[n,{pattern:RegExp(r+/[A-Z]\\w*(?=\\s+\\w+\\s*[;,=()])/.source),lookbehind:!0,inside:n.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\\s*)[a-z_]\\w*/,lookbehind:!0}],number:/\\b0b[01][01_]*L?\\b|\\b0x(?:\\.[\\da-f_p+-]+|[\\da-f_]+(?:\\.[\\da-f_p+-]+)?)\\b|(?:\\b\\d[\\d_]*(?:\\.[\\d_]*)?|\\B\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\\+\\+|&&|\\|\\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore(\"java\",\"string\",{\"triple-quoted-string\":{pattern:/\"\"\"[ \\t]*[\\r\\n](?:(?:\"|\"\")?(?:\\\\.|[^\"\\\\]))*\"\"\"/,greedy:!0,alias:\"string\"}}),e.languages.insertBefore(\"java\",\"class-name\",{annotation:{pattern:/(^|[^.])@\\w+(?:\\s*\\.\\s*\\w+)*/,lookbehind:!0,alias:\"punctuation\"},generics:{pattern:/<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{\"class-name\":n,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!<keyword>)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\\./}}})}(Prism)},9980:()=>{Prism.languages.javascript=Prism.languages.extend(\"clike\",{\"class-name\":[Prism.languages.clike[\"class-name\"],{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$A-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\\})\\s*)catch\\b/,lookbehind:!0},{pattern:/(^|[^.]|\\.\\.\\.\\s*)\\b(?:as|assert(?=\\s*\\{)|async(?=\\s*(?:function\\b|\\(|[$\\w\\xA0-\\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\\s*(?:\\{|$))|for|from(?=\\s*(?:['\"]|$))|function|(?:get|set)(?=\\s*(?:[#\\[$\\w\\xA0-\\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\\b/,lookbehind:!0}],function:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,number:/\\b(?:(?:0[xX](?:[\\dA-Fa-f](?:_[\\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\\d(?:_\\d)?)+n|NaN|Infinity)\\b|(?:\\b(?:\\d(?:_\\d)?)+\\.?(?:\\d(?:_\\d)?)*|\\B\\.(?:\\d(?:_\\d)?)+)(?:[Ee][+-]?(?:\\d(?:_\\d)?)+)?/,operator:/--|\\+\\+|\\*\\*=?|=>|&&=?|\\|\\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\\.{3}|\\?\\?=?|\\?\\.?|[~:]/}),Prism.languages.javascript[\"class-name\"][0].pattern=/(\\b(?:class|interface|extends|implements|instanceof|new)\\s+)[\\w.\\\\]+/,Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:/((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)\\/(?:\\[(?:[^\\]\\\\\\r\\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\\r\\n])+\\/[dgimyus]{0,7}(?=(?:\\s|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*(?:$|[\\r\\n,.;:})\\]]|\\/\\/))/,lookbehind:!0,greedy:!0,inside:{\"regex-source\":{pattern:/^(\\/)[\\s\\S]+(?=\\/[a-z]*$)/,lookbehind:!0,alias:\"language-regex\",inside:Prism.languages.regex},\"regex-delimiter\":/^\\/|\\/$/,\"regex-flags\":/^[a-z]+$/}},\"function-variable\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*[=:]\\s*(?:async\\s*)?(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/,alias:\"function\"},parameter:[{pattern:/(function(?:\\s+(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)?\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\\b|\\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\\w\\xA0-\\uFFFF]))(?:(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*)\\(\\s*|\\]\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*\\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\\b[A-Z](?:[A-Z_]|\\dx?)*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:\"comment\"},\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}|(?!\\$\\{)[^\\\\`])*`/,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}/,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},rest:Prism.languages.javascript}},string:/[\\s\\S]+/}}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(\"script\",\"javascript\"),Prism.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,\"javascript\")),Prism.languages.js=Prism.languages.javascript},6854:()=>{!function(e){function t(e,t){return\"___\"+e.toUpperCase()+t+\"___\"}Object.defineProperties(e.languages[\"markup-templating\"]={},{buildPlaceholders:{value:function(r,n,o,i){if(r.language===n){var s=r.tokenStack=[];r.code=r.code.replace(o,(function(e){if(\"function\"==typeof i&&!i(e))return e;for(var o,a=s.length;-1!==r.code.indexOf(o=t(n,a));)++a;return s[a]=e,o})),r.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(r,n){if(r.language===n&&r.tokenStack){r.grammar=e.languages[n];var o=0,i=Object.keys(r.tokenStack);!function s(a){for(var l=0;l<a.length&&!(o>=i.length);l++){var c=a[l];if(\"string\"==typeof c||c.content&&\"string\"==typeof c.content){var d=i[o],u=r.tokenStack[d],h=\"string\"==typeof c?c:c.content,b=t(n,d),p=h.indexOf(b);if(p>-1){++o;var g=h.substring(0,p),f=new e.Token(n,e.tokenize(u,r.grammar),\"language-\"+n,u),m=h.substring(p+b.length),v=[];g&&v.push.apply(v,s([g])),v.push(f),m&&v.push.apply(v,s([m])),\"string\"==typeof c?a.splice.apply(a,[l,1].concat(v)):c.content=v}}else c.content&&s(c.content)}return a}(r.tokens)}}}})}(Prism)},4335:()=>{Prism.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\\s\\S])*?-->/,greedy:!0},prolog:{pattern:/<\\?[\\s\\S]+?\\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>\"'[\\]]|\"[^\"]*\"|'[^']*')+(?:\\[(?:[^<\"'\\]]|\"[^\"]*\"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\\]\\s*)?>/i,greedy:!0,inside:{\"internal-subset\":{pattern:/(^[^\\[]*\\[)[\\s\\S]+(?=\\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\\]]/,\"doctype-tag\":/^DOCTYPE/i,name:/[^\\s<>'\"]+/}},cdata:{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,greedy:!0},tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s(?:\\s*[^\\s>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))|(?=[\\s/>])))+)?\\s*\\/?>/,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"special-attr\":[],\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:[{pattern:/&[\\da-z]{1,8};/i,alias:\"named-entity\"},/&#x?[\\da-f]{1,8};/i]},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside[\"internal-subset\"].inside=Prism.languages.markup,Prism.hooks.add(\"wrap\",(function(e){\"entity\"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,\"&\"))})),Object.defineProperty(Prism.languages.markup.tag,\"addInlined\",{value:function(e,t){var r={};r[\"language-\"+t]={pattern:/(^<!\\[CDATA\\[)[\\s\\S]+?(?=\\]\\]>$)/i,lookbehind:!0,inside:Prism.languages[t]},r.cdata=/^<!\\[CDATA\\[|\\]\\]>$/i;var n={\"included-cdata\":{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,inside:r}};n[\"language-\"+t]={pattern:/[\\s\\S]+/,inside:Prism.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\\[CDATA\\[(?:[^\\]]|\\](?!\\]>))*\\]\\]>|(?!<!\\[CDATA\\[)[\\s\\S])*?(?=<\\/__>)/.source.replace(/__/g,(function(){return e})),\"i\"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore(\"markup\",\"cdata\",o)}}),Object.defineProperty(Prism.languages.markup.tag,\"addAttribute\",{value:function(e,t){Prism.languages.markup.tag.inside[\"special-attr\"].push({pattern:RegExp(/(^|[\"'\\s])/.source+\"(?:\"+e+\")\"+/\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))/.source,\"i\"),lookbehind:!0,inside:{\"attr-name\":/^[^\\s=]+/,\"attr-value\":{pattern:/=[\\s\\S]+/,inside:{value:{pattern:/(^=\\s*([\"']|(?![\"'])))\\S[\\s\\S]*(?=\\2$)/,lookbehind:!0,alias:[t,\"language-\"+t],inside:Prism.languages[t]},punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend(\"markup\",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml},9945:()=>{!function(e){var t=/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*|#(?!\\[).*/,r=[{pattern:/\\b(?:false|true)\\b/i,alias:\"boolean\"},{pattern:/(::\\s*)\\b[a-z_]\\w*\\b(?!\\s*\\()/i,greedy:!0,lookbehind:!0},{pattern:/(\\b(?:case|const)\\s+)\\b[a-z_]\\w*(?=\\s*[;=])/i,greedy:!0,lookbehind:!0},/\\b(?:null)\\b/i,/\\b[A-Z_][A-Z0-9_]*\\b(?!\\s*\\()/],n=/\\b0b[01]+(?:_[01]+)*\\b|\\b0o[0-7]+(?:_[0-7]+)*\\b|\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b|(?:\\b\\d+(?:_\\d+)*\\.?(?:\\d+(?:_\\d+)*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,o=/<?=>|\\?\\?=?|\\.{3}|\\??->|[!=]=?=?|::|\\*\\*=?|--|\\+\\+|&&|\\|\\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,i=/[{}\\[\\](),:;]/;e.languages.php={delimiter:{pattern:/\\?>$|^<\\?(?:php(?=\\s)|=)?/i,alias:\"important\"},comment:t,variable:/\\$+(?:\\w+\\b|(?=\\{))/i,package:{pattern:/(namespace\\s+|use\\s+(?:function\\s+)?)(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,lookbehind:!0,inside:{punctuation:/\\\\/}},\"class-name-definition\":{pattern:/(\\b(?:class|enum|interface|trait)\\s+)\\b[a-z_]\\w*(?!\\\\)\\b/i,lookbehind:!0,alias:\"class-name\"},\"function-definition\":{pattern:/(\\bfunction\\s+)[a-z_]\\w*(?=\\s*\\()/i,lookbehind:!0,alias:\"function\"},keyword:[{pattern:/(\\(\\s*)\\b(?:bool|boolean|int|integer|float|string|object|array)\\b(?=\\s*\\))/i,alias:\"type-casting\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*)\\b(?:bool|int|float|string|object|array(?!\\s*\\()|mixed|self|static|callable|iterable|(?:null|false)(?=\\s*\\|))\\b(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*[\\w|]\\|\\s*)(?:null|false)\\b(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)\\b(?:bool|int|float|string|object|void|array(?!\\s*\\()|mixed|self|static|callable|iterable|(?:null|false)(?=\\s*\\|))\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?[\\w|]\\|\\s*)(?:null|false)\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/\\b(?:bool|int|float|string|object|void|array(?!\\s*\\()|mixed|iterable|(?:null|false)(?=\\s*\\|))\\b/i,alias:\"type-declaration\",greedy:!0},{pattern:/(\\|\\s*)(?:null|false)\\b/i,alias:\"type-declaration\",greedy:!0,lookbehind:!0},{pattern:/\\b(?:parent|self|static)(?=\\s*::)/i,alias:\"static-context\",greedy:!0},{pattern:/(\\byield\\s+)from\\b/i,lookbehind:!0},/\\bclass\\b/i,{pattern:/((?:^|[^\\s>:]|(?:^|[^-])>|(?:^|[^:]):)\\s*)\\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\\b/i,lookbehind:!0}],\"argument-name\":{pattern:/([(,]\\s+)\\b[a-z_]\\w*(?=\\s*:(?!:))/i,lookbehind:!0},\"class-name\":[{pattern:/(\\b(?:extends|implements|instanceof|new(?!\\s+self|\\s+static))\\s+|\\bcatch\\s*\\()\\b[a-z_]\\w*(?!\\\\)\\b/i,greedy:!0,lookbehind:!0},{pattern:/(\\|\\s*)\\b[a-z_]\\w*(?!\\\\)\\b/i,greedy:!0,lookbehind:!0},{pattern:/\\b[a-z_]\\w*(?!\\\\)\\b(?=\\s*\\|)/i,greedy:!0},{pattern:/(\\|\\s*)(?:\\\\?\\b[a-z_]\\w*)+\\b/i,alias:\"class-name-fully-qualified\",greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+\\b(?=\\s*\\|)/i,alias:\"class-name-fully-qualified\",greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/(\\b(?:extends|implements|instanceof|new(?!\\s+self\\b|\\s+static\\b))\\s+|\\bcatch\\s*\\()(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,alias:\"class-name-fully-qualified\",greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/\\b[a-z_]\\w*(?=\\s*\\$)/i,alias:\"type-declaration\",greedy:!0},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*\\$)/i,alias:[\"class-name-fully-qualified\",\"type-declaration\"],greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/\\b[a-z_]\\w*(?=\\s*::)/i,alias:\"static-context\",greedy:!0},{pattern:/(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*::)/i,alias:[\"class-name-fully-qualified\",\"static-context\"],greedy:!0,inside:{punctuation:/\\\\/}},{pattern:/([(,?]\\s*)[a-z_]\\w*(?=\\s*\\$)/i,alias:\"type-hint\",greedy:!0,lookbehind:!0},{pattern:/([(,?]\\s*)(?:\\\\?\\b[a-z_]\\w*)+(?=\\s*\\$)/i,alias:[\"class-name-fully-qualified\",\"type-hint\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)\\b[a-z_]\\w*(?!\\\\)\\b/i,alias:\"return-type\",greedy:!0,lookbehind:!0},{pattern:/(\\)\\s*:\\s*(?:\\?\\s*)?)(?:\\\\?\\b[a-z_]\\w*)+\\b(?!\\\\)/i,alias:[\"class-name-fully-qualified\",\"return-type\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}}],constant:r,function:{pattern:/(^|[^\\\\\\w])\\\\?[a-z_](?:[\\w\\\\]*\\w)?(?=\\s*\\()/i,lookbehind:!0,inside:{punctuation:/\\\\/}},property:{pattern:/(->\\s*)\\w+/,lookbehind:!0},number:n,operator:o,punctuation:i};var s={pattern:/\\{\\$(?:\\{(?:\\{[^{}]+\\}|[^{}]+)\\}|[^{}])+\\}|(^|[^\\\\{])\\$+(?:\\w+(?:\\[[^\\r\\n\\[\\]]+\\]|->\\w+)?)/,lookbehind:!0,inside:e.languages.php},a=[{pattern:/<<<'([^']+)'[\\r\\n](?:.*[\\r\\n])*?\\1;/,alias:\"nowdoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\\w*;$/i,alias:\"symbol\",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:\"([^\"]+)\"[\\r\\n](?:.*[\\r\\n])*?\\1;|([a-z_]\\w*)[\\r\\n](?:.*[\\r\\n])*?\\2;)/i,alias:\"heredoc-string\",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:\"[^\"]+\"|[a-z_]\\w*)|[a-z_]\\w*;$/i,alias:\"symbol\",inside:{punctuation:/^<<<\"?|[\";]$/}},interpolation:s}},{pattern:/`(?:\\\\[\\s\\S]|[^\\\\`])*`/,alias:\"backtick-quoted-string\",greedy:!0},{pattern:/'(?:\\\\[\\s\\S]|[^\\\\'])*'/,alias:\"single-quoted-string\",greedy:!0},{pattern:/\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"/,alias:\"double-quoted-string\",greedy:!0,inside:{interpolation:s}}];e.languages.insertBefore(\"php\",\"variable\",{string:a,attribute:{pattern:/#\\[(?:[^\"'\\/#]|\\/(?![*/])|\\/\\/.*$|#(?!\\[).*$|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|\"(?:\\\\[\\s\\S]|[^\\\\\"])*\"|'(?:\\\\[\\s\\S]|[^\\\\'])*')+\\](?=\\s*[a-z$#])/im,greedy:!0,inside:{\"attribute-content\":{pattern:/^(#\\[)[\\s\\S]+(?=\\]$)/,lookbehind:!0,inside:{comment:t,string:a,\"attribute-class-name\":[{pattern:/([^:]|^)\\b[a-z_]\\w*(?!\\\\)\\b/i,alias:\"class-name\",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\\\?\\b[a-z_]\\w*)+/i,alias:[\"class-name\",\"class-name-fully-qualified\"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\\\/}}],constant:r,number:n,operator:o,punctuation:i}},delimiter:{pattern:/^#\\[|\\]$/,alias:\"punctuation\"}}}}),e.hooks.add(\"before-tokenize\",(function(t){/<\\?/.test(t.code)&&e.languages[\"markup-templating\"].buildPlaceholders(t,\"php\",/<\\?(?:[^\"'/#]|\\/(?![*/])|(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|(?:\\/\\/|#(?!\\[))(?:[^?\\n\\r]|\\?(?!>))*(?=$|\\?>|[\\r\\n])|#\\[|\\/\\*(?:[^*]|\\*(?!\\/))*(?:\\*\\/|$))*?(?:\\?>|$)/gi)})),e.hooks.add(\"after-tokenize\",(function(t){e.languages[\"markup-templating\"].tokenizePlaceholders(t,\"php\")}))}(Prism)},2886:()=>{Prism.languages.scala=Prism.languages.extend(\"java\",{\"triple-quoted-string\":{pattern:/\"\"\"[\\s\\S]*?\"\"\"/,greedy:!0,alias:\"string\"},string:{pattern:/(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},keyword:/<-|=>|\\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\\b/,number:/\\b0x(?:[\\da-f]*\\.)?[\\da-f]+|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e\\d+)?[dfl]?/i,builtin:/\\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\\b/,symbol:/'[^\\d\\s\\\\]\\w*/}),delete Prism.languages.scala[\"class-name\"],delete Prism.languages.scala.function},6836:()=>{!function(e){e.languages.typescript=e.languages.extend(\"javascript\",{\"class-name\":{pattern:/(\\b(?:class|extends|implements|instanceof|interface|new|type)\\s+)(?!keyof\\b)(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?:\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\\b/}),e.languages.typescript.keyword.push(/\\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\\b/,/\\b(?:asserts|infer|interface|module|namespace|type)\\b(?=\\s*(?:[{_$a-zA-Z\\xA0-\\uFFFF]|$))/,/\\btype\\b(?=\\s*(?:[\\{*]|$))/),delete e.languages.typescript.parameter;var t=e.languages.extend(\"typescript\",{});delete t[\"class-name\"],e.languages.typescript[\"class-name\"].inside=t,e.languages.insertBefore(\"typescript\",\"function\",{decorator:{pattern:/@[$\\w\\xA0-\\uFFFF]+/,inside:{at:{pattern:/^@/,alias:\"operator\"},function:/^[\\s\\S]+/}},\"generic-function\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\\s*\\()/,greedy:!0,inside:{function:/^#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*/,generic:{pattern:/<[\\s\\S]+/,alias:\"class-name\",inside:t}}}}),e.languages.ts=e.languages.typescript}(Prism)},6488:()=>{\"undefined\"!=typeof Prism&&\"undefined\"!=typeof document&&document.createRange&&(Prism.plugins.KeepMarkup=!0,Prism.hooks.add(\"before-highlight\",(function(e){if(e.element.children.length&&Prism.util.isActive(e.element,\"keep-markup\",!0)){var t=0,r=[],n=function(e,o){var i={};o||(i.clone=e.cloneNode(!1),i.posOpen=t,r.push(i));for(var s=0,a=e.childNodes.length;s<a;s++){var l=e.childNodes[s];1===l.nodeType?n(l):3===l.nodeType&&(t+=l.data.length)}o||(i.posClose=t)};n(e.element,!0),r&&r.length&&(e.keepMarkup=r)}})),Prism.hooks.add(\"after-highlight\",(function(e){if(e.keepMarkup&&e.keepMarkup.length){var t=function(e,r){for(var n=0,o=e.childNodes.length;n<o;n++){var i=e.childNodes[n];if(1===i.nodeType){if(!t(i,r))return!1}else 3===i.nodeType&&(!r.nodeStart&&r.pos+i.data.length>r.node.posOpen&&(r.nodeStart=i,r.nodeStartPos=r.node.posOpen-r.pos),r.nodeStart&&r.pos+i.data.length>=r.node.posClose&&(r.nodeEnd=i,r.nodeEndPos=r.node.posClose-r.pos),r.pos+=i.data.length);if(r.nodeStart&&r.nodeEnd){var s=document.createRange();return s.setStart(r.nodeStart,r.nodeStartPos),s.setEnd(r.nodeEnd,r.nodeEndPos),r.node.clone.appendChild(s.extractContents()),s.insertNode(r.node.clone),s.detach(),!1}}return!0};e.keepMarkup.forEach((function(r){t(e.element,{node:r,pos:0})})),e.highlightedCode=e.element.innerHTML}})))},8759:()=>{!function(){if(\"undefined\"!=typeof Prism&&\"undefined\"!=typeof document){var e=\"line-numbers\",t=/\\n(?!$)/g,r=Prism.plugins.lineNumbers={getLine:function(t,r){if(\"PRE\"===t.tagName&&t.classList.contains(e)){var n=t.querySelector(\".line-numbers-rows\");if(n){var o=parseInt(t.getAttribute(\"data-start\"),10)||1,i=o+(n.children.length-1);r<o&&(r=o),r>i&&(r=i);var s=r-o;return n.children[s]}}},resize:function(e){o([e])},assumeViewportIndependence:!0},n=void 0;window.addEventListener(\"resize\",(function(){r.assumeViewportIndependence&&n===window.innerWidth||(n=window.innerWidth,o(Array.prototype.slice.call(document.querySelectorAll(\"pre.line-numbers\"))))})),Prism.hooks.add(\"complete\",(function(r){if(r.code){var n=r.element,i=n.parentNode;if(i&&/pre/i.test(i.nodeName)&&!n.querySelector(\".line-numbers-rows\")&&Prism.util.isActive(n,e)){n.classList.remove(e),i.classList.add(e);var s,a=r.code.match(t),l=a?a.length+1:1,c=new Array(l+1).join(\"<span></span>\");(s=document.createElement(\"span\")).setAttribute(\"aria-hidden\",\"true\"),s.className=\"line-numbers-rows\",s.innerHTML=c,i.hasAttribute(\"data-start\")&&(i.style.counterReset=\"linenumber \"+(parseInt(i.getAttribute(\"data-start\"),10)-1)),r.element.appendChild(s),o([i]),Prism.hooks.run(\"line-numbers\",r)}}})),Prism.hooks.add(\"line-numbers\",(function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}))}function o(e){if(0!=(e=e.filter((function(e){var t,r=(t=e,t?window.getComputedStyle?getComputedStyle(t):t.currentStyle||null:null)[\"white-space\"];return\"pre-wrap\"===r||\"pre-line\"===r}))).length){var r=e.map((function(e){var r=e.querySelector(\"code\"),n=e.querySelector(\".line-numbers-rows\");if(r&&n){var o=e.querySelector(\".line-numbers-sizer\"),i=r.textContent.split(t);o||((o=document.createElement(\"span\")).className=\"line-numbers-sizer\",r.appendChild(o)),o.innerHTML=\"0\",o.style.display=\"block\";var s=o.getBoundingClientRect().height;return o.innerHTML=\"\",{element:e,lines:i,lineHeights:[],oneLinerHeight:s,sizer:o}}})).filter(Boolean);r.forEach((function(e){var t=e.sizer,r=e.lines,n=e.lineHeights,o=e.oneLinerHeight;n[r.length-1]=void 0,r.forEach((function(e,r){if(e&&e.length>1){var i=t.appendChild(document.createElement(\"span\"));i.style.display=\"block\",i.textContent=e}else n[r]=o}))})),r.forEach((function(e){for(var t=e.sizer,r=e.lineHeights,n=0,o=0;o<r.length;o++)void 0===r[o]&&(r[o]=t.children[n++].getBoundingClientRect().height)})),r.forEach((function(e){var t=e.sizer,r=e.element.querySelector(\".line-numbers-rows\");t.style.display=\"none\",t.innerHTML=\"\",e.lineHeights.forEach((function(e,t){r.children[t].style.height=e+\"px\"}))}))}}}()},7951:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.aggregateResultsByModule=void 0;const n=r(5740);t.aggregateResultsByModule=function(e){var t,r;const o=Object.values(e).map((e=>e.projectRoot)).filter(n.isNotNullish),i={files:{},schemaVersion:\"1.7\",thresholds:null!==(r=null===(t=e[0])||void 0===t?void 0:t.thresholds)&&void 0!==r?r:{high:80,low:60},projectRoot:o.length?(0,n.determineCommonBasePath)(o):void 0,config:{}};return Object.entries(e).reduce(((e,[t,r])=>{var o;if(Object.entries((0,n.normalizeFileNames)(r.files)).forEach((([e,r])=>{i.files[`${t}/${e}`]=r})),r.testFiles){const e=null!==(o=i.testFiles)&&void 0!==o?o:i.testFiles=Object.create(null);Object.entries((0,n.normalizeFileNames)(r.testFiles)).forEach((([r,n])=>{e[`${t}/${r}`]=n}))}return e}),i)}},2103:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.calculateMutationTestMetrics=t.calculateMetrics=void 0;const n=r(5740),o=r(9130),i=r(5740),s=r(8533),a=r(8689),l=\"All files\";function c(e,t,r){const n=Object.keys(t);return 1===n.length&&\"\"===n[0]?u(e,t[n[0]],r):d(e,t,r)}function d(e,t,r){const o=r(Object.values(t)),s=function(e,t){const r=(0,i.groupBy)(Object.entries(e),(e=>e[0].split(\"/\")[0]));return Object.keys(r).map((e=>{if(r[e].length>1||r[e][0][0]!==e){const n={};return r[e].forEach((t=>n[t[0].substr(e.length+1)]=t[1])),d(e,n,t)}{const[n,o]=r[e][0];return u(n,o,t)}})).sort(n.compareNames)}(t,r);return{name:e,childResults:s,metrics:o}}function u(e,t,r){return{file:t,name:e,childResults:[],metrics:r([t])}}function h(e){const t=e.flatMap((e=>e.tests)),r=e=>t.filter((t=>t.status===e)).length;return{total:t.length,killing:r(a.TestStatus.Killing),covering:r(a.TestStatus.Covering),notCovering:r(a.TestStatus.NotCovering)}}function b(e){const t=e.flatMap((e=>e.mutants)),r=e=>t.filter((t=>t.status===e)).length,n=r(o.MutantStatus.Killed),i=r(o.MutantStatus.Timeout),s=r(o.MutantStatus.Survived),a=r(o.MutantStatus.NoCoverage),l=r(o.MutantStatus.RuntimeError),c=r(o.MutantStatus.CompileError),d=r(o.MutantStatus.Ignored),u=i+n,h=s+a,b=u+s,p=h+u,g=l+c;return{killed:n,timeout:i,survived:s,noCoverage:a,runtimeErrors:l,compileErrors:c,ignored:d,totalDetected:u,totalUndetected:h,totalCovered:b,totalValid:p,totalInvalid:g,mutationScore:p>0?u/p*100:NaN,totalMutants:p+g+d,mutationScoreBasedOnCoveredCode:p>0?u/b*100||0:NaN}}t.calculateMetrics=function(e){const t=(0,n.normalize)(e,\"\",((e,t)=>new s.FileUnderTestModel(e,t)));return d(l,t,b)},t.calculateMutationTestMetrics=function(e){const{files:t,testFiles:r,projectRoot:o=\"\"}=e,i=(0,n.normalize)(t,o,((e,t)=>new s.FileUnderTestModel(e,t)));if(r){const e=(0,n.normalize)(r,o,((e,t)=>new s.TestFileModel(e,t)));return function(e,t){var r,n;for(const o of e)if(o.coveredBy||o.killedBy)for(const e of t)(null===(r=o.coveredBy)||void 0===r?void 0:r.includes(e.id))&&(o.addCoveredBy(e),e.addCovered(o)),(null===(n=o.killedBy)||void 0===n?void 0:n.includes(e.id))&&(o.addKilledBy(e),e.addKilled(o))}(Object.values(i).flatMap((e=>e.mutants)),Object.values(e).flatMap((e=>e.tests))),{systemUnderTestMetrics:c(l,i,b),testMetrics:c(\"All tests\",e,h)}}return{systemUnderTestMetrics:c(l,i,b),testMetrics:void 0}}},400:(e,t)=>{\"use strict\";function r(e,t,r){const i=Object.keys(e),s=o(i),a=Object.create(null);return i.forEach((o=>{const i=n(o.startsWith(t)?o.substr(t.length):o);a[n(o.substr(s.length))]=r(e[o],i)})),a}function n(e){return e.split(/\\/|\\\\/).filter(Boolean).join(\"/\")}function o(e){const t=e.map((e=>e.split(/\\/|\\\\/).slice(0,-1)));return e.length?t.reduce((function(e,t){for(let r=0;r<e.length;r++)if(e[r]!==t[r])return e.splice(0,r);return e})).join(\"/\"):\"\"}Object.defineProperty(t,\"__esModule\",{value:!0}),t.compareNames=t.determineCommonBasePath=t.normalize=t.normalizeFileNames=void 0,t.normalizeFileNames=function(e,t=\"\"){return r(e,t,(e=>e))},t.normalize=r,t.determineCommonBasePath=o,t.compareNames=function(e,t){const r=e=>e.file?`1${e.name}`:`0${e.name}`;return r(e).localeCompare(r(t))}},7648:(e,t)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.groupBy=void 0,t.groupBy=function(e,t){return e.reduce(((e,r)=>{const n=t(r);return Object.prototype.hasOwnProperty.call(e,n)||(e[n]=[]),e[n].push(r),e}),{})}},5740:function(e,t,r){\"use strict\";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__exportStar||function(e,t){for(var r in e)\"default\"===r||Object.prototype.hasOwnProperty.call(t,r)||n(t,e,r)};Object.defineProperty(t,\"__esModule\",{value:!0}),o(r(7648),t),o(r(400),t),o(r(9676),t),o(r(3029),t)},3029:(e,t)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.isNotNullish=void 0,t.isNotNullish=function(e){return null!=e}},9676:(e,t)=>{\"use strict\";function r(e){return 10===e||13===e||8232===e||8233===e}Object.defineProperty(t,\"__esModule\",{value:!0}),t.computeLineStarts=void 0,t.computeLineStarts=function(e){const t=[];let n=0,o=0;function i(e){t.push(o),o=e}for(i(0);n<e.length;){const t=e.charCodeAt(n);switch(n++,t){case 13:10===e.charCodeAt(n)&&n++,i(n);break;case 10:i(n);break;default:t>127&&r(t)&&i(n)}}return t.push(o),t}},4193:(e,t,r)=>{\"use strict\";t.ih=t.xR=void 0;var n=r(2103);Object.defineProperty(t,\"xR\",{enumerable:!0,get:function(){return n.calculateMutationTestMetrics}});r(7951),r(5740);var o=r(8533);Object.defineProperty(t,\"ih\",{enumerable:!0,get:function(){return o.TestStatus}})},1211:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.FileUnderTestModel=void 0;const n=r(1223),o=r(7966);class i extends o.SourceFile{constructor(e,t){super(),this.name=t,this.language=e.language,this.source=e.source,this.mutants=e.mutants.map((e=>{const t=new n.MutantModel(e);return t.sourceFile=this,t}))}getMutationLines(e){var t,r;const n=this.getLineMap(),o=n[e.location.start.line],i=n[e.location.end.line],s=n[e.location.end.line+1];return`${this.source.substr(o,e.location.start.column-1)}${null!==(r=null!==(t=e.replacement)&&void 0!==t?t:e.description)&&void 0!==r?r:e.mutatorName}${this.source.substring(i+e.location.end.column-1,s)}`}}t.FileUnderTestModel=i},8533:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.TestStatus=t.TestModel=t.TestFileModel=t.MutantModel=t.FileUnderTestModel=void 0;var n=r(1211);Object.defineProperty(t,\"FileUnderTestModel\",{enumerable:!0,get:function(){return n.FileUnderTestModel}});var o=r(1223);Object.defineProperty(t,\"MutantModel\",{enumerable:!0,get:function(){return o.MutantModel}});var i=r(7100);Object.defineProperty(t,\"TestFileModel\",{enumerable:!0,get:function(){return i.TestFileModel}});var s=r(8689);Object.defineProperty(t,\"TestModel\",{enumerable:!0,get:function(){return s.TestModel}}),Object.defineProperty(t,\"TestStatus\",{enumerable:!0,get:function(){return s.TestStatus}})},1223:(e,t)=>{\"use strict\";function r(e){if(void 0===e)throw new Error(\"mutant.sourceFile was not defined\")}Object.defineProperty(t,\"__esModule\",{value:!0}),t.MutantModel=void 0,t.MutantModel=class{constructor(e){this.coveredBy=e.coveredBy,this.description=e.description,this.duration=e.duration,this.id=e.id,this.killedBy=e.killedBy,this.location=e.location,this.mutatorName=e.mutatorName,this.replacement=e.replacement,this.static=e.static,this.status=e.status,this.statusReason=e.statusReason,this.testsCompleted=e.testsCompleted}addCoveredBy(e){this.coveredByTests||(this.coveredByTests=[]),this.coveredByTests.push(e)}addKilledBy(e){this.killedByTests||(this.killedByTests=[]),this.killedByTests.push(e)}getMutatedLines(){return r(this.sourceFile),this.sourceFile.getMutationLines(this)}getOriginalLines(){return r(this.sourceFile),this.sourceFile.getLines(this.location)}get fileName(){return r(this.sourceFile),this.sourceFile.name}}},7966:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.SourceFile=t.assertSourceDefined=void 0;const n=r(5740);function o(e){if(void 0===e)throw new Error(\"sourceFile.source is undefined\")}t.assertSourceDefined=o,t.SourceFile=class{getLineMap(){return o(this.source),this.lineMap||(this.lineMap=(0,n.computeLineStarts)(this.source))}getLines(e){var t;o(this.source);const r=this.getLineMap();return this.source.substring(r[e.start.line],r[(null!==(t=e.end)&&void 0!==t?t:e.start).line+1])}}},7100:(e,t,r)=>{\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.TestFileModel=void 0;const n=r(7966),o=r(8689);class i extends n.SourceFile{constructor(e,t){super(),this.name=t,this.source=e.source,this.tests=e.tests.map((e=>{const t=new o.TestModel(e);return t.sourceFile=this,t}))}}t.TestFileModel=i},8689:(e,t)=>{\"use strict\";function r(e){if(void 0===e)throw new Error(\"test.sourceFile was not defined\")}var n;Object.defineProperty(t,\"__esModule\",{value:!0}),t.TestModel=t.TestStatus=void 0,function(e){e.Killing=\"Killing\",e.Covering=\"Covering\",e.NotCovering=\"NotCovering\"}(n=t.TestStatus||(t.TestStatus={})),t.TestModel=class{constructor(e){Object.entries(e).forEach((([e,t])=>{this[e]=t}))}addCovered(e){this.coveredMutants||(this.coveredMutants=[]),this.coveredMutants.push(e)}addKilled(e){this.killedMutants||(this.killedMutants=[]),this.killedMutants.push(e)}getLines(){return r(this.sourceFile),function(e){if(void 0===e)throw new Error(\"test.location was not defined\")}(this.location),this.sourceFile.getLines(this.location)}get fileName(){return r(this.sourceFile),this.sourceFile.name}get status(){var e,t;return(null===(e=this.killedMutants)||void 0===e?void 0:e.length)?n.Killing:(null===(t=this.coveredMutants)||void 0===t?void 0:t.length)?n.Covering:n.NotCovering}}},9130:(e,t)=>{\"use strict\";var r;Object.defineProperty(t,\"__esModule\",{value:!0}),t.MutantStatus=void 0,(r=t.MutantStatus||(t.MutantStatus={})).Killed=\"Killed\",r.Survived=\"Survived\",r.NoCoverage=\"NoCoverage\",r.CompileError=\"CompileError\",r.RuntimeError=\"RuntimeError\",r.Timeout=\"Timeout\",r.Ignored=\"Ignored\"},7327:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=UTF8,<svg xmlns=%27http://www.w3.org/2000/svg%27 height=%273%27 width=%276%27><g fill=%27%23dc3545%27><path d=%27m5.5 0-3 3H1.1l3-3z%27/><path d=%27m4 0 2 2V.6L5.4 0zM0 2l1 1h1.4L0 .6z%27/></g></svg>\"},6076:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=UTF8,<svg xmlns=%27http://www.w3.org/2000/svg%27 height=%273%27 width=%276%27><g fill=%27%23e13238%27><path d=%27m5.5 0-3 3H1.1l3-3z%27/><path d=%27m4 0 2 2V.6L5.4 0zM0 2l1 1h1.4L0 .6z%27/></g></svg>\"},3726:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=UTF8,<svg xmlns=%27http://www.w3.org/2000/svg%27 height=%273%27 width=%276%27><g fill=%27%23fd7e14%27><path d=%27m5.5 0-3 3H1.1l3-3z%27/><path d=%27m4 0 2 2V.6L5.4 0zM0 2l1 1h1.4L0 .6z%27/></g></svg>\"},5605:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=UTF8,<svg xmlns=%27http://www.w3.org/2000/svg%27 height=%273%27 width=%276%27><g fill=%27%23ff8b26%27><path d=%27m5.5 0-3 3H1.1l3-3z%27/><path d=%27m4 0 2 2V.6L5.4 0zM0 2l1 1h1.4L0 .6z%27/></g></svg>\"},388:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27none%27 stroke=%27%23fff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%273%27 d=%27M6 10h8%27/%3E%3C/svg%3E\"},5322:e=>{\"use strict\";e.exports=\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27none%27 stroke=%27%23fff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%273%27 d=%27m6 10 3 3 6-6%27/%3E%3C/svg%3E\"}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={id:n,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.exports}r.m=e,r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.g=function(){if(\"object\"==typeof globalThis)return globalThis;try{return this||new Function(\"return this\")()}catch(e){if(\"object\"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.b=document.baseURI||self.location.href,(()=>{\"use strict\";const e=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&\"adoptedStyleSheets\"in Document.prototype&&\"replace\"in CSSStyleSheet.prototype,t=Symbol(),n=new Map;class o{constructor(e,r){if(this._$cssResult$=!0,r!==t)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=e}get styleSheet(){let t=n.get(this.cssText);return e&&void 0===t&&(n.set(this.cssText,t=new CSSStyleSheet),t.replaceSync(this.cssText)),t}toString(){return this.cssText}}const i=e=>new o(\"string\"==typeof e?e:e+\"\",t),s=e?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t=\"\";for(const r of e.cssRules)t+=r.cssText;return i(t)})(e):e;var a;const l=window.reactiveElementPolyfillSupport,c={toAttribute(e,t){switch(t){case Boolean:e=e?\"\":null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let r=e;switch(t){case Boolean:r=null!==e;break;case Number:r=null===e?null:Number(e);break;case Object:case Array:try{r=JSON.parse(e)}catch(e){r=null}}return r}},d=(e,t)=>t!==e&&(t==t||e==e),u={attribute:!0,type:String,converter:c,reflect:!1,hasChanged:d};class h extends HTMLElement{constructor(){super(),this._$Et=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Ei=null,this.o()}static addInitializer(e){var t;null!==(t=this.l)&&void 0!==t||(this.l=[]),this.l.push(e)}static get observedAttributes(){this.finalize();const e=[];return this.elementProperties.forEach(((t,r)=>{const n=this._$Eh(r,t);void 0!==n&&(this._$Eu.set(n,r),e.push(n))})),e}static createProperty(e,t=u){if(t.state&&(t.attribute=!1),this.finalize(),this.elementProperties.set(e,t),!t.noAccessor&&!this.prototype.hasOwnProperty(e)){const r=\"symbol\"==typeof e?Symbol():\"__\"+e,n=this.getPropertyDescriptor(e,r,t);void 0!==n&&Object.defineProperty(this.prototype,e,n)}}static getPropertyDescriptor(e,t,r){return{get(){return this[t]},set(n){const o=this[e];this[t]=n,this.requestUpdate(e,o,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)||u}static finalize(){if(this.hasOwnProperty(\"finalized\"))return!1;this.finalized=!0;const e=Object.getPrototypeOf(this);if(e.finalize(),this.elementProperties=new Map(e.elementProperties),this._$Eu=new Map,this.hasOwnProperty(\"properties\")){const e=this.properties,t=[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const r of t)this.createProperty(r,e[r])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const r=new Set(e.flat(1/0).reverse());for(const e of r)t.unshift(s(e))}else void 0!==e&&t.push(s(e));return t}static _$Eh(e,t){const r=t.attribute;return!1===r?void 0:\"string\"==typeof r?r:\"string\"==typeof e?e.toLowerCase():void 0}o(){var e;this._$Ev=new Promise((e=>this.enableUpdating=e)),this._$AL=new Map,this._$Ep(),this.requestUpdate(),null===(e=this.constructor.l)||void 0===e||e.forEach((e=>e(this)))}addController(e){var t,r;(null!==(t=this._$Em)&&void 0!==t?t:this._$Em=[]).push(e),void 0!==this.renderRoot&&this.isConnected&&(null===(r=e.hostConnected)||void 0===r||r.call(e))}removeController(e){var t;null===(t=this._$Em)||void 0===t||t.splice(this._$Em.indexOf(e)>>>0,1)}_$Ep(){this.constructor.elementProperties.forEach(((e,t)=>{this.hasOwnProperty(t)&&(this._$Et.set(t,this[t]),delete this[t])}))}createRenderRoot(){var t;const r=null!==(t=this.shadowRoot)&&void 0!==t?t:this.attachShadow(this.constructor.shadowRootOptions);return((t,r)=>{e?t.adoptedStyleSheets=r.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):r.forEach((e=>{const r=document.createElement(\"style\"),n=window.litNonce;void 0!==n&&r.setAttribute(\"nonce\",n),r.textContent=e.cssText,t.appendChild(r)}))})(r,this.constructor.elementStyles),r}connectedCallback(){var e;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(e=this._$Em)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostConnected)||void 0===t?void 0:t.call(e)}))}enableUpdating(e){}disconnectedCallback(){var e;null===(e=this._$Em)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostDisconnected)||void 0===t?void 0:t.call(e)}))}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$Eg(e,t,r=u){var n,o;const i=this.constructor._$Eh(e,r);if(void 0!==i&&!0===r.reflect){const s=(null!==(o=null===(n=r.converter)||void 0===n?void 0:n.toAttribute)&&void 0!==o?o:c.toAttribute)(t,r.type);this._$Ei=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Ei=null}}_$AK(e,t){var r,n,o;const i=this.constructor,s=i._$Eu.get(e);if(void 0!==s&&this._$Ei!==s){const e=i.getPropertyOptions(s),a=e.converter,l=null!==(o=null!==(n=null===(r=a)||void 0===r?void 0:r.fromAttribute)&&void 0!==n?n:\"function\"==typeof a?a:null)&&void 0!==o?o:c.fromAttribute;this._$Ei=s,this[s]=l(t,e.type),this._$Ei=null}}requestUpdate(e,t,r){let n=!0;void 0!==e&&(((r=r||this.constructor.getPropertyOptions(e)).hasChanged||d)(this[e],t)?(this._$AL.has(e)||this._$AL.set(e,t),!0===r.reflect&&this._$Ei!==e&&(void 0===this._$ES&&(this._$ES=new Map),this._$ES.set(e,r))):n=!1),!this.isUpdatePending&&n&&(this._$Ev=this._$EC())}async _$EC(){this.isUpdatePending=!0;try{await this._$Ev}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var e;if(!this.isUpdatePending)return;this.hasUpdated,this._$Et&&(this._$Et.forEach(((e,t)=>this[t]=e)),this._$Et=void 0);let t=!1;const r=this._$AL;try{t=this.shouldUpdate(r),t?(this.willUpdate(r),null===(e=this._$Em)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostUpdate)||void 0===t?void 0:t.call(e)})),this.update(r)):this._$EU()}catch(e){throw t=!1,this._$EU(),e}t&&this._$AE(r)}willUpdate(e){}_$AE(e){var t;null===(t=this._$Em)||void 0===t||t.forEach((e=>{var t;return null===(t=e.hostUpdated)||void 0===t?void 0:t.call(e)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EU(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$Ev}shouldUpdate(e){return!0}update(e){void 0!==this._$ES&&(this._$ES.forEach(((e,t)=>this._$Eg(t,this[t],e))),this._$ES=void 0),this._$EU()}updated(e){}firstUpdated(e){}}var b;h.finalized=!0,h.elementProperties=new Map,h.elementStyles=[],h.shadowRootOptions={mode:\"open\"},null==l||l({ReactiveElement:h}),(null!==(a=globalThis.reactiveElementVersions)&&void 0!==a?a:globalThis.reactiveElementVersions=[]).push(\"1.0.1\");const p=globalThis.trustedTypes,g=p?p.createPolicy(\"lit-html\",{createHTML:e=>e}):void 0,f=`lit$${(Math.random()+\"\").slice(9)}$`,m=\"?\"+f,v=`<${m}>`,y=document,w=(e=\"\")=>y.createComment(e),k=e=>null===e||\"object\"!=typeof e&&\"function\"!=typeof e,$=Array.isArray,x=e=>{var t;return $(e)||\"function\"==typeof(null===(t=e)||void 0===t?void 0:t[Symbol.iterator])},S=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,A=/-->/g,_=/>/g,M=/>|[ \t\\n\f\\r](?:([^\\s\"'>=/]+)([ \t\\n\f\\r]*=[ \t\\n\f\\r]*(?:[^ \t\\n\f\\r\"'`<>=]|(\"|')|))|$)/g,C=/'/g,E=/\"/g,T=/^(?:script|style|textarea)$/i,P=e=>(t,...r)=>({_$litType$:e,strings:t,values:r}),z=P(1),j=P(2),F=Symbol.for(\"lit-noChange\"),N=Symbol.for(\"lit-nothing\"),O=new WeakMap,R=y.createTreeWalker(y,129,null,!1),B=(e,t)=>{const r=e.length-1,n=[];let o,i=2===t?\"<svg>\":\"\",s=S;for(let t=0;t<r;t++){const r=e[t];let a,l,c=-1,d=0;for(;d<r.length&&(s.lastIndex=d,l=s.exec(r),null!==l);)d=s.lastIndex,s===S?\"!--\"===l[1]?s=A:void 0!==l[1]?s=_:void 0!==l[2]?(T.test(l[2])&&(o=RegExp(\"</\"+l[2],\"g\")),s=M):void 0!==l[3]&&(s=M):s===M?\">\"===l[0]?(s=null!=o?o:S,c=-1):void 0===l[1]?c=-2:(c=s.lastIndex-l[2].length,a=l[1],s=void 0===l[3]?M:'\"'===l[3]?E:C):s===E||s===C?s=M:s===A||s===_?s=S:(s=M,o=void 0);const u=s===M&&e[t+1].startsWith(\"/>\")?\" \":\"\";i+=s===S?r+v:c>=0?(n.push(a),r.slice(0,c)+\"$lit$\"+r.slice(c)+f+u):r+f+(-2===c?(n.push(void 0),t):u)}const a=i+(e[r]||\"<?>\")+(2===t?\"</svg>\":\"\");return[void 0!==g?g.createHTML(a):a,n]};class L{constructor({strings:e,_$litType$:t},r){let n;this.parts=[];let o=0,i=0;const s=e.length-1,a=this.parts,[l,c]=B(e,t);if(this.el=L.createElement(l,r),R.currentNode=this.el.content,2===t){const e=this.el.content,t=e.firstChild;t.remove(),e.append(...t.childNodes)}for(;null!==(n=R.nextNode())&&a.length<s;){if(1===n.nodeType){if(n.hasAttributes()){const e=[];for(const t of n.getAttributeNames())if(t.endsWith(\"$lit$\")||t.startsWith(f)){const r=c[i++];if(e.push(t),void 0!==r){const e=n.getAttribute(r.toLowerCase()+\"$lit$\").split(f),t=/([.?@])?(.*)/.exec(r);a.push({type:1,index:o,name:t[2],strings:e,ctor:\".\"===t[1]?Z:\"?\"===t[1]?K:\"@\"===t[1]?q:H})}else a.push({type:6,index:o})}for(const t of e)n.removeAttribute(t)}if(T.test(n.tagName)){const e=n.textContent.split(f),t=e.length-1;if(t>0){n.textContent=p?p.emptyScript:\"\";for(let r=0;r<t;r++)n.append(e[r],w()),R.nextNode(),a.push({type:2,index:++o});n.append(e[t],w())}}}else if(8===n.nodeType)if(n.data===m)a.push({type:2,index:o});else{let e=-1;for(;-1!==(e=n.data.indexOf(f,e+1));)a.push({type:7,index:o}),e+=f.length-1}o++}}static createElement(e,t){const r=y.createElement(\"template\");return r.innerHTML=e,r}}function U(e,t,r=e,n){var o,i,s,a;if(t===F)return t;let l=void 0!==n?null===(o=r._$Cl)||void 0===o?void 0:o[n]:r._$Cu;const c=k(t)?void 0:t._$litDirective$;return(null==l?void 0:l.constructor)!==c&&(null===(i=null==l?void 0:l._$AO)||void 0===i||i.call(l,!1),void 0===c?l=void 0:(l=new c(e),l._$AT(e,r,n)),void 0!==n?(null!==(s=(a=r)._$Cl)&&void 0!==s?s:a._$Cl=[])[n]=l:r._$Cu=l),void 0!==l&&(t=U(e,l._$AS(e,t.values),l,n)),t}class I{constructor(e,t){this.v=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}p(e){var t;const{el:{content:r},parts:n}=this._$AD,o=(null!==(t=null==e?void 0:e.creationScope)&&void 0!==t?t:y).importNode(r,!0);R.currentNode=o;let i=R.nextNode(),s=0,a=0,l=n[0];for(;void 0!==l;){if(s===l.index){let t;2===l.type?t=new D(i,i.nextSibling,this,e):1===l.type?t=new l.ctor(i,l.name,l.strings,this,e):6===l.type&&(t=new V(i,this,e)),this.v.push(t),l=n[++a]}s!==(null==l?void 0:l.index)&&(i=R.nextNode(),s++)}return o}m(e){let t=0;for(const r of this.v)void 0!==r&&(void 0!==r.strings?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}}class D{constructor(e,t,r,n){var o;this.type=2,this._$AH=N,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=n,this._$Cg=null===(o=null==n?void 0:n.isConnected)||void 0===o||o}get _$AU(){var e,t;return null!==(t=null===(e=this._$AM)||void 0===e?void 0:e._$AU)&&void 0!==t?t:this._$Cg}get parentNode(){let e=this._$AA.parentNode;const t=this._$AM;return void 0!==t&&11===e.nodeType&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=U(this,e,t),k(e)?e===N||null==e||\"\"===e?(this._$AH!==N&&this._$AR(),this._$AH=N):e!==this._$AH&&e!==F&&this.$(e):void 0!==e._$litType$?this.T(e):void 0!==e.nodeType?this.S(e):x(e)?this.M(e):this.$(e)}A(e,t=this._$AB){return this._$AA.parentNode.insertBefore(e,t)}S(e){this._$AH!==e&&(this._$AR(),this._$AH=this.A(e))}$(e){this._$AH!==N&&k(this._$AH)?this._$AA.nextSibling.data=e:this.S(y.createTextNode(e)),this._$AH=e}T(e){var t;const{values:r,_$litType$:n}=e,o=\"number\"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=L.createElement(n.h,this.options)),n);if((null===(t=this._$AH)||void 0===t?void 0:t._$AD)===o)this._$AH.m(r);else{const e=new I(o,this),t=e.p(this.options);e.m(r),this.S(t),this._$AH=e}}_$AC(e){let t=O.get(e.strings);return void 0===t&&O.set(e.strings,t=new L(e)),t}M(e){$(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let r,n=0;for(const o of e)n===t.length?t.push(r=new D(this.A(w()),this.A(w()),this,this.options)):r=t[n],r._$AI(o),n++;n<t.length&&(this._$AR(r&&r._$AB.nextSibling,n),t.length=n)}_$AR(e=this._$AA.nextSibling,t){var r;for(null===(r=this._$AP)||void 0===r||r.call(this,!1,!0,t);e&&e!==this._$AB;){const t=e.nextSibling;e.remove(),e=t}}setConnected(e){var t;void 0===this._$AM&&(this._$Cg=e,null===(t=this._$AP)||void 0===t||t.call(this,e))}}class H{constructor(e,t,r,n,o){this.type=1,this._$AH=N,this._$AN=void 0,this.element=e,this.name=t,this._$AM=n,this.options=o,r.length>2||\"\"!==r[0]||\"\"!==r[1]?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=N}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,t=this,r,n){const o=this.strings;let i=!1;if(void 0===o)e=U(this,e,t,0),i=!k(e)||e!==this._$AH&&e!==F,i&&(this._$AH=e);else{const n=e;let s,a;for(e=o[0],s=0;s<o.length-1;s++)a=U(this,n[r+s],t,s),a===F&&(a=this._$AH[s]),i||(i=!k(a)||a!==this._$AH[s]),a===N?e=N:e!==N&&(e+=(null!=a?a:\"\")+o[s+1]),this._$AH[s]=a}i&&!n&&this.k(e)}k(e){e===N?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,null!=e?e:\"\")}}class Z extends H{constructor(){super(...arguments),this.type=3}k(e){this.element[this.name]=e===N?void 0:e}}class K extends H{constructor(){super(...arguments),this.type=4}k(e){e&&e!==N?this.element.setAttribute(this.name,\"\"):this.element.removeAttribute(this.name)}}class q extends H{constructor(e,t,r,n,o){super(e,t,r,n,o),this.type=5}_$AI(e,t=this){var r;if((e=null!==(r=U(this,e,t,0))&&void 0!==r?r:N)===F)return;const n=this._$AH,o=e===N&&n!==N||e.capture!==n.capture||e.once!==n.once||e.passive!==n.passive,i=e!==N&&(n===N||o);o&&this.element.removeEventListener(this.name,this,n),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){var t,r;\"function\"==typeof this._$AH?this._$AH.call(null!==(r=null===(t=this.options)||void 0===t?void 0:t.host)&&void 0!==r?r:this.element,e):this._$AH.handleEvent(e)}}class V{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){U(this,e)}}const W={P:\"$lit$\",V:f,L:m,I:1,N:B,R:I,D:x,j:U,H:D,O:H,F:K,B:q,W:Z,Z:V},G=window.litHtmlPolyfillSupport;var Y,J;null==G||G(L,D),(null!==(b=globalThis.litHtmlVersions)&&void 0!==b?b:globalThis.litHtmlVersions=[]).push(\"2.0.1\");class Q extends h{constructor(){super(...arguments),this.renderOptions={host:this},this._$Dt=void 0}createRenderRoot(){var e,t;const r=super.createRenderRoot();return null!==(e=(t=this.renderOptions).renderBefore)&&void 0!==e||(t.renderBefore=r.firstChild),r}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Dt=((e,t,r)=>{var n,o;const i=null!==(n=null==r?void 0:r.renderBefore)&&void 0!==n?n:t;let s=i._$litPart$;if(void 0===s){const e=null!==(o=null==r?void 0:r.renderBefore)&&void 0!==o?o:null;i._$litPart$=s=new D(t.insertBefore(w(),e),e,void 0,null!=r?r:{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!1)}render(){return F}}Q.finalized=!0,Q._$litElement$=!0,null===(Y=globalThis.litElementHydrateSupport)||void 0===Y||Y.call(globalThis,{LitElement:Q});const X=globalThis.litElementPolyfillSupport;null==X||X({LitElement:Q}),(null!==(J=globalThis.litElementVersions)&&void 0!==J?J:globalThis.litElementVersions=[]).push(\"3.0.1\");const ee=(e,t)=>\"method\"===t.kind&&t.descriptor&&!(\"value\"in t.descriptor)?{...t,finisher(r){r.createProperty(t.key,e)}}:{kind:\"field\",key:Symbol(),placement:\"own\",descriptor:{},originalKey:t.key,initializer(){\"function\"==typeof t.initializer&&(this[t.key]=t.initializer.call(this))},finisher(r){r.createProperty(t.key,e)}};function te(e){return(t,r)=>void 0!==r?((e,t,r)=>{t.constructor.createProperty(r,e)})(e,t,r):ee(e,t)}const re=e=>t=>\"function\"==typeof t?((e,t)=>(window.customElements.define(e,t),t))(e,t):((e,t)=>{const{kind:r,elements:n}=t;return{kind:r,elements:n,finisher(t){window.customElements.define(e,t)}}})(e,t);var ne=r(4193),oe=r(2420),ie=r(6773),se=r(5043),ae=r(8325);r(8759),r(5433),r(9980),r(6836),r(9016),r(2503),r(2886),r(9472),r(4335),r(6854),r(9945),r(6488);const le=i(oe.Z),ce=i(ie.Z),de=i(se.Z);function ue(e){return\"function\"==typeof e}function he(e){return function(t){if(function(e){return ue(null==e?void 0:e.lift)}(t))return t.lift((function(t){try{return e(t,this)}catch(e){this.error(e)}}));throw new TypeError(\"Unable to lift unknown Observable type\")}}var be=function(e,t){return be=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},be(e,t)};function pe(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Class extends value \"+String(t)+\" is not a constructor or null\");function r(){this.constructor=e}be(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function ge(e,t){var r,n,o,i,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},\"function\"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){return function(i){if(r)throw new TypeError(\"Generator is already executing.\");for(;s;)try{if(r=1,n&&(o=2&i[0]?n.return:i[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,i[1])).done)return o;switch(n=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,n=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!((o=(o=s.trys).length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]<o[3])){s.label=i[1];break}if(6===i[0]&&s.label<o[1]){s.label=o[1],o=i;break}if(o&&s.label<o[2]){s.label=o[2],s.ops.push(i);break}o[2]&&s.ops.pop(),s.trys.pop();continue}i=t.call(e,s)}catch(e){i=[6,e],n=0}finally{r=o=0}if(5&i[0])throw i[1];return{value:i[0]?i[1]:void 0,done:!0}}([i,a])}}}function fe(e){var t=\"function\"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&\"number\"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function me(e,t){var r=\"function\"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,i=r.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s}function ve(e,t){for(var r=0,n=t.length,o=e.length;r<n;r++,o++)e[o]=t[r];return e}function ye(e){return this instanceof ye?(this.v=e,this):new ye(e)}function we(e,t,r){if(!Symbol.asyncIterator)throw new TypeError(\"Symbol.asyncIterator is not defined.\");var n,o=r.apply(e,t||[]),i=[];return n={},s(\"next\"),s(\"throw\"),s(\"return\"),n[Symbol.asyncIterator]=function(){return this},n;function s(e){o[e]&&(n[e]=function(t){return new Promise((function(r,n){i.push([e,t,r,n])>1||a(e,t)}))})}function a(e,t){try{(r=o[e](t)).value instanceof ye?Promise.resolve(r.value.v).then(l,c):d(i[0][2],r)}catch(e){d(i[0][3],e)}var r}function l(e){a(\"next\",e)}function c(e){a(\"throw\",e)}function d(e,t){e(t),i.shift(),i.length&&a(i[0][0],i[0][1])}}Object.create,Object.create;var ke,$e=((ke=function(e){return function(t){e(this),this.message=t?t.length+\" errors occurred during unsubscription:\\n\"+t.map((function(e,t){return t+1+\") \"+e.toString()})).join(\"\\n  \"):\"\",this.name=\"UnsubscriptionError\",this.errors=t}}((function(e){Error.call(e),e.stack=(new Error).stack}))).prototype=Object.create(Error.prototype),ke.prototype.constructor=ke,ke);function xe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Se=function(){function e(e){this.initialTeardown=e,this.closed=!1,this._parentage=null,this._teardowns=null}return e.prototype.unsubscribe=function(){var e,t,r,n,o;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var s=fe(i),a=s.next();!a.done;a=s.next())a.value.remove(this)}catch(t){e={error:t}}finally{try{a&&!a.done&&(t=s.return)&&t.call(s)}finally{if(e)throw e.error}}else i.remove(this);var l=this.initialTeardown;if(ue(l))try{l()}catch(e){o=e instanceof $e?e.errors:[e]}var c=this._teardowns;if(c){this._teardowns=null;try{for(var d=fe(c),u=d.next();!u.done;u=d.next()){var h=u.value;try{_e(h)}catch(e){o=null!=o?o:[],e instanceof $e?o=ve(ve([],me(o)),me(e.errors)):o.push(e)}}}catch(e){r={error:e}}finally{try{u&&!u.done&&(n=d.return)&&n.call(d)}finally{if(r)throw r.error}}}if(o)throw new $e(o)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)_e(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._teardowns=null!==(r=this._teardowns)&&void 0!==r?r:[]).push(t)}},e.prototype._hasParent=function(e){var t=this._parentage;return t===e||Array.isArray(t)&&t.includes(e)},e.prototype._addParent=function(e){var t=this._parentage;this._parentage=Array.isArray(t)?(t.push(e),t):t?[t,e]:e},e.prototype._removeParent=function(e){var t=this._parentage;t===e?this._parentage=null:Array.isArray(t)&&xe(t,e)},e.prototype.remove=function(t){var r=this._teardowns;r&&xe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=((t=new e).closed=!0,t),e;var t}();function Ae(e){return e instanceof Se||e&&\"closed\"in e&&ue(e.remove)&&ue(e.add)&&ue(e.unsubscribe)}function _e(e){ue(e)?e():e.unsubscribe()}Se.EMPTY;var Me=null,Ce=null,Ee=void 0,Te=!1,Pe=!1,ze={setTimeout:function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];var r=ze.delegate;return((null==r?void 0:r.setTimeout)||setTimeout).apply(void 0,ve([],me(e)))},clearTimeout:function(e){var t=ze.delegate;return((null==t?void 0:t.clearTimeout)||clearTimeout)(e)},delegate:void 0};function je(e){ze.setTimeout((function(){if(!Me)throw e;Me(e)}))}function Fe(){}var Ne=Oe(\"C\",void 0,void 0);function Oe(e,t,r){return{kind:e,value:t,error:r}}var Re=null;function Be(e){Te&&Re&&(Re.errorThrown=!0,Re.error=e)}var Le=function(e){function t(t){var r=e.call(this)||this;return r.isStopped=!1,t?(r.destination=t,Ae(t)&&t.add(r)):r.destination=Ze,r}return pe(t,e),t.create=function(e,t,r){return new Ue(e,t,r)},t.prototype.next=function(e){this.isStopped?He(function(e){return Oe(\"N\",e,void 0)}(e),this):this._next(e)},t.prototype.error=function(e){this.isStopped?He(Oe(\"E\",void 0,e),this):(this.isStopped=!0,this._error(e))},t.prototype.complete=function(){this.isStopped?He(Ne,this):(this.isStopped=!0,this._complete())},t.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,e.prototype.unsubscribe.call(this),this.destination=null)},t.prototype._next=function(e){this.destination.next(e)},t.prototype._error=function(e){try{this.destination.error(e)}finally{this.unsubscribe()}},t.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},t}(Se),Ue=function(e){function t(t,r,n){var o,i=e.call(this)||this;if(ue(t))o=t;else if(t){var s;o=t.next,r=t.error,n=t.complete,i&&Pe?(s=Object.create(t)).unsubscribe=function(){return i.unsubscribe()}:s=t,o=null==o?void 0:o.bind(s),r=null==r?void 0:r.bind(s),n=null==n?void 0:n.bind(s)}return i.destination={next:o?Ie(o):Fe,error:Ie(null!=r?r:De),complete:n?Ie(n):Fe},i}return pe(t,e),t}(Le);function Ie(e,t){return function(){for(var t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];try{e.apply(void 0,ve([],me(t)))}catch(e){Te?Be(e):je(e)}}}function De(e){throw e}function He(e,t){var r=Ce;r&&ze.setTimeout((function(){return r(e,t)}))}var Ze={closed:!0,next:Fe,error:De,complete:Fe},Ke=function(e){function t(t,r,n,o,i){var s=e.call(this,t)||this;return s.onFinalize=i,s._next=r?function(e){try{r(e)}catch(e){t.error(e)}}:e.prototype._next,s._error=o?function(e){try{o(e)}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._error,s._complete=n?function(){try{n()}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._complete,s}return pe(t,e),t.prototype.unsubscribe=function(){var t,r=this.closed;e.prototype.unsubscribe.call(this),!r&&(null===(t=this.onFinalize)||void 0===t||t.call(this))},t}(Le);function qe(e,t){return he((function(r,n){var o=0;r.subscribe(new Ke(n,(function(r){n.next(e.call(t,r,o++))})))}))}var Ve=function(e){return e&&\"number\"==typeof e.length&&\"function\"!=typeof e};function We(e){return ue(null==e?void 0:e.then)}var Ge=\"function\"==typeof Symbol&&Symbol.observable||\"@@observable\";function Ye(e){return e}function Je(e){return 0===e.length?Ye:1===e.length?e[0]:function(t){return e.reduce((function(e,t){return t(e)}),t)}}var Qe=function(){function e(e){e&&(this._subscribe=e)}return e.prototype.lift=function(t){var r=new e;return r.source=this,r.operator=t,r},e.prototype.subscribe=function(e,t,r){var n,o=this,i=(n=e)&&n instanceof Le||function(e){return e&&ue(e.next)&&ue(e.error)&&ue(e.complete)}(n)&&Ae(n)?e:new Ue(e,t,r);return function(e){if(Te){var t=!Re;if(t&&(Re={errorThrown:!1,error:null}),e(),t){var r=Re,n=r.errorThrown,o=r.error;if(Re=null,n)throw o}}else e()}((function(){var e=o,t=e.operator,r=e.source;i.add(t?t.call(i,r):r?o._subscribe(i):o._trySubscribe(i))})),i},e.prototype._trySubscribe=function(e){try{return this._subscribe(e)}catch(t){e.error(t)}},e.prototype.forEach=function(e,t){var r=this;return new(t=Xe(t))((function(t,n){var o;o=r.subscribe((function(t){try{e(t)}catch(e){n(e),null==o||o.unsubscribe()}}),n,t)}))},e.prototype._subscribe=function(e){var t;return null===(t=this.source)||void 0===t?void 0:t.subscribe(e)},e.prototype[Ge]=function(){return this},e.prototype.pipe=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];return Je(e)(this)},e.prototype.toPromise=function(e){var t=this;return new(e=Xe(e))((function(e,r){var n;t.subscribe((function(e){return n=e}),(function(e){return r(e)}),(function(){return e(n)}))}))},e.create=function(t){return new e(t)},e}();function Xe(e){var t;return null!==(t=null!=e?e:Ee)&&void 0!==t?t:Promise}function et(e){return ue(e[Ge])}function tt(e){return Symbol.asyncIterator&&ue(null==e?void 0:e[Symbol.asyncIterator])}function rt(e){return new TypeError(\"You provided \"+(null!==e&&\"object\"==typeof e?\"an invalid object\":\"'\"+e+\"'\")+\" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.\")}var nt=\"function\"==typeof Symbol&&Symbol.iterator?Symbol.iterator:\"@@iterator\";function ot(e){return ue(null==e?void 0:e[nt])}function it(e){return we(this,arguments,(function(){var t,r,n;return ge(this,(function(o){switch(o.label){case 0:t=e.getReader(),o.label=1;case 1:o.trys.push([1,,9,10]),o.label=2;case 2:return[4,ye(t.read())];case 3:return r=o.sent(),n=r.value,r.done?[4,ye(void 0)]:[3,5];case 4:return[2,o.sent()];case 5:return[4,ye(n)];case 6:return[4,o.sent()];case 7:return o.sent(),[3,2];case 8:return[3,10];case 9:return t.releaseLock(),[7];case 10:return[2]}}))}))}function st(e){return ue(null==e?void 0:e.getReader)}function at(e){if(e instanceof Qe)return e;if(null!=e){if(et(e))return o=e,new Qe((function(e){var t=o[Ge]();if(ue(t.subscribe))return t.subscribe(e);throw new TypeError(\"Provided object does not correctly implement Symbol.observable\")}));if(Ve(e))return n=e,new Qe((function(e){for(var t=0;t<n.length&&!e.closed;t++)e.next(n[t]);e.complete()}));if(We(e))return r=e,new Qe((function(e){r.then((function(t){e.closed||(e.next(t),e.complete())}),(function(t){return e.error(t)})).then(null,je)}));if(tt(e))return lt(e);if(ot(e))return t=e,new Qe((function(e){var r,n;try{for(var o=fe(t),i=o.next();!i.done;i=o.next()){var s=i.value;if(e.next(s),e.closed)return}}catch(e){r={error:e}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}e.complete()}));if(st(e))return lt(it(e))}var t,r,n,o;throw rt(e)}function lt(e){return new Qe((function(t){(function(e,t){var r,n,o,i;return function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{l(n.next(e))}catch(e){i(e)}}function a(e){try{l(n.throw(e))}catch(e){i(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}l((n=n.apply(e,t||[])).next())}))}(this,void 0,void 0,(function(){var s,a;return ge(this,(function(l){switch(l.label){case 0:l.trys.push([0,5,6,11]),r=function(e){if(!Symbol.asyncIterator)throw new TypeError(\"Symbol.asyncIterator is not defined.\");var t,r=e[Symbol.asyncIterator];return r?r.call(e):(e=fe(e),t={},n(\"next\"),n(\"throw\"),n(\"return\"),t[Symbol.asyncIterator]=function(){return this},t);function n(r){t[r]=e[r]&&function(t){return new Promise((function(n,o){!function(e,t,r,n){Promise.resolve(n).then((function(t){e({value:t,done:r})}),t)}(n,o,(t=e[r](t)).done,t.value)}))}}}(e),l.label=1;case 1:return[4,r.next()];case 2:if((n=l.sent()).done)return[3,4];if(s=n.value,t.next(s),t.closed)return[2];l.label=3;case 3:return[3,1];case 4:return[3,11];case 5:return a=l.sent(),o={error:a},[3,11];case 6:return l.trys.push([6,,9,10]),n&&!n.done&&(i=r.return)?[4,i.call(r)]:[3,8];case 7:l.sent(),l.label=8;case 8:return[3,10];case 9:if(o)throw o.error;return[7];case 10:return[7];case 11:return t.complete(),[2]}}))}))})(e,t).catch((function(e){return t.error(e)}))}))}function ct(e,t,r,n,o){void 0===n&&(n=0),void 0===o&&(o=!1);var i=t.schedule((function(){r(),o?e.add(this.schedule(null,n)):this.unsubscribe()}),n);if(e.add(i),!o)return i}function dt(e,t,r){return void 0===r&&(r=1/0),ue(t)?dt((function(r,n){return qe((function(e,o){return t(r,e,n,o)}))(at(e(r,n)))}),r):(\"number\"==typeof t&&(r=t),he((function(t,n){return function(e,t,r,n,o,i,s,a){var l=[],c=0,d=0,u=!1,h=function(){!u||l.length||c||t.complete()},b=function(e){return c<n?p(e):l.push(e)},p=function(e){c++;var o=!1;at(r(e,d++)).subscribe(new Ke(t,(function(e){t.next(e)}),(function(){o=!0}),void 0,(function(){if(o)try{c--;for(;l.length&&c<n;)e=void 0,e=l.shift(),p(e);h()}catch(e){t.error(e)}var e})))};return e.subscribe(new Ke(t,b,(function(){u=!0,h()}))),function(){}}(t,n,e,r)})))}function ut(e){return void 0===e&&(e=1/0),dt(Ye,e)}var ht=new Qe((function(e){return e.complete()}));function bt(e){return e[e.length-1]}function pt(e){return(t=bt(e))&&ue(t.schedule)?e.pop():void 0;var t}function gt(e,t){return\"number\"==typeof bt(e)?e.pop():t}function ft(e,t){return void 0===t&&(t=0),he((function(r,n){r.subscribe(new Ke(n,(function(r){return ct(n,e,(function(){return n.next(r)}),t)}),(function(){return ct(n,e,(function(){return n.complete()}),t)}),(function(r){return ct(n,e,(function(){return n.error(r)}),t)})))}))}function mt(e,t){return void 0===t&&(t=0),he((function(r,n){n.add(e.schedule((function(){return r.subscribe(n)}),t))}))}function vt(e,t){if(!e)throw new Error(\"Iterable cannot be null\");return new Qe((function(r){ct(r,t,(function(){var n=e[Symbol.asyncIterator]();ct(r,t,(function(){n.next().then((function(e){e.done?r.complete():r.next(e.value)}))}),0,!0)}))}))}function yt(e,t){return t?function(e,t){if(null!=e){if(et(e))return function(e,t){return at(e).pipe(mt(t),ft(t))}(e,t);if(Ve(e))return function(e,t){return new Qe((function(r){var n=0;return t.schedule((function(){n===e.length?r.complete():(r.next(e[n++]),r.closed||this.schedule())}))}))}(e,t);if(We(e))return function(e,t){return at(e).pipe(mt(t),ft(t))}(e,t);if(tt(e))return vt(e,t);if(ot(e))return function(e,t){return new Qe((function(r){var n;return ct(r,t,(function(){n=e[nt](),ct(r,t,(function(){var e,t,o;try{t=(e=n.next()).value,o=e.done}catch(e){return void r.error(e)}o?r.complete():r.next(t)}),0,!0)})),function(){return ue(null==n?void 0:n.return)&&n.return()}}))}(e,t);if(st(e))return function(e,t){return vt(it(e),t)}(e,t)}throw rt(e)}(e,t):at(e)}var wt=Array.isArray;var kt=[\"addListener\",\"removeListener\"],$t=[\"addEventListener\",\"removeEventListener\"],xt=[\"on\",\"off\"];function St(e,t){return function(r){return function(n){return e[r](t,n)}}}const At=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];var r=pt(e),n=gt(e,1/0),o=e;return o.length?1===o.length?at(o[0]):ut(n)(yt(o,r)):ht}(function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];var r=pt(e);return yt(e,r)}(1),function e(t,r,n,o){if(ue(n)&&(o=n,n=void 0),o)return e(t,r,n).pipe((i=o,qe((function(e){return function(e,t){return wt(t)?e.apply(void 0,ve([],me(t))):e(t)}(i,e)}))));var i,s=me(function(e){return ue(e.addEventListener)&&ue(e.removeEventListener)}(t)?$t.map((function(e){return function(o){return t[e](r,o,n)}})):function(e){return ue(e.addListener)&&ue(e.removeListener)}(t)?kt.map(St(t,r)):function(e){return ue(e.on)&&ue(e.off)}(t)?xt.map(St(t,r)):[],2),a=s[0],l=s[1];if(!a&&Ve(t))return dt((function(t){return e(t,r,n)}))(at(t));if(!a)throw new TypeError(\"Invalid event target\");return new Qe((function(e){var t=function(){for(var t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];return e.next(1<t.length?t:t[0])};return a(t),function(){return l(t)}}))}(window,\"hashchange\").pipe((_t=e=>e.preventDefault(),Et=ue(_t)?{next:_t,error:Mt,complete:Ct}:_t,Et?he((function(e,t){var r;null===(r=Et.subscribe)||void 0===r||r.call(Et);var n=!0;e.subscribe(new Ke(t,(function(e){var r;null===(r=Et.next)||void 0===r||r.call(Et,e),t.next(e)}),(function(){var e;n=!1,null===(e=Et.complete)||void 0===e||e.call(Et),t.complete()}),(function(e){var r;n=!1,null===(r=Et.error)||void 0===r||r.call(Et,e),t.error(e)}),(function(){var e,t;n&&(null===(e=Et.unsubscribe)||void 0===e||e.call(Et)),null===(t=Et.finalize)||void 0===t||t.call(Et)})))})):Ye))).pipe(qe((()=>window.location.hash.substr(1).split(\"/\").filter(Boolean).map(decodeURIComponent))));var _t,Mt,Ct,Et,Tt;!function(e){e.mutant=\"mutant\",e.test=\"test\"}(Tt||(Tt={}));var Pt=r(8986),zt=r(3704);function jt(e,t,r){return new CustomEvent(e,{detail:t,...r})}var Ft=r(9130),Nt=r(9483),Ot=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Rt=class extends Q{constructor(){super(...arguments),this.mode=\"closed\",this.hasDetail=!1,this.toggleReadMore=e=>{\"open\"===this.mode?this.mode=\"half\":this.mode=\"open\",e.preventDefault(),e.stopImmediatePropagation()}}get toggleMoreLabel(){switch(this.mode){case\"half\":return\"🔼 More\";case\"open\":return\"🔽 Less\";case\"closed\":return\"\"}}render(){return z`<aside class=\"h-100 container-fluid\" @click=\"${e=>e.stopPropagation()}\">\n      <div class=\"h-100 row\">\n        <header>\n          <h5>\n            <slot name=\"header\"></slot>\n            ${Bt(this.hasDetail,z`<button data-testId=\"btnReadMoreToggle\" class=\"btn\" @click=\"${this.toggleReadMore}\">${this.toggleMoreLabel}</button>`)}\n          </h5>\n        </header>\n        <div class=\"h-100 overflow-auto col-md-12\">\n          <slot name=\"summary\"></slot>\n          ${Bt(this.hasDetail&&\"open\"===this.mode,z`<slot name=\"detail\"></slot>`)}\n        </div>\n      </div>\n    </aside>`}};function Bt(e,t){return e?\"function\"==typeof t?t():t:void 0}function Lt(e,t){return null==e?void 0:t(e)}function Ut(e){switch(e){case Ft.MutantStatus.Killed:return\"success\";case Ft.MutantStatus.NoCoverage:return\"caution\";case Ft.MutantStatus.Survived:return\"danger\";case Ft.MutantStatus.Timeout:return\"warning\";case Ft.MutantStatus.Ignored:case Ft.MutantStatus.RuntimeError:case Ft.MutantStatus.CompileError:return\"secondary\"}}function It(e){switch(e){case ne.ih.Killing:return\"success\";case ne.ih.Covering:return\"warning\";case ne.ih.NotCovering:return\"caution\"}}function Dt(e){switch(e){case ne.ih.Killing:return\"✅\";case ne.ih.Covering:return\"☂\";case ne.ih.NotCovering:return\"🌧\"}}function Ht(e){switch(e){case Ft.MutantStatus.Killed:return\"✅\";case Ft.MutantStatus.NoCoverage:return\"🙈\";case Ft.MutantStatus.Ignored:return\"🤥\";case Ft.MutantStatus.Survived:return\"👽\";case Ft.MutantStatus.Timeout:return\"⌛\";case Ft.MutantStatus.RuntimeError:case Ft.MutantStatus.CompileError:return\"💥\"}}function Zt(...e){const t=new URL(window.location.href);return new URL(`#${e.filter(Boolean).join(\"/\")}`,t).href}function Kt(e){return e.length>1?\"s\":\"\"}function qt({fileName:e,location:t}){return e?`${e}${t?`:${t.start.line}:${t.start.column}`:\"\"}`:\"\"}function Vt(e){e&&!function(e){const{top:t,bottom:r}=e.getBoundingClientRect();return t>=0&&r<=(window.innerHeight||document.documentElement.clientHeight)-120}(e)&&e.scrollIntoView({block:\"center\",behavior:\"smooth\"})}function Wt(){const e=\"test\";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}}Rt.styles=[le,i(Nt.Z)],Ot([te({reflect:!0})],Rt.prototype,\"mode\",void 0),Ot([te({reflect:!0,type:Boolean})],Rt.prototype,\"hasDetail\",void 0),Ot([te()],Rt.prototype,\"toggleMoreLabel\",null),Rt=Ot([re(\"mte-drawer\")],Rt);var Gt=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Yt=class extends Q{constructor(){super(...arguments),this.context={view:Tt.mutant,path:[]},this.path=[],this.themeSwitch=e=>{this.theme=e.detail,Wt()&&localStorage.setItem(\"mutation-testing-elements-theme\",this.theme)},this.subscriptions=[]}get themeBackgroundColor(){return getComputedStyle(this).getPropertyValue(\"--bs-body-bg\")}get title(){return this.context.result?this.titlePostfix?`${this.context.result.name} - ${this.titlePostfix}`:this.context.result.name:\"\"}firstUpdated(){var e;if(!this.theme){const t=Wt()&&localStorage.getItem(\"mutation-testing-elements-theme\");t?this.theme=t:window.matchMedia&&(null===(e=window.matchMedia(\"(prefers-color-scheme: dark)\"))||void 0===e?void 0:e.matches)?this.theme=\"dark\":this.theme=\"light\"}(0===this.path.length||this.path[0]!==Tt.mutant&&this.path[0]!==Tt.test)&&window.location.replace(Zt(`${Tt.mutant}`))}async loadData(){if(this.src)try{const e=await fetch(this.src);this.report=await e.json()}catch(e){const t=String(e);this.errorMessage=t}}async updated(e){(e.has(\"path\")||e.has(\"report\"))&&this.report&&(this.updateModel(this.report),this.updateContext(),this.updateTitle()),e.has(\"src\")&&await this.loadData(),e.has(\"theme\")&&this.theme&&this.dispatchEvent(jt(\"theme-changed\",{theme:this.theme,themeBackgroundColor:this.themeBackgroundColor}))}updateModel(e){this.rootModel=(0,ne.xR)(e)}updateContext(){if(this.rootModel){const e=(e,t)=>t.reduce(((e,t)=>e&&e.childResults.find((e=>e.name===t))),e),t=this.path.slice(1);this.path[0]===Tt.test&&this.rootModel.testMetrics?this.context={view:Tt.test,path:t,result:e(this.rootModel.testMetrics,this.path.slice(1))}:this.context={view:Tt.mutant,path:t,result:e(this.rootModel.systemUnderTestMetrics,this.path.slice(1))}}}updateTitle(){document.title=this.title}connectedCallback(){super.connectedCallback(),this.subscriptions.push(At.subscribe((e=>this.path=e)))}disconnectedCallback(){super.disconnectedCallback(),this.subscriptions.forEach((e=>e.unsubscribe()))}renderTitle(){if(this.context.result)return z`<h1 class=\"display-4\"\n        >${this.context.result.name}${this.titlePostfix?z`<small class=\"text-muted\"> - ${this.titlePostfix}</small>`:\"\"}</h1\n      >`}render(){return this.context.result||this.errorMessage?z`\n        <div class=\"container-fluid\">\n          <div class=\"row\">\n            <div class=\"col-md-12\">\n              ${this.renderErrorMessage()}\n              <mte-theme-switch @theme-switch=\"${this.themeSwitch}\" class=\"theme-switch\" .theme=\"${this.theme}\"> </mte-theme-switch>\n              ${this.renderTitle()} ${this.renderTabs()}\n              <mte-breadcrumb .view=\"${this.context.view}\" .path=\"${this.context.path}\"></mte-breadcrumb>\n              ${\"mutant\"===this.context.view&&this.context.result?z`<mte-mutant-view\n                    .result=\"${this.context.result}\"\n                    .thresholds=\"${this.report.thresholds}\"\n                    .path=\"${this.path}\"\n                  ></mte-mutant-view>`:\"\"}\n              ${\"test\"===this.context.view&&this.context.result?z`<mte-test-view .result=\"${this.context.result}\" .path=\"${this.path}\"></mte-test-view>`:\"\"}\n            </div>\n          </div>\n        </div>\n      `:z``}renderErrorMessage(){return this.errorMessage?z`<div class=\"alert alert-danger\" role=\"alert\">${this.errorMessage}</div>`:z``}renderTabs(){var e;return(null===(e=this.rootModel)||void 0===e?void 0:e.testMetrics)?z`<nav>\n        <ul class=\"nav nav-tabs border-bottom-0\" role=\"tablist\">\n          <li class=\"nav-item\">\n            <a class=\"nav-link ${\"mutant\"===this.context.view?\"active\":\"\"}\" role=\"tab\" href=\"${Zt(\"mutant\")}\">👽 Mutants</a>\n          </li>\n          <li class=\"nav-item\">\n            <a class=\"nav-link ${\"test\"===this.context.view?\"active\":\"\"}\" role=\"tab\" href=\"${Zt(\"test\")}\">🧪 Tests</a>\n          </li>\n        </ul>\n      </nav>`:void 0}};function Jt(e){return te({...e,state:!0})}Yt.styles=[de,i(zt.Z),le,i(Pt.Z)],Gt([te({attribute:!1})],Yt.prototype,\"report\",void 0),Gt([te({attribute:!1})],Yt.prototype,\"rootModel\",void 0),Gt([te()],Yt.prototype,\"src\",void 0),Gt([te({attribute:!1})],Yt.prototype,\"errorMessage\",void 0),Gt([te({attribute:!1})],Yt.prototype,\"context\",void 0),Gt([te()],Yt.prototype,\"path\",void 0),Gt([te({attribute:\"title-postfix\"})],Yt.prototype,\"titlePostfix\",void 0),Gt([te({reflect:!0})],Yt.prototype,\"theme\",void 0),Gt([te({attribute:!1})],Yt.prototype,\"themeBackgroundColor\",null),Gt([te()],Yt.prototype,\"title\",null),Yt=Gt([re(\"mutation-test-report-app\")],Yt);const{H:Qt}=W,Xt=()=>document.createComment(\"\"),er=(e,t,r)=>{var n;const o=e._$AA.parentNode,i=void 0===t?e._$AB:t._$AA;if(void 0===r){const t=o.insertBefore(Xt(),i),n=o.insertBefore(Xt(),i);r=new Qt(t,n,e,e.options)}else{const t=r._$AB.nextSibling,s=r._$AM,a=s!==e;if(a){let t;null===(n=r._$AQ)||void 0===n||n.call(r,e),r._$AM=e,void 0!==r._$AP&&(t=e._$AU)!==s._$AU&&r._$AP(t)}if(t!==i||a){let e=r._$AA;for(;e!==t;){const t=e.nextSibling;o.insertBefore(e,i),e=t}}}return r},tr=(e,t,r=e)=>(e._$AI(t,r),e),rr={},nr=e=>{var t;null===(t=e._$AP)||void 0===t||t.call(e,!1,!0);let r=e._$AA;const n=e._$AB.nextSibling;for(;r!==n;){const e=r.nextSibling;r.remove(),r=e}},or=e=>(...t)=>({_$litDirective$:e,values:t});class ir{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,r){this._$Ct=e,this._$AM=t,this._$Ci=r}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}const sr=(e,t)=>{var r,n;const o=e._$AN;if(void 0===o)return!1;for(const e of o)null===(n=(r=e)._$AO)||void 0===n||n.call(r,t,!1),sr(e,t);return!0},ar=e=>{let t,r;do{if(void 0===(t=e._$AM))break;r=t._$AN,r.delete(e),e=t}while(0===(null==r?void 0:r.size))},lr=e=>{for(let t;t=e._$AM;e=t){let r=t._$AN;if(void 0===r)t._$AN=r=new Set;else if(r.has(e))break;r.add(e),ur(t)}};function cr(e){void 0!==this._$AN?(ar(this),this._$AM=e,lr(this)):this._$AM=e}function dr(e,t=!1,r=0){const n=this._$AH,o=this._$AN;if(void 0!==o&&0!==o.size)if(t)if(Array.isArray(n))for(let e=r;e<n.length;e++)sr(n[e],!1),ar(n[e]);else null!=n&&(sr(n,!1),ar(n));else sr(this,e)}const ur=e=>{var t,r,n,o;2==e.type&&(null!==(t=(n=e)._$AP)&&void 0!==t||(n._$AP=dr),null!==(r=(o=e)._$AQ)&&void 0!==r||(o._$AQ=cr))};class hr extends ir{constructor(){super(...arguments),this._$AN=void 0}_$AT(e,t,r){super._$AT(e,t,r),lr(this),this.isConnected=e._$AU}_$AO(e,t=!0){var r,n;e!==this.isConnected&&(this.isConnected=e,e?null===(r=this.reconnected)||void 0===r||r.call(this):null===(n=this.disconnected)||void 0===n||n.call(this)),t&&(sr(this,e),ar(this))}setValue(e){if((e=>void 0===this._$Ct.strings)())this._$Ct._$AI(e,this);else{const t=[...this._$Ct._$AH];t[this._$Ci]=e,this._$Ct._$AI(t,this,0)}}disconnected(){}reconnected(){}}class br{}const pr=new WeakMap,gr=or(class extends hr{render(e){return N}update(e,[t]){var r;const n=t!==this.U;return n&&void 0!==this.U&&this.nt(void 0),(n||this.rt!==this.lt)&&(this.U=t,this.ht=null===(r=e.options)||void 0===r?void 0:r.host,this.nt(this.lt=e.element)),N}nt(e){\"function\"==typeof this.U?(void 0!==pr.get(this.U)&&this.U.call(this.ht,void 0),pr.set(this.U,e),void 0!==e&&this.U.call(this.ht,e)):this.U.value=e}get rt(){var e;return\"function\"==typeof this.U?pr.get(this.U):null===(e=this.U)||void 0===e?void 0:e.value}disconnected(){this.rt===this.lt&&this.nt(void 0)}reconnected(){this.nt(this.lt)}});class fr extends ir{constructor(e){if(super(e),this.it=N,2!==e.type)throw Error(this.constructor.directiveName+\"() can only be used in child bindings\")}render(e){if(e===N||null==e)return this.vt=void 0,this.it=e;if(e===F)return e;if(\"string\"!=typeof e)throw Error(this.constructor.directiveName+\"() called with a non-string value\");if(e===this.it)return this.vt;this.it=e;const t=[e];return t.raw=t,this.vt={_$litType$:this.constructor.resultType,strings:t,values:[]}}}fr.directiveName=\"unsafeHTML\",fr.resultType=1;const mr=or(fr);var vr,yr;function wr(e){switch(function(e){return e.substr(e.lastIndexOf(\".\")+1).toLocaleLowerCase()}(e)){case\"cs\":return vr.csharp;case\"html\":return vr.html;case\"java\":return vr.java;case\"js\":case\"cjs\":case\"mjs\":return vr.javascript;case\"ts\":case\"tsx\":case\"cts\":case\"mts\":return vr.typescript;case\"scala\":return vr.scala;case\"php\":return vr.php;case\"vue\":return vr.vue;case\"feature\":return vr.gherkin;default:return}}function kr(e,t){var r;const n=null!==(r=wr(t))&&void 0!==r?r:\"plain\";let o=n;return n===vr.vue&&(o=vr.html),(0,ae.highlight)(e,ae.languages[o],o)}function $r(e,t){let r=[];const n=[],o={column:0,line:1,offset:-1},i=[];let s=!1,a=0;for(;a<e.length;){switch(s&&!xr(e[a])&&(i.forEach((e=>l(c(e)))),s=!1),e[a]){case yr.CarriageReturn:o.offset++;break;case yr.NewLine:d(),o.offset++,o.line++,o.column=0,s=!0;break;case yr.LT:{const e=h();e.isClosing?p(e):b(e);break}case yr.Amp:u(f());break;default:u(e[a])}a++}return d(),n;function l(...e){r.push(...e)}function c({attributes:e,elementName:t,isClosing:r}){return r?`</${t}>`:`<${t}${Object.entries(null!=e?e:{}).reduce(((e,[t,r])=>void 0===r?`${e} ${t}`:`${e} ${t}=\"${r}\"`),\"\")}>`}function d(){i.forEach((e=>l(c({...e,isClosing:!0})))),n.push(r.join(\"\")),r=[]}function u(e){if(o.column++,o.offset++,t)for(const e of t(o))e.isClosing?p(e):(l(c(e)),i.push(e));l(e)}function h(){a++;const t=\"/\"===e[a]||void 0;t&&a++;const r=a;for(;!xr(e[a])&&e[a]!==yr.GT;)a++;return{elementName:e.substring(r,a),attributes:function(){const t=Object.create(null);for(;a<e.length;){const r=e[a];if(r===yr.GT)return t;if(!xr(r)){const{name:e,value:r}=g();t[e]=r}a++}throw new Error(`Missing closing tag near ${e.substr(a-10)}`)}(),isClosing:t}}function b(e){i.push(e),l(c(e))}function p(e){let t;for(t=i.length-1;t>=0;t--){const r=i[t];if(e.elementName===r.elementName&&r.id===e.id){l(c(e)),i.splice(t,1);for(let e=t;e<i.length;e++)l(c(i[e]));break}l(c({...r,isClosing:!0}))}if(-1===t)throw new Error(`Cannot find corresponding opening tag for ${c(e)}`)}function g(){const t=a;for(;\"=\"!==e[a];)a++;const r=e.substring(t,a);a++;const n=function(){'\"'===e[a]&&a++;const t=a;for(;'\"'!==e[a];)a++;return e.substring(t,a)}();return{name:r,value:n}}function f(){const t=a;for(;e[a]!==yr.Semicolon;)a++;return e.substring(t,a+1)}}function xr(e){return e===yr.NewLine||e===yr.Space||e===yr.Tab}function Sr(e,t){return e.line>t.line||e.line===t.line&&e.column>=t.column}!function(e){e.csharp=\"cs\",e.java=\"java\",e.javascript=\"javascript\",e.html=\"html\",e.php=\"php\",e.scala=\"scala\",e.typescript=\"typescript\",e.vue=\"vue\",e.gherkin=\"gherkin\"}(vr||(vr={})),function(e){e.CarriageReturn=\"\\r\",e.NewLine=\"\\n\",e.Space=\" \",e.Amp=\"&\",e.Semicolon=\";\",e.LT=\"<\",e.GT=\">\",e.Tab=\"\\t\"}(yr||(yr={}));var Ar=r(5545),_r=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};const Mr=\"diff-old\";let Cr=class extends Q{constructor(){super(...arguments),this.filters=[],this.selectedMutantStates=[],this.lines=[],this.mutants=[],this.codeRef=new br,this.filtersChanged=e=>{this.selectedMutantStates=e.detail},this.codeClicked=e=>{if(e.stopPropagation(),e.target instanceof Element){let t=e.target;const r=[];for(;t instanceof Element;t=t.parentElement){const e=t.getAttribute(\"mutant-id\"),n=this.mutants.find((({id:t})=>t.toString()===e));n&&r.push(n)}const n=(this.selectedMutant?r.indexOf(this.selectedMutant):-1)+1;r[n]?(this.toggleMutant(r[n]),Tr()):this.selectedMutant&&(this.toggleMutant(this.selectedMutant),Tr())}},this.nextMutant=()=>{const e=this.selectedMutant?(this.mutants.indexOf(this.selectedMutant)+1)%this.mutants.length:0;this.mutants[e]&&this.toggleMutant(this.mutants[e])},this.previousMutant=()=>{const e=this.selectedMutant?(this.mutants.indexOf(this.selectedMutant)+this.mutants.length-1)%this.mutants.length:this.mutants.length-1;this.mutants[e]&&this.toggleMutant(this.mutants[e])}}render(){const e=new Map;for(const t of this.mutants){let r=e.get(t.location.start.line);r||(r=[],e.set(t.location.start.line,r)),r.push(t)}const t=t=>this.renderMutantDots([...e.entries()].filter((([e])=>e>t)).flatMap((([,e])=>e)));return z`\n      <div class=\"row\">\n        <div class=\"col-md-12\">\n          <mte-state-filter\n            allow-toggle-all\n            .filters=\"${this.filters}\"\n            @filters-changed=\"${this.filtersChanged}\"\n            @next=${this.nextMutant}\n            @previous=${this.previousMutant}\n          ></mte-state-filter>\n          <pre\n            @click=\"${this.codeClicked}\"\n            id=\"report-code-block\"\n            class=\"line-numbers ${this.selectedMutantStates.map((e=>`mte-selected-${e}`)).join(\" \")}\"\n          ><code ${gr(this.codeRef)} class=\"language-${this.model.language}\"><table>${this.lines.map(((r,n)=>{const o=n+1;return z`<tr class=\"line\"\n              ><td class=\"line-number\"></td><td class=\"line-marker\"></td\n              ><td class=\"code\"\n                >${mr(r)}${this.renderMutantDots(e.get(o))}${this.lines.length===o?t(o):\"\"}</td\n              ></tr\n            >`}))}</table></code></pre>\n        </div>\n      </div>\n    `}renderMutantDots(e){return z`${null==e?void 0:e.map((e=>{var t;return j`<svg mutant-id=\"${e.id}\" class=\"mutant-dot ${(null===(t=this.selectedMutant)||void 0===t?void 0:t.id)===e.id?\"selected\":e.status}\" height=\"10\" width=\"10\">\n          <title>${Er(e)}</title>\n          <circle cx=\"5\" cy=\"5\" r=\"5\" />\n          </svg>`}))}`}toggleMutant(e){if(this.removeCurrentDiff(),this.selectedMutant===e)return this.selectedMutant=void 0,void this.dispatchEvent(jt(\"mutant-selected\",{selected:!1,mutant:e}));this.selectedMutant=e;const t=this.codeRef.value.querySelectorAll(\"tr.line\");for(let r=e.location.start.line-1;r<e.location.end.line;r++)t.item(r).classList.add(Mr);const r=this.highlightedReplacementRows(e),n=t.item(e.location.end.line-1);n.insertAdjacentHTML(\"afterend\",r),Vt(n),this.dispatchEvent(jt(\"mutant-selected\",{selected:!0,mutant:e}))}removeCurrentDiff(){this.codeRef.value.querySelectorAll(\".diff-old\").forEach((e=>e.classList.remove(Mr))),this.codeRef.value.querySelectorAll(\".diff-new\").forEach((e=>e.remove()))}update(e){if(e.has(\"model\")&&this.model){this.filters=[Ft.MutantStatus.Killed,Ft.MutantStatus.Survived,Ft.MutantStatus.NoCoverage,Ft.MutantStatus.Ignored,Ft.MutantStatus.Timeout,Ft.MutantStatus.CompileError,Ft.MutantStatus.RuntimeError].filter((e=>this.model.mutants.some((t=>t.status===e)))).map((e=>({enabled:[Ft.MutantStatus.Survived,Ft.MutantStatus.NoCoverage,Ft.MutantStatus.Timeout].includes(e),count:this.model.mutants.filter((t=>t.status===e)).length,status:e,label:`${Ht(e)} ${e}`,context:Ut(e)})));const e=kr(this.model.source,this.model.name),t=new Set,r=new Set(this.model.mutants);this.lines=$r(e,(function*(e){for(const r of t)Sr(e,r.location.end)&&(t.delete(r),yield{elementName:\"span\",id:r.id,isClosing:!0});for(const n of r)Sr(e,n.location.start)&&(t.add(n),r.delete(n),yield{elementName:\"span\",id:n.id,attributes:{class:`mutant ${n.status}`,title:Er(n),\"mutant-id\":n.id}})}))}(e.has(\"model\")&&this.model||e.has(\"selectedMutantStates\"))&&(this.mutants=this.model.mutants.filter((e=>this.selectedMutantStates.includes(e.status))).sort(((e,t)=>Sr(e.location.start,t.location.start)?1:-1)),this.selectedMutant&&!this.mutants.includes(this.selectedMutant)&&this.toggleMutant(this.selectedMutant)),super.update(e)}highlightedReplacementRows(e){const t=e.getMutatedLines().trimEnd(),r=e.getOriginalLines().trimEnd(),[n,o]=function(e,t){let r=0,n=t.length-1;for(;e[r]===t[r]&&r<t.length;)r++;const o=e.length-t.length;for(;e[n+o]===t[n]&&n>r;)n--;n===r&&(xr(t[r-1])||r--),n++;const i=t.substring(r,n);return[\"true\",\"false\"].forEach((e=>{i===e.substr(0,e.length-1)&&e[e.length-1]===t[n]&&n++,i===e.substr(1,e.length)&&e[0]===t[r-1]&&r--})),[r,n]}(r,t);return $r(kr(t,this.model.name),(function*({offset:e}){e===n?yield{elementName:\"span\",id:\"diff-focus\",attributes:{class:\"diff-focus\"}}:e===o&&(yield{elementName:\"span\",id:\"diff-focus\",isClosing:!0})})).map((e=>`<tr class=\"diff-new\"><td class=\"empty-line-number\"></td><td class=\"line-marker\"></td><td class=\"code\">${e}</td></tr>`)).join(\"\")}};function Er(e){return`${e.mutatorName} ${e.status}`}function Tr(){var e;null===(e=window.getSelection())||void 0===e||e.removeAllRanges()}Cr.styles=[ce,le,i(Ar.Z)],_r([Jt()],Cr.prototype,\"filters\",void 0),_r([te()],Cr.prototype,\"model\",void 0),_r([Jt()],Cr.prototype,\"selectedMutantStates\",void 0),_r([Jt()],Cr.prototype,\"selectedMutant\",void 0),_r([Jt()],Cr.prototype,\"lines\",void 0),_r([Jt()],Cr.prototype,\"mutants\",void 0),Cr=_r([re(\"mte-file\")],Cr);var Pr=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let zr=class extends Q{get rootName(){switch(this.view){case Tt.mutant:return\"All files\";case Tt.test:return\"All tests\"}}render(){return z`\n      <ol class=\"breadcrumb rounded\">\n        ${this.path&&this.path.length>0?this.renderLink(this.rootName,[]):this.renderActiveItem(this.rootName)}\n        ${this.renderBreadcrumbItems()}\n      </ol>\n    `}renderBreadcrumbItems(){if(this.path){const e=this.path;return e.map(((t,r)=>r===e.length-1?this.renderActiveItem(t):this.renderLink(t,e.slice(0,r+1))))}}renderActiveItem(e){return z` <li class=\"breadcrumb-item active\" aria-current=\"page\">${e}</li> `}renderLink(e,t){return z` <li class=\"breadcrumb-item\"><a href=\"${Zt(this.view,...t)}\">${e}</a></li> `}};zr.styles=[le],Pr([te()],zr.prototype,\"path\",void 0),Pr([te()],zr.prototype,\"view\",void 0),zr=Pr([re(\"mte-breadcrumb\")],zr);const jr=(e,t,r)=>{const n=new Map;for(let o=t;o<=r;o++)n.set(e[o],o);return n},Fr=or(class extends ir{constructor(e){if(super(e),2!==e.type)throw Error(\"repeat() can only be used in text expressions\")}dt(e,t,r){let n;void 0===r?r=t:void 0!==t&&(n=t);const o=[],i=[];let s=0;for(const t of e)o[s]=n?n(t,s):s,i[s]=r(t,s),s++;return{values:i,keys:o}}render(e,t,r){return this.dt(e,t,r).values}update(e,[t,r,n]){var o;const i=(e=>e._$AH)(e),{values:s,keys:a}=this.dt(t,r,n);if(!Array.isArray(i))return this.ct=a,s;const l=null!==(o=this.ct)&&void 0!==o?o:this.ct=[],c=[];let d,u,h=0,b=i.length-1,p=0,g=s.length-1;for(;h<=b&&p<=g;)if(null===i[h])h++;else if(null===i[b])b--;else if(l[h]===a[p])c[p]=tr(i[h],s[p]),h++,p++;else if(l[b]===a[g])c[g]=tr(i[b],s[g]),b--,g--;else if(l[h]===a[g])c[g]=tr(i[h],s[g]),er(e,c[g+1],i[h]),h++,g--;else if(l[b]===a[p])c[p]=tr(i[b],s[p]),er(e,i[h],i[b]),b--,p++;else if(void 0===d&&(d=jr(a,p,g),u=jr(l,h,b)),d.has(l[h]))if(d.has(l[b])){const t=u.get(a[p]),r=void 0!==t?i[t]:null;if(null===r){const t=er(e,i[h]);tr(t,s[p]),c[p]=t}else c[p]=tr(r,s[p]),er(e,i[h],r),i[t]=null;p++}else nr(i[b]),b--;else nr(i[h]),h++;for(;p<=g;){const t=er(e,c[g+1]);tr(t,s[p]),c[p++]=t}for(;h<=b;){const e=i[h++];null!==e&&nr(e)}return this.ct=a,((e,t=rr)=>{e._$AH=t})(e,c),F}});var Nr=r(1276),Or=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Rr=class extends Q{constructor(){super(...arguments),this.next=e=>{e.stopPropagation(),this.dispatchEvent(jt(\"next\",void 0,{bubbles:!0,composed:!0}))},this.previous=e=>{e.stopPropagation(),this.dispatchEvent(jt(\"previous\",void 0,{bubbles:!0,composed:!0}))}}updated(e){e.has(\"filters\")&&this.dispatchFiltersChangedEvent()}checkboxChanged(e,t){e.enabled=t,this.dispatchFiltersChangedEvent()}dispatchFiltersChangedEvent(){this.dispatchEvent(jt(\"filters-changed\",this.filters.filter((({enabled:e})=>e)).map((({status:e})=>e))))}render(){return z`\n      <div class=\"legend col-md-12 d-flex align-items-center\">\n        <div class=\"d-flex me-2\">\n          <button title=\"Previous\" @click=${this.previous} class=\"me-1 btn btn-sm btn-secondary mte-previous\" type=\"button\">&lt;</button>\n          <button title=\"Next\" @click=${this.next} class=\"btn btn-sm btn-secondary mte-next\" type=\"button\">&gt;</button>\n        </div>\n\n        ${this.filters&&Fr(this.filters,(e=>JSON.stringify(e)),(e=>z`<div data-status=\"${e.status}\" class=\"form-check form-check-inline\">\n            <label class=\"form-check-label\">\n              <input\n                class=\"form-check-input\"\n                type=\"checkbox\"\n                ?checked=\"${e.enabled}\"\n                value=\"${e.status}\"\n                @input=\"${t=>this.checkboxChanged(e,t.target.checked)}\"\n              />\n              <span class=\"badge bg-${e.context}\">${e.label} (${e.count})</span>\n            </label>\n          </div>`))}\n      </div>\n    `}};Rr.styles=[le,i(Nr.Z)],Or([te({type:Array})],Rr.prototype,\"filters\",void 0),Rr=Or([re(\"mte-state-filter\")],Rr);var Br=r(4835),Lr=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Ur=class extends Q{constructor(){super(...arguments),this.dispatchThemeChangedEvent=e=>{const t=e.target.checked;this.dispatchEvent(jt(\"theme-switch\",t?\"dark\":\"light\"))}}render(){return z`\n      <div class=\"check-box-container\" @click=\"${e=>e.stopPropagation()}\">\n        <input type=\"checkbox\" @click=\"${this.dispatchThemeChangedEvent}\" ?checked=\"${\"dark\"==this.theme}\" id=\"darkTheme\" />\n        <label for=\"darkTheme\">Dark</label>\n      </div>\n    `}};Ur.styles=[le,i(Br.Z)],Lr([te()],Ur.prototype,\"theme\",void 0),Ur=Lr([re(\"mte-theme-switch\")],Ur);var Ir=r(371),Dr=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};const Hr=e=>z`${e.name}${e.sourceFile&&e.location?` (${qt(e)})`:\"\"}`;let Zr=class extends Q{constructor(){super(...arguments),this.mode=\"closed\"}render(){var e,t;return z`<mte-drawer ?hasDetail=\"${(null===(e=this.mutant)||void 0===e?void 0:e.killedByTests)||(null===(t=this.mutant)||void 0===t?void 0:t.coveredByTests)}\" .mode=\"${this.mode}\">\n      ${Lt(this.mutant,(e=>z`\n          <span slot=\"header\"\n            >${e.id} ${Ht(e.status)} ${e.mutatorName} ${e.status}\n            (${e.location.start.line}:${e.location.start.column})</span\n          >\n          <span slot=\"summary\">${this.renderSummary()}</span>\n          <span slot=\"detail\">${this.renderDetail()}</span>\n        `))}\n    </mte-drawer>`}renderSummary(){var e,t,r,n,o,i,s;return z`<div class=\"d-flex mx-2\">\n      ${(null===(t=null===(e=this.mutant)||void 0===e?void 0:e.killedByTests)||void 0===t?void 0:t[0])?z`<h6 class=\"pe-4\"\n            >🎯 Killed by: ${null===(r=this.mutant.killedByTests)||void 0===r?void 0:r[0].name}\n            ${this.mutant.killedByTests.length>1?z`(and ${this.mutant.killedByTests.length-1} more)`:void 0}</h6\n          >`:void 0}\n      ${Bt(null===(n=this.mutant)||void 0===n?void 0:n.static,z`<h6 class=\"pe-4\">🗿 Static mutant</h6>`)}\n      ${Lt(null===(o=this.mutant)||void 0===o?void 0:o.coveredByTests,(e=>{var t;return z`<h6 class=\"pe-4\"\n            >☂️ Covered by ${e.length} test${Kt(e)}\n            ${Bt((null===(t=this.mutant)||void 0===t?void 0:t.status)===Ft.MutantStatus.Survived,\"(yet still survived)\")}</h6\n          >`}))}\n      ${Lt(null===(i=this.mutant)||void 0===i?void 0:i.statusReason,(e=>z`<h6 class=\"pe-4\" title=\"Reason for the ${this.mutant.status} status\">🕵️ ${e}</h6>`))}\n      ${Lt(null===(s=this.mutant)||void 0===s?void 0:s.description,(e=>z`<h6 class=\"pe-4\">📖 ${e}</h6>`))}\n    </div>`}renderDetail(){var e,t,r,n;return z`<ul class=\"list-group\">\n      ${null===(t=null===(e=this.mutant)||void 0===e?void 0:e.killedByTests)||void 0===t?void 0:t.map((e=>z`<li title=\"This mutant was killed by this test\" class=\"list-group-item\">🎯 ${Hr(e)}</li>`))}\n      ${null===(n=null===(r=this.mutant)||void 0===r?void 0:r.coveredByTests)||void 0===n?void 0:n.filter((e=>{var t,r;return!(null===(r=null===(t=this.mutant)||void 0===t?void 0:t.killedByTests)||void 0===r?void 0:r.includes(e))})).map((e=>z`<li class=\"list-group-item\" title=\"This mutant was covered by this test\">☂️ ${Hr(e)}</li>`))}\n    </ul>`}};Zr.styles=[le,i(Ir.Z)],Dr([te()],Zr.prototype,\"mutant\",void 0),Dr([te({reflect:!0})],Zr.prototype,\"mode\",void 0),Zr=Dr([re(\"mte-drawer-mutant\")],Zr);var Kr=r(3813),qr=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Vr=class extends Q{constructor(){super(...arguments),this.drawerMode=\"closed\",this.handleClick=()=>{this.drawerMode=\"closed\"},this.handleMutantSelected=e=>{this.selectedMutant=e.detail.mutant,this.drawerMode=e.detail.selected?\"half\":\"closed\"}}updated(e){e.has(\"result\")&&!this.result.file&&(this.drawerMode=\"closed\")}render(){return z`\n      <main @click=\"${this.handleClick}\">\n        <div class=\"row\">\n          <div class=\"totals col-sm-11\">\n            <mte-metrics-table .columns=\"${Wr}\" .currentPath=\"${this.path}\" .thresholds=\"${this.thresholds}\" .model=\"${this.result}\">\n            </mte-metrics-table>\n          </div>\n        </div>\n        ${this.result.file?z`<mte-file @mutant-selected=\"${this.handleMutantSelected}\" .model=\"${this.result.file}\"></mte-file>`:\"\"}\n      </main>\n      <mte-drawer-mutant .mode=\"${this.drawerMode}\" .mutant=\"${this.selectedMutant}\"></mte-drawer-mutant>\n    `}};Vr.styles=[le,i(Kr.Z)],qr([te()],Vr.prototype,\"drawerMode\",void 0),qr([te()],Vr.prototype,\"selectedMutant\",void 0),qr([te()],Vr.prototype,\"result\",void 0),qr([te({attribute:!1,reflect:!1})],Vr.prototype,\"thresholds\",void 0),qr([te({attribute:!1,reflect:!1})],Vr.prototype,\"path\",void 0),Vr=qr([re(\"mte-mutant-view\")],Vr);const Wr=[{key:\"mutationScore\",label:\"Mutation score\",tooltip:\"The percentage of mutants that were detected. The higher, the better!\",category:\"percentage\"},{key:\"killed\",label:\"# Killed\",tooltip:\"At least one test failed while these mutants were active. This is what you want!\",category:\"number\"},{key:\"survived\",label:\"# Survived\",tooltip:\"All tests passed while these mutants were active. You're missing a test for them.\",category:\"number\"},{key:\"timeout\",label:\"# Timeout\",tooltip:\"Running the tests while these mutants were active resulted in a timeout. For example, an infinite loop.\",category:\"number\"},{key:\"noCoverage\",label:\"# No coverage\",tooltip:\"These mutants aren't covered by one of your tests and survived as a result.\",category:\"number\"},{key:\"ignored\",label:\"# Ignored\",tooltip:\"These mutants weren't tested because they are ignored. Either by user action, or for another reason.\",category:\"number\"},{key:\"runtimeErrors\",label:\"# Runtime errors\",tooltip:\"Running tests when these mutants are active resulted in an error (rather than a failed test). For example: an out of memory error.\",category:\"number\"},{key:\"compileErrors\",label:\"# Compile errors\",tooltip:\"Mutants that caused a compile error.\",category:\"number\"},{key:\"totalDetected\",label:\"Total detected\",tooltip:\"The number of mutants detected by your tests (killed + timeout).\",category:\"number\",width:\"large\",isHeader:!0},{key:\"totalUndetected\",label:\"Total undetected\",tooltip:\"The number of mutants that are not detected by your tests (survived + no coverage).\",category:\"number\",width:\"large\",isHeader:!0},{key:\"totalMutants\",label:\"Total mutants\",tooltip:\"All mutants (valid + invalid + ignored)\",category:\"number\",width:\"large\",isHeader:!0}];var Gr=r(9827),Yr=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let Jr=class extends Q{constructor(){super(...arguments),this.drawerMode=\"closed\",this.handleClick=()=>{this.drawerMode=\"closed\"},this.handleTestSelected=e=>{this.selectedTest=e.detail.test,this.drawerMode=e.detail.selected?\"half\":\"closed\"}}updated(e){e.has(\"result\")&&!this.result.file&&(this.drawerMode=\"closed\")}render(){return z`\n      <main @click=\"${this.handleClick}\">\n        <div class=\"row\">\n          <div class=\"totals col-sm-11\">\n            <mte-metrics-table .columns=\"${Qr}\" .currentPath=\"${this.path}\" .model=\"${this.result}\"> </mte-metrics-table>\n          </div>\n        </div>\n        ${this.result.file?z`<mte-test-file @test-selected=\"${this.handleTestSelected}\" .model=\"${this.result.file}\"></mte-test-file>`:\"\"}\n      </main>\n      <mte-drawer-test .mode=\"${this.drawerMode}\" .test=\"${this.selectedTest}\"></mte-drawer-test>\n    `}};Jr.styles=[le,i(Gr.Z)],Yr([te()],Jr.prototype,\"drawerMode\",void 0),Yr([te()],Jr.prototype,\"result\",void 0),Yr([te({attribute:!1,reflect:!1})],Jr.prototype,\"path\",void 0),Yr([te()],Jr.prototype,\"selectedTest\",void 0),Jr=Yr([re(\"mte-test-view\")],Jr);const Qr=[{key:\"killing\",label:\"# Killing\",tooltip:\"These tests killed at least one mutant\",width:\"normal\",category:\"number\"},{key:\"covering\",label:\"# Covering\",tooltip:\"These tests are covering at least one mutant, but not killing any of them.\",width:\"normal\",category:\"number\"},{key:\"notCovering\",label:\"# Not Covering\",tooltip:\"These tests were not covering a mutant (and thus not killing any of them).\",width:\"normal\",category:\"number\"},{key:\"total\",label:\"Total tests\",width:\"large\",category:\"number\",isHeader:!0}];var Xr=r(8469),en=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let tn=class extends Q{constructor(){super(...arguments),this.currentPath=[],this.thresholds={high:80,low:60}}render(){return z`${this.model?z`<table class=\"table table-hover table-no-top\">${this.renderTableHeadRow()}${this.renderTableBody(this.model)}</table>`:\"\"}`}renderTableHeadRow(){return z`<thead>\n      <th scope=\"col\" colspan=\"2\" style=\"width: 217px\">\n        <div\n          ><span>File / Directory</span\n          ><a\n            href=\"https://stryker-mutator.io/docs/mutation-testing-elements/mutant-states-and-metrics\"\n            target=\"_blank\"\n            class=\"info-icon\"\n            title=\"What does this all mean?\"\n            >ℹ</a\n          ></div\n        >\n      </th>\n      ${this.columns.map((e=>this.renderTableHead(e)))}\n    </thead>`}renderTableHead(e){const t=e.tooltip?z`<mte-tooltip title=\"${e.tooltip}\">${e.label}</mte-tooltip>`:z`<span>${e.label}</span>`;return\"percentage\"===e.category?z` <th colspan=\"2\"> ${t} </th>`:z`<th class=\"rotate text-center\" style=\"width: ${\"large\"===e.width?70:50}px\">\n      <div>${t}</div>\n    </th>`}renderTableBody(e){return z`<tbody>${this.renderRow(e.name,e)} ${(()=>e.file?void 0:e.childResults.map((e=>{const t=[e.name];for(;!e.file&&1===e.childResults.length;)e=e.childResults[0],t.push(e.name);return this.renderRow(t.join(\"/\"),e,...this.currentPath,...t)})))()}</tbody>`}renderRow(e,t,...r){return z`<tr title=\"${t.name}\" class=\"align-middle\">\n      <td style=\"width: 32px;\" class=\"icon\"><mte-file-icon file-name=\"${t.name}\" ?file=\"${t.file}\"></mte-file-icon></td>\n      <td>${r.length>0?z`<a href=\"${Zt(...r)}\">${e}</a>`:z`<span>${t.name}</span>`}</td>\n      ${this.columns.map((e=>this.renderCell(e,t.metrics)))}\n    </tr>`}renderCell(e,t){const r=t[e.key];if(\"percentage\"===e.category){const e=!isNaN(r),t=this.determineColoringClass(r),n=r.toFixed(2),o=`width: ${r}%`;return z`<td>\n          ${e?z` <div class=\"progress\">\n                <div\n                  class=\"progress-bar bg-${t}\"\n                  role=\"progressbar\"\n                  aria-valuenow=\"${n}\"\n                  aria-valuemin=\"0\"\n                  aria-valuemax=\"100\"\n                  style=\"${o}\"\n                >\n                  ${n}%\n                </div>\n              </div>`:z` <span class=\"fw-bold text-muted\">N/A</span> `}\n        </td>\n        <td style=\"width: 50px;\" class=\"fw-bold text-center text-${t}\">${e?n:void 0}</td>`}return e.isHeader?z`<th class=\"text-center\">${r}</th>`:z`<td class=\"text-center\">${r}</td>`}determineColoringClass(e){return!isNaN(e)&&this.thresholds?e<this.thresholds.low?\"danger\":e<this.thresholds.high?\"warning\":\"success\":\"default\"}};tn.styles=[le,i(Xr.Z)],en([te()],tn.prototype,\"model\",void 0),en([te()],tn.prototype,\"currentPath\",void 0),en([te({type:Array})],tn.prototype,\"columns\",void 0),en([te()],tn.prototype,\"thresholds\",void 0),tn=en([re(\"mte-metrics-table\")],tn);var rn=r(5110),nn=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let on=class extends Q{constructor(){super(...arguments),this.filters=[],this.lines=[],this.enabledStates=[],this.tests=[],this.filtersChanged=e=>{this.enabledStates=e.detail,this.selectedTest&&!this.enabledStates.includes(this.selectedTest.status)&&this.toggleTest(this.selectedTest)},this.nextTest=()=>{const e=this.selectedTest?(this.tests.findIndex((({id:e})=>e===this.selectedTest.id))+1)%this.tests.length:0;this.selectTest(this.tests[e])},this.previousTest=()=>{const e=this.selectedTest?(this.tests.findIndex((({id:e})=>e===this.selectedTest.id))+this.tests.length-1)%this.tests.length:this.tests.length-1;this.selectTest(this.tests[e])}}toggleTest(e){this.selectedTest===e?(this.selectedTest=void 0,this.dispatchEvent(jt(\"test-selected\",{selected:!1,test:e}))):(this.selectedTest=e,this.dispatchEvent(jt(\"test-selected\",{selected:!0,test:e})),Vt(this.shadowRoot.querySelector(`[test-id=\"${e.id}\"]`)))}selectTest(e){e&&this.toggleTest(e)}render(){return z`\n      <div class=\"row\">\n        <div class=\"col-md-12\">\n          <mte-state-filter\n            @next=${this.nextTest}\n            @previous=${this.previousTest}\n            .filters=\"${this.filters}\"\n            @filters-changed=\"${this.filtersChanged}\"\n          ></mte-state-filter>\n          ${this.renderTestList()} ${this.renderCode()}\n        </div>\n      </div>\n    `}renderTestList(){const e=this.tests.filter((e=>!e.location));if(e.length)return z`<div class=\"list-group\">\n        ${e.map((e=>{var t;return z`<button\n            type=\"button\"\n            test-id=\"${e.id}\"\n            @click=${t=>{t.stopPropagation(),this.toggleTest(e)}}\n            class=\"mte-test-list-group-item list-group-item list-group-item-action${(null===(t=this.selectedTest)||void 0===t?void 0:t.id)===e.id?\" active\":\"\"}\"\n            ><span class=\"emblem\">${Dt(e.status)}</span> ${e.name} [${e.status}]</button\n          >`}))}\n      </div>`}renderCode(){var e;if(null===(e=this.model)||void 0===e?void 0:e.source){const e=new Map;for(const t of this.tests)if(t.location){let r=e.get(t.location.start.line);r||(r=[],e.set(t.location.start.line,r)),r.push(t)}const t=t=>this.renderTestDots([...e.entries()].filter((([e])=>e>t)).flatMap((([,e])=>e)));return z`<pre id=\"report-code-block\" class=\"line-numbers\"><code class=\"language-${wr(this.model.name)}\"><table>\n        ${this.lines.map(((r,n)=>z`<tr class=\"line\"\n            ><td class=\"line-number\"></td><td class=\"line-marker\"></td\n            ><td class=\"code\"\n              >${mr(r)}${this.renderTestDots(e.get(n+1))}${this.lines.length===n+1?t(n+1):\"\"}</td\n            ></tr\n          >`))}</table></code></pre>`}}renderTestDots(e){return z`${null==e?void 0:e.map((e=>j`<svg test-id=\"${e.id}\" class=\"test-dot ${this.selectedTest===e?\"selected\":e.status}\" @click=${t=>{t.stopPropagation(),this.toggleTest(e)}} height=\"10\" width=\"10\">\n          <title>${function(e){return`${e.name} (${e.status})`}(e)}</title>\n          <circle cx=\"5\" cy=\"5\" r=\"5\" />\n          </svg>`))}`}update(e){if(e.has(\"model\")&&this.model){const e=this.model;this.filters=[ne.ih.Killing,ne.ih.Covering,ne.ih.NotCovering].filter((t=>e.tests.some((e=>e.status===t)))).map((t=>({enabled:!0,count:e.tests.filter((e=>e.status===t)).length,status:t,label:`${Dt(t)} ${t}`,context:It(t)}))),this.model.source&&(this.lines=$r(kr(this.model.source,this.model.name)))}(e.has(\"model\")||e.has(\"enabledStates\"))&&this.model&&(this.tests=this.model.tests.filter((e=>this.enabledStates.includes(e.status))).sort(((e,t)=>e.location&&t.location?Sr(e.location.start,t.location.start)?1:-1:this.model.tests.indexOf(e)-this.model.tests.indexOf(t)))),super.update(e)}};on.styles=[ce,le,i(rn.Z)],nn([te()],on.prototype,\"model\",void 0),nn([Jt()],on.prototype,\"filters\",void 0),nn([Jt()],on.prototype,\"lines\",void 0),nn([Jt()],on.prototype,\"enabledStates\",void 0),nn([Jt()],on.prototype,\"selectedTest\",void 0),nn([Jt()],on.prototype,\"tests\",void 0),on=nn([re(\"mte-test-file\")],on);var sn=r(4642),an=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};const ln=e=>z`${e.id} <code>${e.getMutatedLines()}</code> (${qt(e)})`;let cn=class extends Q{constructor(){super(...arguments),this.mode=\"closed\"}render(){var e,t;return z`<mte-drawer ?hasDetail=\"${(null===(e=this.test)||void 0===e?void 0:e.killedMutants)||(null===(t=this.test)||void 0===t?void 0:t.coveredMutants)}\" .mode=\"${this.mode}\">\n      ${Lt(this.test,(e=>z`\n          <span slot=\"header\"\n            >${e.id} ${Dt(e.status)} ${e.name} [${e.status}]\n            ${e.location?z`(${e.location.start.line}:${e.location.start.column})`:\"\"}</span\n          >\n          <span slot=\"summary\">${this.renderSummary()}</span>\n          <span slot=\"detail\">${this.renderDetail()}</span>\n        `))}</mte-drawer\n    >`}renderSummary(){var e,t,r,n;return z`<div class=\"d-flex mx-2\">\n      ${(null===(t=null===(e=this.test)||void 0===e?void 0:e.killedMutants)||void 0===t?void 0:t[0])?z`<h6 class=\"pe-4\"\n            >🎯 Killed: ${ln(null===(r=this.test.killedMutants)||void 0===r?void 0:r[0])}\n            ${this.test.killedMutants.length>1?z`(and ${this.test.killedMutants.length-1} more)`:\"\"}</h6\n          >`:\"\"}\n      ${Lt(null===(n=this.test)||void 0===n?void 0:n.coveredMutants,(e=>{var t;return z`<h6 class=\"pe-4\">\n            ☂️ Covered ${e.length} mutant${Kt(e)}\n            ${Bt((null===(t=this.test)||void 0===t?void 0:t.status)===ne.ih.Covering,\"(yet didn't kill any of them)\")}\n          </h6>`}))}\n    </div>`}renderDetail(){var e,t,r,n;return z`<ul class=\"list-group\">\n      ${null===(t=null===(e=this.test)||void 0===e?void 0:e.killedMutants)||void 0===t?void 0:t.map((e=>z`<li title=\"This test killed this mutant\" class=\"list-group-item\">🎯 ${ln(e)}</li>`))}\n      ${null===(n=null===(r=this.test)||void 0===r?void 0:r.coveredMutants)||void 0===n?void 0:n.filter((e=>{var t,r;return!(null===(r=null===(t=this.test)||void 0===t?void 0:t.killedMutants)||void 0===r?void 0:r.includes(e))})).map((e=>z`<li class=\"list-group-item\" title=\"This test covered this mutant\">☂️ ${ln(e)}</li>`))}\n    </ul>`}};cn.styles=[le,i(sn.Z)],an([te()],cn.prototype,\"test\",void 0),an([te({reflect:!0})],cn.prototype,\"mode\",void 0),cn=an([re(\"mte-drawer-test\")],cn);var dn=r(8847),un=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let hn=class extends Q{get language(){return wr(this.fileName)}get isTestFile(){const e=this.fileName.substr(0,this.fileName.lastIndexOf(\".\")).toLowerCase();return e.endsWith(\"spec\")||e.endsWith(\"test\")}get cssClass(){var e,t;return`${this.isFile?null!==(t=null===(e=this.language)||void 0===e?void 0:e.toString())&&void 0!==t?t:\"unknown\":\"directory\"}${this.isTestFile?\" test\":\"\"}`}render(){if(!this.isFile)return j`<svg aria-label=\"directory\" class=\"octicon octicon-file-directory\" viewBox=\"0 0 14 16\" version=\"1.1\" width=\"14\" height=\"16\" role=\"img\"><path fill-rule=\"evenodd\" d=\"M13 4H7V3c0-.66-.31-1-1-1H1c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zM6 4H1V3h5v1z\"></path></svg>`;if(!this.language)return j`<svg aria-label=\"file\" class=\"octicon octicon-file\" viewBox=\"0 0 12 16\" version=\"1.1\" width=\"12\" height=\"16\" role=\"img\"><path fill-rule=\"evenodd\" d=\"M6 5H2V4h4v1zM2 8h7V7H2v1zm0 2h7V9H2v1zm0 2h7v-1H2v1zm10-7.5V14c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V2c0-.55.45-1 1-1h7.5L12 4.5zM11 5L8 2H1v12h10V5z\"></path></svg>`;switch(this.language){case vr.csharp:return j`<svg class=\"${this.cssClass}\" aria-label=\"cs\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><g><path d=\"M7.1 15.9c0-1.3.2-2.4.6-3.4.4-1 .9-1.8 1.6-2.5.7-.7 1.5-1.2 2.4-1.6s1.9-.5 2.9-.5 1.9.2 2.7.6c.8.4 1.5.9 2 1.4l-2.2 2.5c-.4-.3-.7-.6-1.1-.7-.4-.1-.8-.3-1.4-.3-.5 0-.9.1-1.3.3-.4.2-.8.5-1.1.9s-.5.8-.7 1.4c-.2.6-.3 1.2-.3 1.9 0 1.5.3 2.6 1 3.3.7.8 1.5 1.2 2.6 1.2.5 0 1-.1 1.4-.3.4-.2.8-.5 1.1-.9l2.2 2.5c-.7.8-1.4 1.3-2.2 1.7-.8.4-1.7.6-2.7.6s-2-.2-2.9-.5-1.7-.8-2.4-1.5-1.1-1.7-1.5-2.7c-.5-.9-.7-2.1-.7-3.4z\"/><path d=\"M21.8 17.1h-1l-.4 2.4h-1.2l.4-2.4h-1.2V16h1.5l.2-1.6h-1.3v-1.1h1.5l.4-2.4h1.2l-.4 2.4h1l.4-2.4h1.2l-.4 2.4H25v1.1h-1.6l-.2 1.6h1.3v1.1h-1.6l-.4 2.4h-1.2c0 .1.5-2.4.5-2.4zm-.8-1h1l.2-1.6h-1l-.2 1.6z\"/></g></svg>`;case vr.html:return j`<svg class=\"${this.cssClass}\" aria-label=\"html\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path d=\"M8 15l6-5.6V12l-4.5 4 4.5 4v2.6L8 17v-2zm16 2.1l-6 5.6V20l4.6-4-4.6-4V9.3l6 5.6v2.2z\"/></svg>`;case vr.java:return j`<svg class=\"${this.cssClass}\" aria-label=\"java\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"-4 -4 20 20\"><path class=\"cls-1\" d=\"M6 0a6 6 0 1 0 6 6 6 6 0 0 0-6-6zm2.14 6.8a2.16 2.16 0 0 1-2.29 2.41 2.5 2.5 0 0 1-2-.87l.73-.92a1.52 1.52 0 0 0 1.23.59c.66 0 1.06-.42 1.06-1.32V2.8h1.26z\"/></svg>`;case vr.javascript:return j`<svg class=\"${this.cssClass}\" aria-label=\"js\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path  d=\"M11.4 10h2.7v7.6c0 3.4-1.6 4.6-4.3 4.6-.6 0-1.5-.1-2-.3l.3-2.2c.4.2.9.3 1.4.3 1.1 0 1.9-.5 1.9-2.4V10zm5.1 9.2c.7.4 1.9.8 3 .8 1.3 0 1.9-.5 1.9-1.3s-.6-1.2-2-1.7c-2-.7-3.3-1.8-3.3-3.6 0-2.1 1.7-3.6 4.6-3.6 1.4 0 2.4.3 3.1.6l-.6 2.2c-.5-.2-1.3-.6-2.5-.6s-1.8.5-1.8 1.2c0 .8.7 1.1 2.2 1.7 2.1.8 3.1 1.9 3.1 3.6 0 2-1.6 3.7-4.9 3.7-1.4 0-2.7-.4-3.4-.7l.6-2.3z\"/></svg>`;case vr.typescript:return j`<svg class=\"${this.cssClass}\" aria-label=\"ts\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path d=\"M15.6 11.8h-3.4V22H9.7V11.8H6.3V10h9.2v1.8zm7.7 7.1c0-.5-.2-.8-.5-1.1-.3-.3-.9-.5-1.7-.8-1.4-.4-2.5-.9-3.3-1.5-.7-.6-1.1-1.3-1.1-2.3 0-1 .4-1.8 1.3-2.4.8-.6 1.9-.9 3.2-.9 1.3 0 2.4.4 3.2 1.1.8.7 1.2 1.6 1.2 2.6h-2.3c0-.6-.2-1-.6-1.4-.4-.3-.9-.5-1.6-.5-.6 0-1.1.1-1.5.4-.4.3-.5.7-.5 1.1 0 .4.2.7.6 1 .4.3 1 .5 2 .8 1.3.4 2.3.9 3 1.5.7.6 1 1.4 1 2.4s-.4 1.9-1.2 2.4c-.8.6-1.9.9-3.2.9-1.3 0-2.5-.3-3.4-1s-1.5-1.6-1.4-2.9h2.4c0 .7.2 1.2.7 1.6.4.3 1.1.5 1.8.5s1.2-.1 1.5-.4c.2-.3.4-.7.4-1.1z\"/></svg>`;case vr.scala:return j`<svg class=\"${this.cssClass}\" aria-label=\"scala\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path d=\"M21.6 7v4.2c-.1.1-.1.2-.2.2-.3.3-.7.5-1.1.6-.9.3-1.9.5-2.8.7-1.6.3-3.1.5-4.7.7-.8.1-1.6.2-2.4.4V9.6c.1-.1.2-.1.4-.1 1.2-.2 2.5-.4 3.8-.5 1.9-.3 3.8-.5 5.6-1.1.5-.2 1.1-.4 1.4-.9zm0 5.6v4.2l-.2.2c-.5.4-1.1.6-1.6.8-.8.2-1.6.4-2.4.5-1 .2-1.9.3-2.9.5-1.4.2-2.7.3-4.1.6v-4.2c.1-.1.2-.1.3-.1 1.7-.2 3.4-.5 5.1-.7 1.4-.2 2.9-.5 4.3-.9.6-.2 1.1-.4 1.5-.9zM10.5 25h-.1v-4.2c.1-.1.2-.1.3-.1 1.2-.2 2.3-.3 3.5-.5 2-.3 3.9-.5 5.8-1.1.6-.2 1.2-.4 1.6-.9v4.2c-.1.2-.3.3-.5.5-.6.3-1.2.5-1.9.7-1.2.3-2.5.5-3.7.7-1.3.2-2.6.4-3.9.5-.4 0-.7.1-1.1.2z\"/></svg>`;case vr.php:return j`<svg class=\"${this.cssClass}\" aria-label=\"php\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path d=\"M12.7 19.7c-.1-.6-.4-1.1-1-1.3-.2-.1-.5-.3-.7-.4-.3-.1-.6-.2-.8-.3-.2-.1-.4 0-.6.2-.1.2 0 .4.1.5.1.2.2.3.4.5.2.3.4.5.7.8.2.3.4.5.3.9-.1.7-.4 1.4-.9 1.9-.1.1-.2.1-.2.1-.3 0-.7-.2-.9-.4-.3-.3-.2-.6.1-.8.1 0 .2-.1.2-.2.2-.2.3-.4.2-.7-.1-.1-.1-.2-.2-.3-.4-.4-.9-.8-1.4-1.2-1.3-1-1.9-2.2-2-3.6-.1-1.6.3-3.1 1.1-4.5.3-.5.7-1 1.3-1.3.4-.2.8-.3 1.2-.4 1.1-.3 2.3-.5 3.5-.3 1 .2 1.8.7 2.1 1.7.2.7.3 1.3.2 2-.1 1.4-1.2 2.6-2.5 3-.6.2-.9.1-1.2-.4-.2-.3-.5-.7-.7-1.1V14c0-.1-.1-.1-.1-.2.1.6.2 1.2.5 1.7.2.3.4.5.8.5 1.3.1 2.3-.3 3.1-1.3.8-1.1 1-2.4.8-3.8 0-.3-.1-.5-.2-.8 0-.2 0-.3.2-.4.1 0 .2 0 .2-.1 1-.2 2.1-.3 3.1-.2 1.2.1 2.3.4 3.3 1.1 1.6 1 2.6 2.5 3.1 4.3.1.3.1.5.1.8 0 .2-.1.2-.3.1-.2-.1-.3-.3-.4-.4-.1-.1-.2-.3-.3-.4-.1-.1-.2-.1-.2 0s-.1.2-.1.3c-.3 1-.7 1.9-1.4 2.6-.1.1-.2.3-.2.4 0 .4-.1.8 0 1.2.1.8.2 1.7.3 2.5.1.5-.1.7-.5.9-.3.1-.6.2-1 .2h-1.6c0-.6 0-1.2-.5-1.5.1-.4.2-.8.3-1.3.1-.4 0-.7-.2-1-.2-.3-.5-.3-.8-.2-.8.5-1.6.5-2.5.2-.4-.1-.7-.1-.9.3-.2.4-.3.8-.3 1.2 0 .5.1 1.1.2 1.6 0 .3 0 .4-.3.5-.7.2-1.4.2-2 .1h-.1c0-.6 0-1.2-.7-1.5.4-.4.4-1.1.3-1.7zm-4.1-2.3c.1-.1.2-.2.2-.4.1-.3-.2-.8-.5-.9-.2-.1-.3 0-.4.1-.3.3-.5.6-.8.9 0 .1-.1.1-.1.2-.1.2 0 .4.2.4.1 0 .3 0 .4.1.4 0 .7-.1 1-.4zm0-3.3c0-.2-.2-.4-.4-.4s-.5.2-.4.5c0 .2.2.4.5.4.1-.1.3-.3.3-.5z\"/></svg>`;case vr.vue:return j`<svg class=\"${this.cssClass}\" aria-label=\"vue\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1200 1000\"><path d=\"M600 495.9l159.1-275.4h-84.4L600 349.7l-74.6-129.2h-84.5z\"/><path d=\"M793.7 220.5L600 555.9 406.3 220.5H277l323 559 323-559z\"/></svg>`;case vr.gherkin:return j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"><path d=\"M16.129,2a12.348,12.348,0,0,0-2.35,24.465V30c7.371-1.114,13.9-6.982,14.384-14.684a12.8,12.8,0,0,0-5.9-11.667c-.223-.132-.449-.262-.682-.377s-.481-.231-.729-.33c-.079-.033-.156-.063-.235-.094-.216-.08-.435-.17-.658-.236A12.188,12.188,0,0,0,16.129,2Z\" style=\"fill:var(--mut-file-gherkin-color)\"/><path d=\"M18.68,6.563a1.345,1.345,0,0,0-1.178.472,5.493,5.493,0,0,0-.518.9,2.9,2.9,0,0,0,.377,3.023A3.317,3.317,0,0,0,19.763,9,2.388,2.388,0,0,0,20,8,1.411,1.411,0,0,0,18.68,6.563Zm-5.488.071A1.441,1.441,0,0,0,11.85,8,2.388,2.388,0,0,0,12.085,9a3.427,3.427,0,0,0,2.473,1.96,3.141,3.141,0,0,0-.212-3.85,1.322,1.322,0,0,0-1.154-.472Zm-3.7,3.637a1.3,1.3,0,0,0-.73,2.338,5.663,5.663,0,0,0,.895.543,3.386,3.386,0,0,0,3.179-.307,3.492,3.492,0,0,0-2.049-2.338,2.69,2.69,0,0,0-1.06-.236,1.369,1.369,0,0,0-.236,0Zm11.611,4.582a3.44,3.44,0,0,0-1.955.567A3.492,3.492,0,0,0,21.2,17.758a2.69,2.69,0,0,0,1.06.236,1.329,1.329,0,0,0,.966-2.362,5.47,5.47,0,0,0-.895-.52,3.247,3.247,0,0,0-1.225-.26Zm-10.292.071a3.247,3.247,0,0,0-1.225.26,2.575,2.575,0,0,0-.895.543A1.34,1.34,0,0,0,9.73,18.065a2.426,2.426,0,0,0,1.06-.236,3.185,3.185,0,0,0,1.955-2.338,3.366,3.366,0,0,0-1.931-.567Zm3.815,2.314a3.317,3.317,0,0,0-2.4,1.96,2.286,2.286,0,0,0-.236.968,1.4,1.4,0,0,0,2.426.992,5.492,5.492,0,0,0,.518-.9,3.109,3.109,0,0,0-.306-3.023Zm2.8.071a3.141,3.141,0,0,0,.212,3.85,1.47,1.47,0,0,0,2.5-.9,2.388,2.388,0,0,0-.236-.992,3.427,3.427,0,0,0-2.473-1.96Z\" style=\"fill:#fff\"/></svg>`}}};hn.styles=[i(dn.Z)],un([te({attribute:\"file-name\"})],hn.prototype,\"fileName\",void 0),un([te({attribute:\"file\",type:Boolean})],hn.prototype,\"isFile\",void 0),hn=un([re(\"mte-file-icon\")],hn);var bn=r(5465),pn=function(e,t,r,n){var o,i=arguments.length,s=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(i<3?o(s):i>3?o(t,r,s):o(t,r))||s);return i>3&&s&&Object.defineProperty(t,r,s),s};let gn=class extends Q{render(){return z`<span class=\"tooltip\" title=\"${this.title}\"><slot></slot></span>`}};gn.styles=[i(bn.Z)],pn([te({attribute:!0})],gn.prototype,\"title\",void 0),gn=pn([re(\"mte-tooltip\")],gn)})()})();</script>\n    </head>\n    <body>\n        <mutation-test-report-app title-postfix=\"Stryker.NET Report\">\n            Your browser doesn't support <a href=\"https://caniuse.com/#search=custom%20elements\">custom elements</a>.\n            Please use a latest version of an evergreen browser (Firefox, Chrome, Safari, Opera, etc).\n        </mutation-test-report-app>\n        <script>\n            const app = document.querySelector('mutation-test-report-app');\n\n            app.report = {\"schemaVersion\":\"1\",\"thresholds\":{\"high\":80,\"low\":60},\"projectRoot\":\"C:\\\\OSS\\\\ModularMonolith\\\\Repository\\\\modular-monolith-with-ddd\\\\src\\\\Modules\\\\Meetings\\\\Domain\",\"files\":{\"MeetingCommentingConfigurations\\\\Events\\\\MeetingCommentingConfigurationCreatedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\\r\\n{\\r\\n    public class MeetingCommentingConfigurationCreatedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public bool IsEnabled { get; }\\r\\n\\r\\n        public MeetingCommentingConfigurationCreatedDomainEvent(MeetingId meetingId, bool isEnabled)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            IsEnabled = isEnabled;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"0\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingCommentingConfigurations\\\\Events\\\\MeetingCommentingDisabledDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\\r\\n{\\r\\n    public class MeetingCommentingDisabledDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MeetingCommentingDisabledDomainEvent(MeetingId meetingId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"1\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":11,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingCommentingConfigurations\\\\Events\\\\MeetingCommentingEnabledDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\\r\\n{\\r\\n    public class MeetingCommentingEnabledDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MeetingCommentingEnabledDomainEvent(MeetingId meetingId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"2\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":11,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingCommentingConfigurations\\\\IMeetingCommentingConfigurationRepository.cs\":{\"language\":\"cs\",\"source\":\"using System.Threading.Tasks;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\\r\\n{\\r\\n    public interface IMeetingCommentingConfigurationRepository\\r\\n    {\\r\\n        Task AddAsync(MeetingCommentingConfiguration meetingCommentingConfiguration);\\r\\n\\r\\n        Task\\u003CMeetingCommentingConfiguration\\u003E GetByMeetingIdAsync(MeetingId meetingId);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingCommentingConfigurations\\\\MeetingCommentingConfiguration.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\\r\\n{\\r\\n    public class MeetingCommentingConfiguration : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingCommentingConfigurationId Id { get; }\\r\\n\\r\\n        private MeetingId _meetingId;\\r\\n\\r\\n        private bool _isCommentingEnabled;\\r\\n\\r\\n        private MeetingCommentingConfiguration(MeetingId meetingId)\\r\\n        {\\r\\n            this.Id = new MeetingCommentingConfigurationId(Guid.NewGuid());\\r\\n            this._meetingId = meetingId;\\r\\n            this._isCommentingEnabled = true;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingCommentingConfigurationCreatedDomainEvent(this._meetingId, this._isCommentingEnabled));\\r\\n        }\\r\\n\\r\\n        private MeetingCommentingConfiguration()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        public void EnableCommenting(MemberId enablingMemberId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            CheckRule(new MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule(enablingMemberId, meetingGroup));\\r\\n\\r\\n            if (!this._isCommentingEnabled)\\r\\n            {\\r\\n                this._isCommentingEnabled = true;\\r\\n                AddDomainEvent(new MeetingCommentingEnabledDomainEvent(this._meetingId));\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public void DisableCommenting(MemberId disablingMemberId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            CheckRule(new MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule(disablingMemberId, meetingGroup));\\r\\n\\r\\n            if (this._isCommentingEnabled)\\r\\n            {\\r\\n                this._isCommentingEnabled = false;\\r\\n                AddDomainEvent(new MeetingCommentingDisabledDomainEvent(this._meetingId));\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public bool GetIsCommentingEnabled() =\\u003E _isCommentingEnabled;\\r\\n\\r\\n        internal static MeetingCommentingConfiguration Create(MeetingId meetingId)\\r\\n            =\\u003E new MeetingCommentingConfiguration(meetingId);\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"3\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":20,\"column\":9},\"end\":{\"line\":26,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"4\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":23,\"column\":41},\"end\":{\"line\":23,\"column\":45}},\"status\":\"Killed\",\"static\":false},{\"id\":\"5\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":25,\"column\":13},\"end\":{\"line\":25,\"column\":131}},\"status\":\"Killed\",\"static\":false},{\"id\":\"6\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":34,\"column\":9},\"end\":{\"line\":42,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"7\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":35,\"column\":13},\"end\":{\"line\":35,\"column\":114}},\"status\":\"Killed\",\"static\":false},{\"id\":\"8\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"this._isCommentingEnabled\",\"location\":{\"start\":{\"line\":37,\"column\":17},\"end\":{\"line\":37,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"9\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":38,\"column\":13},\"end\":{\"line\":41,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"10\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":39,\"column\":45},\"end\":{\"line\":39,\"column\":49}},\"status\":\"Survived\",\"static\":false},{\"id\":\"11\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":40,\"column\":17},\"end\":{\"line\":40,\"column\":90}},\"status\":\"Killed\",\"static\":false},{\"id\":\"12\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":45,\"column\":9},\"end\":{\"line\":53,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"13\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":46,\"column\":13},\"end\":{\"line\":46,\"column\":116}},\"status\":\"Killed\",\"static\":false},{\"id\":\"14\",\"mutatorName\":\"Negate expression\",\"replacement\":\"!(this._isCommentingEnabled)\",\"location\":{\"start\":{\"line\":48,\"column\":17},\"end\":{\"line\":48,\"column\":42}},\"status\":\"Killed\",\"static\":false},{\"id\":\"15\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":49,\"column\":13},\"end\":{\"line\":52,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"16\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":50,\"column\":45},\"end\":{\"line\":50,\"column\":50}},\"status\":\"Killed\",\"static\":false},{\"id\":\"17\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":51,\"column\":17},\"end\":{\"line\":51,\"column\":91}},\"status\":\"Killed\",\"static\":false}]},\"MeetingCommentingConfigurations\\\\MeetingCommentingConfigurationId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\\r\\n{\\r\\n    public class MeetingCommentingConfigurationId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingCommentingConfigurationId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingCommentingConfigurations\\\\Rules\\\\MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules\\r\\n{\\r\\n    public class MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n        private readonly MemberId _disablingMemberId;\\r\\n\\r\\n        public MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule(MemberId disablingMemberId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _disablingMemberId = disablingMemberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingGroup.IsOrganizer(_disablingMemberId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Commenting for meeting can be disabled only by group organizer\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"18\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"19\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsOrganizer(_disablingMemberId)\",\"location\":{\"start\":{\"line\":18,\"column\":35},\"end\":{\"line\":18,\"column\":81}},\"status\":\"Killed\",\"static\":false},{\"id\":\"20\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":20,\"column\":34},\"end\":{\"line\":20,\"column\":98}},\"status\":\"Survived\",\"static\":false}]},\"MeetingCommentingConfigurations\\\\Rules\\\\MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules\\r\\n{\\r\\n    public class MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n        private readonly MemberId _enablingMemberId;\\r\\n\\r\\n        public MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule(MemberId enablingMemberId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _enablingMemberId = enablingMemberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingGroup.IsOrganizer(_enablingMemberId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Commenting for meeting can be enabled only by group organizer\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"21\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"22\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsOrganizer(_enablingMemberId)\",\"location\":{\"start\":{\"line\":18,\"column\":35},\"end\":{\"line\":18,\"column\":80}},\"status\":\"Killed\",\"static\":false},{\"id\":\"23\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":20,\"column\":34},\"end\":{\"line\":20,\"column\":97}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Events\\\\MeetingCommentAddedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Comments.Events\\r\\n{\\r\\n    public class MeetingCommentAddedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public string Comment { get; }\\r\\n\\r\\n        public MeetingCommentAddedDomainEvent(MeetingCommentId meetingCommentId, MeetingId meetingId, string comment)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n            MeetingId = meetingId;\\r\\n            Comment = comment;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"24\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingComments\\\\Events\\\\MeetingCommentEditedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Comments.Events\\r\\n{\\r\\n    public class MeetingCommentEditedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public string EditedComment { get; }\\r\\n\\r\\n        public MeetingCommentEditedDomainEvent(MeetingCommentId meetingCommentId, string editedComment)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n            EditedComment = editedComment;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"25\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingComments\\\\Events\\\\MeetingCommentRemovedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Comments.Events\\r\\n{\\r\\n    public class MeetingCommentRemovedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public MeetingCommentRemovedDomainEvent(MeetingCommentId meetingCommentId)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"26\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingComments\\\\Events\\\\ReplyToMeetingCommentAddedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Comments.Events\\r\\n{\\r\\n    public class ReplyToMeetingCommentAddedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public MeetingCommentId InReplyToCommentId { get; }\\r\\n\\r\\n        public string Reply { get; }\\r\\n\\r\\n        public ReplyToMeetingCommentAddedDomainEvent(MeetingCommentId meetingCommentId, MeetingCommentId inReplyToCommentId, string reply)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n            InReplyToCommentId = inReplyToCommentId;\\r\\n            Reply = reply;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"27\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingComments\\\\IMeetingCommentRepository.cs\":{\"language\":\"cs\",\"source\":\"using System.Threading.Tasks;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments\\r\\n{\\r\\n    public interface IMeetingCommentRepository\\r\\n    {\\r\\n        Task AddAsync(MeetingComment meetingComment);\\r\\n\\r\\n        Task\\u003CMeetingComment\\u003E GetByIdAsync(MeetingCommentId meetingCommentId);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingComments\\\\MeetingComment.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Collections.Generic;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments\\r\\n{\\r\\n    public class MeetingComment : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingCommentId Id { get; }\\r\\n\\r\\n        private MeetingId _meetingId;\\r\\n\\r\\n        private MemberId _authorId;\\r\\n\\r\\n        private MeetingCommentId? _inReplyToCommentId;\\r\\n\\r\\n        private string _comment;\\r\\n\\r\\n        private DateTime _createDate;\\r\\n\\r\\n        private DateTime? _editDate;\\r\\n\\r\\n        private bool _isRemoved;\\r\\n\\r\\n        private string _removedByReason;\\r\\n\\r\\n        private MeetingComment(\\r\\n            MeetingId meetingId,\\r\\n            MemberId authorId,\\r\\n            string comment,\\r\\n            MeetingCommentId? inReplyToCommentId,\\r\\n            MeetingCommentingConfiguration meetingCommentingConfiguration,\\r\\n            MeetingGroup meetingGroup)\\r\\n        {\\r\\n            this.CheckRule(new CommentTextMustBeProvidedRule(comment));\\r\\n            this.CheckRule(new CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule(meetingCommentingConfiguration));\\r\\n            this.CheckRule(new CommentCanBeAddedOnlyByMeetingGroupMemberRule(authorId, meetingGroup));\\r\\n\\r\\n            this.Id = new MeetingCommentId(Guid.NewGuid());\\r\\n            _meetingId = meetingId;\\r\\n            _authorId = authorId;\\r\\n            _comment = comment;\\r\\n\\r\\n            _inReplyToCommentId = inReplyToCommentId;\\r\\n\\r\\n            _createDate = SystemClock.Now;\\r\\n            _editDate = null;\\r\\n\\r\\n            _isRemoved = false;\\r\\n            _removedByReason = null;\\r\\n\\r\\n            if (inReplyToCommentId == null)\\r\\n            {\\r\\n                this.AddDomainEvent(new MeetingCommentAddedDomainEvent(this.Id, _meetingId, comment));\\r\\n            }\\r\\n            else\\r\\n            {\\r\\n                this.AddDomainEvent(new ReplyToMeetingCommentAddedDomainEvent(this.Id, inReplyToCommentId, comment));\\r\\n            }\\r\\n        }\\r\\n\\r\\n        private MeetingComment()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        public void Edit(MemberId editorId, string editedComment, MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n        {\\r\\n            this.CheckRule(new CommentTextMustBeProvidedRule(editedComment));\\r\\n            this.CheckRule(new MeetingCommentCanBeEditedOnlyByAuthorRule(this._authorId, editorId));\\r\\n            this.CheckRule(new CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule(meetingCommentingConfiguration));\\r\\n\\r\\n            _comment = editedComment;\\r\\n            _editDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingCommentEditedDomainEvent(this.Id, editedComment));\\r\\n        }\\r\\n\\r\\n        public void Remove(MemberId removingMemberId, MeetingGroup meetingGroup, string reason = null)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule(meetingGroup, this._authorId, removingMemberId));\\r\\n            this.CheckRule(new RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule(meetingGroup, removingMemberId, reason));\\r\\n\\r\\n            _isRemoved = true;\\r\\n            _removedByReason = reason ?? string.Empty;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingCommentRemovedDomainEvent(this.Id));\\r\\n        }\\r\\n\\r\\n        public MeetingComment Reply(MemberId replierId, string reply, MeetingGroup meetingGroup, MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n            =\\u003E new MeetingComment(\\r\\n                _meetingId,\\r\\n                replierId,\\r\\n                reply,\\r\\n                this.Id,\\r\\n                meetingCommentingConfiguration,\\r\\n                meetingGroup);\\r\\n\\r\\n        public MeetingMemberCommentLike Like(\\r\\n            MemberId likerId,\\r\\n            MeetingGroupMemberData likerMeetingGroupMember,\\r\\n            int meetingMemberCommentLikesCount)\\r\\n        {\\r\\n            this.CheckRule(new CommentCanBeLikedOnlyByMeetingGroupMemberRule(likerMeetingGroupMember));\\r\\n            this.CheckRule(new CommentCannotBeLikedByTheSameMemberMoreThanOnceRule(meetingMemberCommentLikesCount));\\r\\n\\r\\n            return MeetingMemberCommentLike.Create(this.Id, likerId);\\r\\n        }\\r\\n\\r\\n        public MeetingId GetMeetingId() =\\u003E this._meetingId;\\r\\n\\r\\n        internal static MeetingComment Create(\\r\\n            MeetingId meetingId,\\r\\n            MemberId authorId,\\r\\n            string comment,\\r\\n            MeetingGroup meetingGroup,\\r\\n            MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n            =\\u003E new MeetingComment(\\r\\n                meetingId,\\r\\n                authorId,\\r\\n                comment,\\r\\n                inReplyToCommentId: null,\\r\\n                meetingCommentingConfiguration,\\r\\n                meetingGroup);\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"28\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":43,\"column\":9},\"end\":{\"line\":69,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"29\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":44,\"column\":13},\"end\":{\"line\":44,\"column\":72}},\"status\":\"Killed\",\"static\":false},{\"id\":\"30\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":45,\"column\":13},\"end\":{\"line\":45,\"column\":122}},\"status\":\"Killed\",\"static\":false},{\"id\":\"31\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":46,\"column\":13},\"end\":{\"line\":46,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"32\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":58,\"column\":26},\"end\":{\"line\":58,\"column\":31}},\"status\":\"Survived\",\"static\":false},{\"id\":\"33\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"inReplyToCommentId != null\",\"location\":{\"start\":{\"line\":61,\"column\":17},\"end\":{\"line\":61,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"34\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":62,\"column\":13},\"end\":{\"line\":64,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"35\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":63,\"column\":17},\"end\":{\"line\":63,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"36\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":66,\"column\":13},\"end\":{\"line\":68,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"37\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":67,\"column\":17},\"end\":{\"line\":67,\"column\":118}},\"status\":\"Killed\",\"static\":false},{\"id\":\"38\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":77,\"column\":9},\"end\":{\"line\":86,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"39\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":78,\"column\":13},\"end\":{\"line\":78,\"column\":78}},\"status\":\"Killed\",\"static\":false},{\"id\":\"40\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":79,\"column\":13},\"end\":{\"line\":79,\"column\":101}},\"status\":\"Killed\",\"static\":false},{\"id\":\"41\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":80,\"column\":13},\"end\":{\"line\":80,\"column\":121}},\"status\":\"Killed\",\"static\":false},{\"id\":\"42\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":85,\"column\":13},\"end\":{\"line\":85,\"column\":94}},\"status\":\"Killed\",\"static\":false},{\"id\":\"43\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":89,\"column\":9},\"end\":{\"line\":97,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"44\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":90,\"column\":13},\"end\":{\"line\":90,\"column\":140}},\"status\":\"Killed\",\"static\":false},{\"id\":\"45\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":91,\"column\":13},\"end\":{\"line\":91,\"column\":125}},\"status\":\"Killed\",\"static\":false},{\"id\":\"46\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":93,\"column\":26},\"end\":{\"line\":93,\"column\":30}},\"status\":\"Survived\",\"static\":false},{\"id\":\"47\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022Stryker was here!\\u0022\",\"location\":{\"start\":{\"line\":94,\"column\":42},\"end\":{\"line\":94,\"column\":54}},\"status\":\"Survived\",\"static\":false},{\"id\":\"48\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":96,\"column\":13},\"end\":{\"line\":96,\"column\":80}},\"status\":\"Killed\",\"static\":false},{\"id\":\"49\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":112,\"column\":9},\"end\":{\"line\":117,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"50\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":113,\"column\":13},\"end\":{\"line\":113,\"column\":104}},\"status\":\"Killed\",\"static\":false},{\"id\":\"51\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":114,\"column\":13},\"end\":{\"line\":114,\"column\":117}},\"status\":\"Killed\",\"static\":false}]},\"MeetingComments\\\\MeetingCommentId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Comments\\r\\n{\\r\\n    public class MeetingCommentId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingCommentId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingComments\\\\Rules\\\\CommentCanBeAddedOnlyByMeetingGroupMemberRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentCanBeAddedOnlyByMeetingGroupMemberRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MemberId _authorId;\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n\\r\\n        public CommentCanBeAddedOnlyByMeetingGroupMemberRule(MemberId authorId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            _authorId = authorId;\\r\\n            _meetingGroup = meetingGroup;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingGroup.IsMemberOfGroup(_authorId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only meeting attendee can add comments\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"52\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"53\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsMemberOfGroup(_authorId)\",\"location\":{\"start\":{\"line\":18,\"column\":35},\"end\":{\"line\":18,\"column\":76}},\"status\":\"Killed\",\"static\":false},{\"id\":\"54\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":20,\"column\":34},\"end\":{\"line\":20,\"column\":74}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingCommentingConfiguration _meetingCommentingConfiguration;\\r\\n\\r\\n        public CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule(MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n        {\\r\\n            _meetingCommentingConfiguration = meetingCommentingConfiguration;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingCommentingConfiguration.GetIsCommentingEnabled();\\r\\n\\r\\n        public string Message =\\u003E \\u0022Commenting for meeting is disabled.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"55\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":11,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"56\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingCommentingConfiguration.GetIsCommentingEnabled()\",\"location\":{\"start\":{\"line\":15,\"column\":35},\"end\":{\"line\":15,\"column\":92}},\"status\":\"Killed\",\"static\":false},{\"id\":\"57\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":17,\"column\":34},\"end\":{\"line\":17,\"column\":71}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingCommentingConfiguration _meetingCommentingConfiguration;\\r\\n\\r\\n        public CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule(MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n        {\\r\\n            _meetingCommentingConfiguration = meetingCommentingConfiguration;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingCommentingConfiguration.GetIsCommentingEnabled();\\r\\n\\r\\n        public string Message =\\u003E \\u0022Commenting for meeting is disabled.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"58\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":11,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"59\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingCommentingConfiguration.GetIsCommentingEnabled()\",\"location\":{\"start\":{\"line\":15,\"column\":35},\"end\":{\"line\":15,\"column\":92}},\"status\":\"Killed\",\"static\":false},{\"id\":\"60\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":17,\"column\":34},\"end\":{\"line\":17,\"column\":71}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\CommentCanBeLikedOnlyByMeetingGroupMemberRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentCanBeLikedOnlyByMeetingGroupMemberRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroupMemberData _likerMeetingGroupMember;\\r\\n\\r\\n        public CommentCanBeLikedOnlyByMeetingGroupMemberRule(MeetingGroupMemberData? likerMeetingGroupMember)\\r\\n        {\\r\\n            _likerMeetingGroupMember = likerMeetingGroupMember;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _likerMeetingGroupMember == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Comment can be liked only by meeting group member.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"61\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":11,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"62\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_likerMeetingGroupMember != null\",\"location\":{\"start\":{\"line\":15,\"column\":35},\"end\":{\"line\":15,\"column\":67}},\"status\":\"Killed\",\"static\":false},{\"id\":\"63\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":17,\"column\":34},\"end\":{\"line\":17,\"column\":86}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\CommentCannotBeLikedByTheSameMemberMoreThanOnceRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentCannotBeLikedByTheSameMemberMoreThanOnceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int _memberCommentLikesCount;\\r\\n\\r\\n        public CommentCannotBeLikedByTheSameMemberMoreThanOnceRule(int memberCommentLikesCount)\\r\\n        {\\r\\n            _memberCommentLikesCount = memberCommentLikesCount;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _memberCommentLikesCount \\u003E 0;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member cannot like one comment more than once.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"64\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"65\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_memberCommentLikesCount \\u003C 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":63}},\"status\":\"Killed\",\"static\":false},{\"id\":\"66\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_memberCommentLikesCount \\u003E= 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":63}},\"status\":\"Killed\",\"static\":false},{\"id\":\"67\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":82}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\CommentTextMustBeProvidedRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class CommentTextMustBeProvidedRule : IBusinessRule\\r\\n    {\\r\\n        private readonly string _comment;\\r\\n\\r\\n        public CommentTextMustBeProvidedRule(string comment)\\r\\n        {\\r\\n            _comment = comment;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E string.IsNullOrEmpty(_comment);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Comment text must be provided.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"68\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"69\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":66}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\MeetingCommentCanBeEditedOnlyByAuthorRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class MeetingCommentCanBeEditedOnlyByAuthorRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MemberId _authorId;\\r\\n        private readonly MemberId _editorId;\\r\\n\\r\\n        public MeetingCommentCanBeEditedOnlyByAuthorRule(MemberId authorId, MemberId editorId)\\r\\n        {\\r\\n            _authorId = authorId;\\r\\n            _editorId = editorId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _editorId != _authorId;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only the author of a comment can edit it.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"70\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"71\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_editorId == _authorId\",\"location\":{\"start\":{\"line\":17,\"column\":35},\"end\":{\"line\":17,\"column\":57}},\"status\":\"Killed\",\"static\":false},{\"id\":\"72\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":19,\"column\":34},\"end\":{\"line\":19,\"column\":77}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n        private readonly MemberId _authorId;\\r\\n        private readonly MemberId _removingMemberId;\\r\\n\\r\\n        public MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule(MeetingGroup meetingGroup, MemberId authorId, MemberId removingMemberId)\\r\\n        {\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _authorId = authorId;\\r\\n            _removingMemberId = removingMemberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _removingMemberId != _authorId \\u0026\\u0026 !_meetingGroup.IsOrganizer(_removingMemberId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only author of comment or group organizer can remove meeting comment.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"73\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"74\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"_removingMemberId != _authorId || !_meetingGroup.IsOrganizer(_removingMemberId)\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":114}},\"status\":\"Killed\",\"static\":false},{\"id\":\"75\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_removingMemberId == _authorId \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":65}},\"status\":\"Killed\",\"static\":false},{\"id\":\"76\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsOrganizer(_removingMemberId)\",\"location\":{\"start\":{\"line\":20,\"column\":69},\"end\":{\"line\":20,\"column\":114}},\"status\":\"Killed\",\"static\":false},{\"id\":\"77\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":105}},\"status\":\"Survived\",\"static\":false}]},\"MeetingComments\\\\Rules\\\\RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\\r\\n{\\r\\n    public class RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n        private readonly MemberId _removingMemberId;\\r\\n        private readonly string _removingReason;\\r\\n\\r\\n        public RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule(MeetingGroup meetingGroup, MemberId removingMemberId, string removingReason)\\r\\n        {\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _removingMemberId = removingMemberId;\\r\\n            _removingReason = removingReason;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E\\r\\n            !string.IsNullOrEmpty(_removingReason) \\u0026\\u0026 !_meetingGroup.IsOrganizer(_removingMemberId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only group organizer can provide comment\\u0027s removing reason.\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"78\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"79\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"            !string.IsNullOrEmpty(_removingReason) || !_meetingGroup.IsOrganizer(_removingMemberId)\",\"location\":{\"start\":{\"line\":21,\"column\":13},\"end\":{\"line\":21,\"column\":100}},\"status\":\"Killed\",\"static\":false},{\"id\":\"80\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"string.IsNullOrEmpty(_removingReason) \",\"location\":{\"start\":{\"line\":21,\"column\":13},\"end\":{\"line\":21,\"column\":51}},\"status\":\"Killed\",\"static\":false},{\"id\":\"81\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsOrganizer(_removingMemberId)\",\"location\":{\"start\":{\"line\":21,\"column\":55},\"end\":{\"line\":21,\"column\":100}},\"status\":\"Killed\",\"static\":false},{\"id\":\"82\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":23,\"column\":34},\"end\":{\"line\":23,\"column\":95}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroupProposals\\\\Events\\\\MeetingGroupProposalAcceptedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events\\r\\n{\\r\\n    public class MeetingGroupProposalAcceptedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\\r\\n\\r\\n        public MeetingGroupProposalAcceptedDomainEvent(MeetingGroupProposalId meetingGroupProposalId)\\r\\n        {\\r\\n            MeetingGroupProposalId = meetingGroupProposalId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"83\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroupProposals\\\\Events\\\\MeetingGroupProposedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events\\r\\n{\\r\\n    public class MeetingGroupProposedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupProposedDomainEvent(\\r\\n            MeetingGroupProposalId meetingGroupProposalId,\\r\\n            string name,\\r\\n            string description,\\r\\n            MemberId proposalUserId,\\r\\n            DateTime proposalDate,\\r\\n            string locationCity,\\r\\n            string locationCountryCode)\\r\\n        {\\r\\n            this.MeetingGroupProposalId = meetingGroupProposalId;\\r\\n            this.Name = name;\\r\\n            this.Description = description;\\r\\n            this.LocationCity = locationCity;\\r\\n            this.LocationCountryCode = locationCountryCode;\\r\\n            this.ProposalDate = proposalDate;\\r\\n            this.ProposalUserId = proposalUserId;\\r\\n        }\\r\\n\\r\\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\\r\\n\\r\\n        public string Name { get; }\\r\\n\\r\\n        public string Description { get; }\\r\\n\\r\\n        public string LocationCity { get; }\\r\\n\\r\\n        public string LocationCountryCode { get; }\\r\\n\\r\\n        public MemberId ProposalUserId { get; }\\r\\n\\r\\n        public DateTime ProposalDate { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"84\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":17,\"column\":9},\"end\":{\"line\":25,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroupProposals\\\\IMeetingGroupProposalRepository.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Threading.Tasks;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\\r\\n{\\r\\n    public interface IMeetingGroupProposalRepository\\r\\n    {\\r\\n        Task AddAsync(MeetingGroupProposal meetingGroupProposal);\\r\\n\\r\\n        Task\\u003CMeetingGroupProposal\\u003E GetByIdAsync(MeetingGroupProposalId meetingGroupProposalId);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingGroupProposals\\\\MeetingGroupProposal.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\\r\\n{\\r\\n    public class MeetingGroupProposal : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingGroupProposalId Id { get; private set; }\\r\\n\\r\\n        private string _name;\\r\\n\\r\\n        private string _description;\\r\\n\\r\\n        private MeetingGroupLocation _location;\\r\\n\\r\\n        private DateTime _proposalDate;\\r\\n\\r\\n        private MemberId _proposalUserId;\\r\\n\\r\\n        private MeetingGroupProposalStatus _status;\\r\\n\\r\\n        public MeetingGroup CreateMeetingGroup()\\r\\n        {\\r\\n            return MeetingGroup.CreateBasedOnProposal(this.Id, _name, _description, _location, _proposalUserId);\\r\\n        }\\r\\n\\r\\n        private MeetingGroupProposal()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        private MeetingGroupProposal(\\r\\n            string name,\\r\\n            string description,\\r\\n            MeetingGroupLocation location,\\r\\n            MemberId proposalUserId)\\r\\n        {\\r\\n            Id = new MeetingGroupProposalId(Guid.NewGuid());\\r\\n            _name = name;\\r\\n            _description = description;\\r\\n            _location = location;\\r\\n            _proposalUserId = proposalUserId;\\r\\n            _proposalDate = SystemClock.Now;\\r\\n            _status = MeetingGroupProposalStatus.InVerification;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupProposedDomainEvent(this.Id, _name, _description, proposalUserId, _proposalDate, _location.City, _location.CountryCode));\\r\\n        }\\r\\n\\r\\n        public static MeetingGroupProposal ProposeNew(\\r\\n            string name,\\r\\n            string description,\\r\\n            MeetingGroupLocation location,\\r\\n            MemberId proposalMemberId)\\r\\n        {\\r\\n            return new MeetingGroupProposal(name, description, location, proposalMemberId);\\r\\n        }\\r\\n\\r\\n        public void Accept()\\r\\n        {\\r\\n            this.CheckRule(new MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule(_status));\\r\\n\\r\\n            _status = MeetingGroupProposalStatus.Accepted;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupProposalAcceptedDomainEvent(this.Id));\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"85\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":28,\"column\":9},\"end\":{\"line\":30,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"86\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":42,\"column\":9},\"end\":{\"line\":52,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"87\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":51,\"column\":13},\"end\":{\"line\":51,\"column\":170}},\"status\":\"Killed\",\"static\":false},{\"id\":\"88\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":59,\"column\":9},\"end\":{\"line\":61,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"89\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":64,\"column\":9},\"end\":{\"line\":70,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"90\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":65,\"column\":13},\"end\":{\"line\":65,\"column\":95}},\"status\":\"Killed\",\"static\":false},{\"id\":\"91\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":69,\"column\":13},\"end\":{\"line\":69,\"column\":87}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroupProposals\\\\MeetingGroupProposalId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\\r\\n{\\r\\n    public class MeetingGroupProposalId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingGroupProposalId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingGroupProposals\\\\MeetingGroupProposalStatus.cs\":{\"language\":\"cs\",\"source\":\"using System.Reflection.Metadata;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\\r\\n{\\r\\n    public class MeetingGroupProposalStatus : ValueObject\\r\\n    {\\r\\n        public string Value { get; }\\r\\n\\r\\n        internal static MeetingGroupProposalStatus InVerification =\\u003E new MeetingGroupProposalStatus(\\u0022InVerification\\u0022);\\r\\n\\r\\n        internal static MeetingGroupProposalStatus Accepted =\\u003E new MeetingGroupProposalStatus(\\u0022Accepted\\u0022);\\r\\n\\r\\n        internal bool IsAccepted =\\u003E Value == \\u0022Accepted\\u0022;\\r\\n\\r\\n        private MeetingGroupProposalStatus(string value)\\r\\n        {\\r\\n            Value = value;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"92\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":10,\"column\":101},\"end\":{\"line\":10,\"column\":117}},\"status\":\"Survived\",\"static\":false},{\"id\":\"93\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":12,\"column\":95},\"end\":{\"line\":12,\"column\":105}},\"status\":\"Killed\",\"static\":false},{\"id\":\"94\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"Value != \\u0022Accepted\\u0022\",\"location\":{\"start\":{\"line\":14,\"column\":37},\"end\":{\"line\":14,\"column\":56}},\"status\":\"Killed\",\"static\":false},{\"id\":\"95\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":14,\"column\":46},\"end\":{\"line\":14,\"column\":56}},\"status\":\"Killed\",\"static\":false},{\"id\":\"96\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":17,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroupProposals\\\\Rules\\\\MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Rules\\r\\n{\\r\\n    public class MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroupProposalStatus _actualStatus;\\r\\n\\r\\n        internal MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule(MeetingGroupProposalStatus actualStatus)\\r\\n        {\\r\\n            _actualStatus = actualStatus;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _actualStatus.IsAccepted;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting group proposal cannot be accepted more than once rule\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"97\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"98\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":97}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingAttendeeChangedDecisionDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingAttendeeChangedDecisionDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingAttendeeChangedDecisionDomainEvent(MemberId memberId, MeetingId meetingId)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"99\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingGroupCreatedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingGroupCreatedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public MemberId CreatorId { get; }\\r\\n\\r\\n        public MeetingGroupCreatedDomainEvent(MeetingGroupId meetingGroupId, MemberId creatorId)\\r\\n        {\\r\\n            this.MeetingGroupId = meetingGroupId;\\r\\n            this.CreatorId = creatorId;\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"100\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingGroupGeneralAttributesEditedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingGroupGeneralAttributesEditedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public string NewName { get; }\\r\\n\\r\\n        public string NewDescription { get; }\\r\\n\\r\\n        public MeetingGroupLocation NewLocation { get; }\\r\\n\\r\\n        public MeetingGroupGeneralAttributesEditedDomainEvent(string newName, string newDescription, MeetingGroupLocation newLocation)\\r\\n        {\\r\\n            this.NewName = newName;\\r\\n            this.NewDescription = newDescription;\\r\\n            this.NewLocation = newLocation;\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"101\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingGroupMemberLeftGroupDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingGroupMemberLeftGroupDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupMemberLeftGroupDomainEvent(MeetingGroupId meetingGroupId, MemberId memberId)\\r\\n        {\\r\\n            MeetingGroupId = meetingGroupId;\\r\\n            MemberId = memberId;\\r\\n        }\\r\\n\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"102\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingGroupPaymentInfoUpdatedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingGroupPaymentInfoUpdatedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupPaymentInfoUpdatedDomainEvent(MeetingGroupId meetingGroupId, DateTime paymentDateTo)\\r\\n        {\\r\\n            MeetingGroupId = meetingGroupId;\\r\\n            PaymentDateTo = paymentDateTo;\\r\\n        }\\r\\n\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public DateTime PaymentDateTo { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"103\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\MeetingNotAttendeeChangedDecisionDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class MeetingNotAttendeeChangedDecisionDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingNotAttendeeChangedDecisionDomainEvent(MemberId memberId, MeetingId meetingId)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"104\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\Events\\\\NewMeetingGroupMemberJoinedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\\r\\n{\\r\\n    public class NewMeetingGroupMemberJoinedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingGroupMemberRole Role { get; }\\r\\n\\r\\n        public NewMeetingGroupMemberJoinedDomainEvent(MeetingGroupId meetingGroupId, MemberId memberId, MeetingGroupMemberRole role)\\r\\n        {\\r\\n            this.MeetingGroupId = meetingGroupId;\\r\\n            this.MemberId = memberId;\\r\\n            this.Role = role;\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"105\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\IMeetingGroupRepository.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Threading.Tasks;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public interface IMeetingGroupRepository\\r\\n    {\\r\\n        Task AddAsync(MeetingGroup meetingGroup);\\r\\n\\r\\n        Task\\u003Cint\\u003E Commit();\\r\\n\\r\\n        Task\\u003CMeetingGroup\\u003E GetByIdAsync(MeetingGroupId id);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingGroups\\\\MeetingGroup.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Collections.Generic;\\r\\nusing System.Diagnostics;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public class MeetingGroup : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingGroupId Id { get; private set; }\\r\\n\\r\\n        private string _name;\\r\\n\\r\\n        private string _description;\\r\\n\\r\\n        private MeetingGroupLocation _location;\\r\\n\\r\\n        private MemberId _creatorId;\\r\\n\\r\\n        private List\\u003CMeetingGroupMember\\u003E _members;\\r\\n\\r\\n        private DateTime _createDate;\\r\\n\\r\\n        private DateTime? _paymentDateTo;\\r\\n\\r\\n        internal static MeetingGroup CreateBasedOnProposal(\\r\\n            MeetingGroupProposalId meetingGroupProposalId,\\r\\n            string name,\\r\\n            string description,\\r\\n            MeetingGroupLocation location,\\r\\n            MemberId creatorId)\\r\\n        {\\r\\n            return new MeetingGroup(meetingGroupProposalId, name, description, location, creatorId);\\r\\n        }\\r\\n\\r\\n        private MeetingGroup()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        private MeetingGroup(MeetingGroupProposalId meetingGroupProposalId, string name, string description, MeetingGroupLocation location, MemberId creatorId)\\r\\n        {\\r\\n            this.Id = new MeetingGroupId(meetingGroupProposalId.Value);\\r\\n            this._name = name;\\r\\n            this._description = description;\\r\\n            this._creatorId = creatorId;\\r\\n            this._location = location;\\r\\n            this._createDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupCreatedDomainEvent(this.Id, creatorId));\\r\\n\\r\\n            this._members = new List\\u003CMeetingGroupMember\\u003E();\\r\\n            this._members.Add(MeetingGroupMember.CreateNew(this.Id, this._creatorId, MeetingGroupMemberRole.Organizer));\\r\\n        }\\r\\n\\r\\n        public void EditGeneralAttributes(string name, string description, MeetingGroupLocation location)\\r\\n        {\\r\\n            this._name = name;\\r\\n            this._description = description;\\r\\n            this._location = location;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupGeneralAttributesEditedDomainEvent(this._name, this._description, this._location));\\r\\n        }\\r\\n\\r\\n        public void JoinToGroupMember(MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingGroupMemberCannotBeAddedTwiceRule(_members, memberId));\\r\\n\\r\\n            this._members.Add(MeetingGroupMember.CreateNew(this.Id, memberId, MeetingGroupMemberRole.Member));\\r\\n        }\\r\\n\\r\\n        public void LeaveGroup(MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new NotActualGroupMemberCannotLeaveGroupRule(_members, memberId));\\r\\n\\r\\n            var member = this._members.Single(x =\\u003E x.IsMember(memberId));\\r\\n\\r\\n            member.Leave();\\r\\n        }\\r\\n\\r\\n        public void SetExpirationDate(DateTime dateTo)\\r\\n        {\\r\\n            _paymentDateTo = dateTo;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupPaymentInfoUpdatedDomainEvent(this.Id, _paymentDateTo.Value));\\r\\n        }\\r\\n\\r\\n        public Meeting CreateMeeting(\\r\\n            string title,\\r\\n            MeetingTerm term,\\r\\n            string description,\\r\\n            MeetingLocation location,\\r\\n            int? attendeesLimit,\\r\\n            int guestsLimit,\\r\\n            Term rsvpTerm,\\r\\n            MoneyValue eventFee,\\r\\n            List\\u003CMemberId\\u003E hostsMembersIds,\\r\\n            MemberId creatorId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCanBeOrganizedOnlyByPayedGroupRule(_paymentDateTo));\\r\\n\\r\\n            this.CheckRule(new MeetingHostMustBeAMeetingGroupMemberRule(creatorId, hostsMembersIds, _members));\\r\\n\\r\\n            return Meeting.CreateNew(\\r\\n                this.Id,\\r\\n                title,\\r\\n                term,\\r\\n                description,\\r\\n                location,\\r\\n                MeetingLimits.Create(attendeesLimit, guestsLimit),\\r\\n                rsvpTerm,\\r\\n                eventFee,\\r\\n                hostsMembersIds,\\r\\n                creatorId);\\r\\n        }\\r\\n\\r\\n        internal bool IsMemberOfGroup(MemberId attendeeId)\\r\\n        {\\r\\n            return _members.Any(x =\\u003E x.IsMember(attendeeId));\\r\\n        }\\r\\n\\r\\n        internal bool IsOrganizer(MemberId memberId)\\r\\n        {\\r\\n            return _members.Any(x =\\u003E x.IsOrganizer(memberId));\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"106\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":40,\"column\":9},\"end\":{\"line\":42,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"107\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":50,\"column\":9},\"end\":{\"line\":62,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"108\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":58,\"column\":13},\"end\":{\"line\":58,\"column\":89}},\"status\":\"Killed\",\"static\":false},{\"id\":\"109\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":61,\"column\":13},\"end\":{\"line\":61,\"column\":121}},\"status\":\"Killed\",\"static\":false},{\"id\":\"110\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":65,\"column\":9},\"end\":{\"line\":71,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"111\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":70,\"column\":13},\"end\":{\"line\":70,\"column\":132}},\"status\":\"Killed\",\"static\":false},{\"id\":\"112\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":74,\"column\":9},\"end\":{\"line\":78,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"113\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":75,\"column\":13},\"end\":{\"line\":75,\"column\":94}},\"status\":\"Killed\",\"static\":false},{\"id\":\"114\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":77,\"column\":13},\"end\":{\"line\":77,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"115\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":81,\"column\":9},\"end\":{\"line\":87,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"116\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":82,\"column\":13},\"end\":{\"line\":82,\"column\":94}},\"status\":\"Killed\",\"static\":false},{\"id\":\"117\",\"mutatorName\":\"Linq method mutation (Single() to SingleOrDefault())\",\"replacement\":\"this._members.SingleOrDefault(x =\\u003E x.IsMember(memberId))\",\"location\":{\"start\":{\"line\":84,\"column\":26},\"end\":{\"line\":84,\"column\":73}},\"status\":\"Survived\",\"static\":false},{\"id\":\"118\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":86,\"column\":13},\"end\":{\"line\":86,\"column\":28}},\"status\":\"Killed\",\"static\":false},{\"id\":\"119\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":90,\"column\":9},\"end\":{\"line\":94,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"120\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":93,\"column\":13},\"end\":{\"line\":93,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"121\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":107,\"column\":9},\"end\":{\"line\":123,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"122\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":108,\"column\":13},\"end\":{\"line\":108,\"column\":91}},\"status\":\"Killed\",\"static\":false},{\"id\":\"123\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":110,\"column\":13},\"end\":{\"line\":110,\"column\":112}},\"status\":\"Killed\",\"static\":false},{\"id\":\"124\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":126,\"column\":9},\"end\":{\"line\":128,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"125\",\"mutatorName\":\"Linq method mutation (Any() to All())\",\"replacement\":\"_members.All(x =\\u003E x.IsMember(attendeeId))\",\"location\":{\"start\":{\"line\":127,\"column\":20},\"end\":{\"line\":127,\"column\":61}},\"status\":\"Killed\",\"static\":false},{\"id\":\"126\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":131,\"column\":9},\"end\":{\"line\":133,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"127\",\"mutatorName\":\"Linq method mutation (Any() to All())\",\"replacement\":\"_members.All(x =\\u003E x.IsOrganizer(memberId))\",\"location\":{\"start\":{\"line\":132,\"column\":20},\"end\":{\"line\":132,\"column\":62}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\MeetingGroupId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public class MeetingGroupId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingGroupId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingGroups\\\\MeetingGroupLocation.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public class MeetingGroupLocation : ValueObject\\r\\n    {\\r\\n        public static MeetingGroupLocation CreateNew(string city, string countryCode)\\r\\n        {\\r\\n            return new MeetingGroupLocation(city, countryCode);\\r\\n        }\\r\\n\\r\\n        public string City { get; }\\r\\n\\r\\n        public string CountryCode { get; }\\r\\n\\r\\n        private MeetingGroupLocation(string city, string countryCode)\\r\\n        {\\r\\n            City = city;\\r\\n            CountryCode = countryCode;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"128\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":8,\"column\":9},\"end\":{\"line\":10,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"129\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":17,\"column\":9},\"end\":{\"line\":20,\"column\":10}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroups\\\\MeetingGroupMember.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public class MeetingGroupMember : Entity\\r\\n    {\\r\\n        internal MeetingGroupId MeetingGroupId { get; private set; }\\r\\n\\r\\n        internal MemberId MemberId { get; private set; }\\r\\n\\r\\n        private MeetingGroupMemberRole _role;\\r\\n\\r\\n        internal DateTime JoinedDate { get; private set; }\\r\\n\\r\\n        private bool _isActive;\\r\\n\\r\\n        private DateTime? _leaveDate;\\r\\n\\r\\n        private MeetingGroupMember()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        private MeetingGroupMember(\\r\\n            MeetingGroupId meetingGroupId,\\r\\n            MemberId memberId,\\r\\n            MeetingGroupMemberRole role)\\r\\n        {\\r\\n            this.MeetingGroupId = meetingGroupId;\\r\\n            this.MemberId = memberId;\\r\\n            this._role = role;\\r\\n            this.JoinedDate = SystemClock.Now;\\r\\n            this._isActive = true;\\r\\n\\r\\n            this.AddDomainEvent(new NewMeetingGroupMemberJoinedDomainEvent(this.MeetingGroupId, this.MemberId, this._role));\\r\\n        }\\r\\n\\r\\n        internal static MeetingGroupMember CreateNew(\\r\\n            MeetingGroupId meetingGroupId,\\r\\n            MemberId memberId,\\r\\n            MeetingGroupMemberRole role)\\r\\n        {\\r\\n            return new MeetingGroupMember(meetingGroupId, memberId, role);\\r\\n        }\\r\\n\\r\\n        internal void Leave()\\r\\n        {\\r\\n            _isActive = false;\\r\\n            _leaveDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingGroupMemberLeftGroupDomainEvent(this.MeetingGroupId, this.MemberId));\\r\\n        }\\r\\n\\r\\n        internal bool IsMember(MemberId memberId)\\r\\n        {\\r\\n            return this._isActive \\u0026\\u0026 this.MemberId == memberId;\\r\\n        }\\r\\n\\r\\n        internal bool IsOrganizer(MemberId memberId)\\r\\n        {\\r\\n            return this.IsMember(memberId) \\u0026\\u0026 _role == MeetingGroupMemberRole.Organizer;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"130\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":32,\"column\":9},\"end\":{\"line\":40,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"131\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":37,\"column\":30},\"end\":{\"line\":37,\"column\":34}},\"status\":\"Killed\",\"static\":false},{\"id\":\"132\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":39,\"column\":13},\"end\":{\"line\":39,\"column\":125}},\"status\":\"Killed\",\"static\":false},{\"id\":\"133\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":46,\"column\":9},\"end\":{\"line\":48,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"134\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":51,\"column\":9},\"end\":{\"line\":56,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"135\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":52,\"column\":25},\"end\":{\"line\":52,\"column\":30}},\"status\":\"Survived\",\"static\":false},{\"id\":\"136\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":55,\"column\":13},\"end\":{\"line\":55,\"column\":113}},\"status\":\"Killed\",\"static\":false},{\"id\":\"137\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":59,\"column\":9},\"end\":{\"line\":61,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"138\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this._isActive || this.MemberId == memberId\",\"location\":{\"start\":{\"line\":60,\"column\":20},\"end\":{\"line\":60,\"column\":63}},\"status\":\"Killed\",\"static\":false},{\"id\":\"139\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.MemberId != memberId\",\"location\":{\"start\":{\"line\":60,\"column\":38},\"end\":{\"line\":60,\"column\":63}},\"status\":\"Killed\",\"static\":false},{\"id\":\"140\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":64,\"column\":9},\"end\":{\"line\":66,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"141\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this.IsMember(memberId) || _role == MeetingGroupMemberRole.Organizer\",\"location\":{\"start\":{\"line\":65,\"column\":20},\"end\":{\"line\":65,\"column\":88}},\"status\":\"Killed\",\"static\":false},{\"id\":\"142\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_role != MeetingGroupMemberRole.Organizer\",\"location\":{\"start\":{\"line\":65,\"column\":47},\"end\":{\"line\":65,\"column\":88}},\"status\":\"Killed\",\"static\":false}]},\"MeetingGroups\\\\MeetingGroupMemberRole.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\\r\\n{\\r\\n    public class MeetingGroupMemberRole : ValueObject\\r\\n    {\\r\\n        public static MeetingGroupMemberRole Organizer =\\u003E new MeetingGroupMemberRole(\\u0022Organizer\\u0022);\\r\\n\\r\\n        public static MeetingGroupMemberRole Member =\\u003E new MeetingGroupMemberRole(\\u0022Member\\u0022);\\r\\n\\r\\n        public string Value { get; }\\r\\n\\r\\n        private MeetingGroupMemberRole(string value)\\r\\n        {\\r\\n            this.Value = value;\\r\\n        }\\r\\n\\r\\n        public static MeetingGroupMemberRole Of(string roleCode)\\r\\n        {\\r\\n            return new MeetingGroupMemberRole(roleCode);\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"143\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":7,\"column\":86},\"end\":{\"line\":7,\"column\":97}},\"status\":\"Survived\",\"static\":false},{\"id\":\"144\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":9,\"column\":83},\"end\":{\"line\":9,\"column\":91}},\"status\":\"Survived\",\"static\":false},{\"id\":\"145\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"146\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":19,\"column\":9},\"end\":{\"line\":21,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"MeetingGroups\\\\Policies\\\\MeetingGroupExpirationDatePolicy.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Policies\\r\\n{\\r\\n    public static class MeetingGroupExpirationDatePolicy\\r\\n    {\\r\\n        public static List\\u003CMeetingGroupId\\u003E GetMeetingGroupsCoveredByMemberSubscription(\\r\\n            List\\u003CMeetingGroupMemberData\\u003E meetingGroups)\\r\\n        {\\r\\n            return meetingGroups\\r\\n                .Where(x =\\u003E x.Role == MeetingGroupMemberRole.Organizer)\\r\\n                .Select(x =\\u003E x.MeetingGroupId)\\r\\n                .ToList();\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"147\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"148\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"x.Role != MeetingGroupMemberRole.Organizer\",\"location\":{\"start\":{\"line\":12,\"column\":29},\"end\":{\"line\":12,\"column\":71}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"MeetingGroups\\\\Policies\\\\MeetingGroupMemberData.cs\":{\"language\":\"cs\",\"source\":\"namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Policies\\r\\n{\\r\\n    public class MeetingGroupMemberData\\r\\n    {\\r\\n        public MeetingGroupMemberData(MeetingGroupId meetingGroupId, MeetingGroupMemberRole role)\\r\\n        {\\r\\n            MeetingGroupId = meetingGroupId;\\r\\n            Role = role;\\r\\n        }\\r\\n\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public MeetingGroupMemberRole Role { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"149\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":6,\"column\":9},\"end\":{\"line\":9,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"MeetingGroups\\\\Rules\\\\MeetingCanBeOrganizedOnlyByPayedGroupRule.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\\r\\n{\\r\\n    public class MeetingCanBeOrganizedOnlyByPayedGroupRule : IBusinessRule\\r\\n    {\\r\\n        private readonly DateTime? _paymentDateTo;\\r\\n\\r\\n        internal MeetingCanBeOrganizedOnlyByPayedGroupRule(DateTime? paymentDateTo)\\r\\n        {\\r\\n            _paymentDateTo = paymentDateTo;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_paymentDateTo.HasValue || _paymentDateTo \\u003C SystemClock.Now;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting can be organized only by payed group\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"150\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":14,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"151\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!_paymentDateTo.HasValue \\u0026\\u0026 _paymentDateTo \\u003C SystemClock.Now\",\"location\":{\"start\":{\"line\":16,\"column\":35},\"end\":{\"line\":16,\"column\":95}},\"status\":\"Killed\",\"static\":false},{\"id\":\"152\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_paymentDateTo.HasValue \",\"location\":{\"start\":{\"line\":16,\"column\":35},\"end\":{\"line\":16,\"column\":59}},\"status\":\"Killed\",\"static\":false},{\"id\":\"153\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_paymentDateTo \\u003E SystemClock.Now\",\"location\":{\"start\":{\"line\":16,\"column\":63},\"end\":{\"line\":16,\"column\":95}},\"status\":\"Killed\",\"static\":false},{\"id\":\"154\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_paymentDateTo \\u003C= SystemClock.Now\",\"location\":{\"start\":{\"line\":16,\"column\":63},\"end\":{\"line\":16,\"column\":95}},\"status\":\"Survived\",\"static\":false},{\"id\":\"155\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":18,\"column\":34},\"end\":{\"line\":18,\"column\":80}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroups\\\\Rules\\\\MeetingGroupMemberCannotBeAddedTwiceRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\\r\\n{\\r\\n    public class MeetingGroupMemberCannotBeAddedTwiceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingGroupMember\\u003E _members;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        public MeetingGroupMemberCannotBeAddedTwiceRule(List\\u003CMeetingGroupMember\\u003E members, MemberId memberId)\\r\\n            : base()\\r\\n        {\\r\\n            _members = members;\\r\\n            _memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E this._members.SingleOrDefault(x =\\u003E x.IsMember(_memberId)) != null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member cannot be added twice to the same group\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"156\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":16,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"157\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._members.SingleOrDefault(x =\\u003E x.IsMember(_memberId)) == null\",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":100}},\"status\":\"Killed\",\"static\":false},{\"id\":\"158\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"this._members.Single(x =\\u003E x.IsMember(_memberId)) \",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":92}},\"status\":\"Killed\",\"static\":false},{\"id\":\"159\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":23,\"column\":34},\"end\":{\"line\":23,\"column\":82}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroups\\\\Rules\\\\MeetingHostMustBeAMeetingGroupMemberRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\\r\\n{\\r\\n    public class MeetingHostMustBeAMeetingGroupMemberRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MemberId _creatorId;\\r\\n\\r\\n        private readonly List\\u003CMemberId\\u003E _hostsMembersIds;\\r\\n\\r\\n        private readonly List\\u003CMeetingGroupMember\\u003E _members;\\r\\n\\r\\n        public MeetingHostMustBeAMeetingGroupMemberRule(\\r\\n            MemberId creatorId,\\r\\n            List\\u003CMemberId\\u003E hostsMembersIds,\\r\\n            List\\u003CMeetingGroupMember\\u003E members)\\r\\n        {\\r\\n            _creatorId = creatorId;\\r\\n            _hostsMembersIds = hostsMembersIds;\\r\\n            _members = members;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken()\\r\\n        {\\r\\n            var memberIds = _members.Select(x =\\u003E x.MemberId).ToList();\\r\\n            if (!_hostsMembersIds.Any() \\u0026\\u0026 !memberIds.Contains(_creatorId))\\r\\n            {\\r\\n                return true;\\r\\n            }\\r\\n\\r\\n            return _hostsMembersIds.Any() \\u0026\\u0026 _hostsMembersIds.Except(memberIds).Any();\\r\\n        }\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting host must be a meeting group member\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"160\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":20,\"column\":9},\"end\":{\"line\":24,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"161\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":27,\"column\":9},\"end\":{\"line\":35,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"162\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!_hostsMembersIds.Any() || !memberIds.Contains(_creatorId)\",\"location\":{\"start\":{\"line\":29,\"column\":17},\"end\":{\"line\":29,\"column\":75}},\"status\":\"Killed\",\"static\":false},{\"id\":\"163\",\"mutatorName\":\"Negate expression\",\"replacement\":\"!(!_hostsMembersIds.Any() \\u0026\\u0026 !memberIds.Contains(_creatorId))\",\"location\":{\"start\":{\"line\":29,\"column\":17},\"end\":{\"line\":29,\"column\":75}},\"status\":\"Killed\",\"static\":false},{\"id\":\"164\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_hostsMembersIds.Any() \",\"location\":{\"start\":{\"line\":29,\"column\":17},\"end\":{\"line\":29,\"column\":40}},\"status\":\"Killed\",\"static\":false},{\"id\":\"165\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"memberIds.Contains(_creatorId)\",\"location\":{\"start\":{\"line\":29,\"column\":44},\"end\":{\"line\":29,\"column\":75}},\"status\":\"Killed\",\"static\":false},{\"id\":\"166\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":30,\"column\":13},\"end\":{\"line\":32,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"167\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":31,\"column\":24},\"end\":{\"line\":31,\"column\":28}},\"status\":\"Killed\",\"static\":false},{\"id\":\"168\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"_hostsMembersIds.Any() || _hostsMembersIds.Except(memberIds).Any()\",\"location\":{\"start\":{\"line\":34,\"column\":20},\"end\":{\"line\":34,\"column\":86}},\"status\":\"Killed\",\"static\":false},{\"id\":\"169\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":37,\"column\":34},\"end\":{\"line\":37,\"column\":79}},\"status\":\"Survived\",\"static\":false}]},\"MeetingGroups\\\\Rules\\\\NotActualGroupMemberCannotLeaveGroupRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\\r\\n{\\r\\n    public class NotActualGroupMemberCannotLeaveGroupRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingGroupMember\\u003E _members;\\r\\n\\r\\n        private readonly MemberId memberId;\\r\\n\\r\\n        public NotActualGroupMemberCannotLeaveGroupRule(List\\u003CMeetingGroupMember\\u003E members, MemberId memberId)\\r\\n            : base()\\r\\n        {\\r\\n            _members = members;\\r\\n            this.memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E this._members.SingleOrDefault(x =\\u003E x.IsMember(memberId)) == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member is not member of this group so he cannot leave it\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"170\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":16,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"171\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._members.SingleOrDefault(x =\\u003E x.IsMember(memberId)) != null\",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"172\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"this._members.Single(x =\\u003E x.IsMember(memberId)) \",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":91}},\"status\":\"Killed\",\"static\":false},{\"id\":\"173\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":23,\"column\":34},\"end\":{\"line\":23,\"column\":92}},\"status\":\"Survived\",\"static\":false}]},\"MeetingMemberCommentLikes\\\\Events\\\\MeetingCommentLikedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events\\r\\n{\\r\\n    public class MeetingCommentLikedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public MemberId LikerId { get; }\\r\\n\\r\\n        public MeetingCommentLikedDomainEvent(MeetingCommentId meetingCommentId, MemberId likerId)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n            LikerId = likerId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"174\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":17,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingMemberCommentLikes\\\\Events\\\\MeetingCommentUnlikedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events\\r\\n{\\r\\n    public class MeetingCommentUnlikedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCommentId MeetingCommentId { get; }\\r\\n\\r\\n        public MemberId LikerId { get; }\\r\\n\\r\\n        public MeetingCommentUnlikedDomainEvent(MeetingCommentId meetingCommentId, MemberId likerId)\\r\\n        {\\r\\n            MeetingCommentId = meetingCommentId;\\r\\n            LikerId = likerId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"175\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":17,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"MeetingMemberCommentLikes\\\\IMeetingMemberCommentLikesRepository.cs\":{\"language\":\"cs\",\"source\":\"using System.Threading.Tasks;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\\r\\n{\\r\\n    public interface IMeetingMemberCommentLikesRepository\\r\\n    {\\r\\n        Task AddAsync(MeetingMemberCommentLike meetingMemberCommentLike);\\r\\n\\r\\n        Task\\u003CMeetingMemberCommentLike\\u003E GetAsync(MemberId memberId, MeetingCommentId meetingCommentId);\\r\\n\\r\\n        Task\\u003Cint\\u003E CountMemberCommentLikesAsync(MemberId memberId, MeetingCommentId meetingCommentId);\\r\\n\\r\\n        void Remove(MeetingMemberCommentLike meetingMemberCommentLike);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"MeetingMemberCommentLikes\\\\MeetingMemberCommentLike.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Comments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\\r\\n{\\r\\n    public class MeetingMemberCommentLike : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingMemberCommentLikeId Id { get; }\\r\\n\\r\\n        private MeetingCommentId _meetingCommentId;\\r\\n\\r\\n        private MemberId _memberId;\\r\\n\\r\\n        private MeetingMemberCommentLike()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        private MeetingMemberCommentLike(MeetingCommentId meetingCommentId, MemberId memberId)\\r\\n        {\\r\\n            Id = new MeetingMemberCommentLikeId(Guid.NewGuid());\\r\\n            _meetingCommentId = meetingCommentId;\\r\\n            _memberId = memberId;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingCommentLikedDomainEvent(meetingCommentId, memberId));\\r\\n        }\\r\\n\\r\\n        public void Remove()\\r\\n        {\\r\\n            this.AddDomainEvent(new MeetingCommentUnlikedDomainEvent(_meetingCommentId, _memberId));\\r\\n        }\\r\\n\\r\\n        public static MeetingMemberCommentLike Create(MeetingCommentId meetingCommentId, MemberId memberId)\\r\\n            =\\u003E new MeetingMemberCommentLike(meetingCommentId, memberId);\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"176\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":23,\"column\":9},\"end\":{\"line\":29,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"177\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":28,\"column\":13},\"end\":{\"line\":28,\"column\":97}},\"status\":\"Killed\",\"static\":false},{\"id\":\"178\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":32,\"column\":9},\"end\":{\"line\":34,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"179\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":33,\"column\":13},\"end\":{\"line\":33,\"column\":101}},\"status\":\"Killed\",\"static\":false}]},\"MeetingMemberCommentLikes\\\\MeetingMemberCommentLikeId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\\r\\n{\\r\\n    public class MeetingMemberCommentLikeId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingMemberCommentLikeId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Meetings\\\\Events\\\\MeetingAttendeeAddedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingAttendeeAddedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingAttendeeAddedDomainEvent(\\r\\n            MeetingId meetingId,\\r\\n            MemberId attendeeId,\\r\\n            DateTime rsvpDate,\\r\\n            string role,\\r\\n            int guestsNumber,\\r\\n            decimal? feeValue,\\r\\n            string feeCurrency)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            AttendeeId = attendeeId;\\r\\n            RSVPDate = rsvpDate;\\r\\n            Role = role;\\r\\n            GuestsNumber = guestsNumber;\\r\\n            FeeValue = feeValue;\\r\\n            FeeCurrency = feeCurrency;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId AttendeeId { get; }\\r\\n\\r\\n        public DateTime RSVPDate { get; }\\r\\n\\r\\n        public string Role { get; }\\r\\n\\r\\n        public int GuestsNumber { get; }\\r\\n\\r\\n        public decimal? FeeValue { get; }\\r\\n\\r\\n        public string FeeCurrency { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"180\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":17,\"column\":9},\"end\":{\"line\":25,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingAttendeeFeePaidDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingAttendeeFeePaidDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingAttendeeFeePaidDomainEvent(MeetingId meetingId, MemberId attendeeId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            AttendeeId = attendeeId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId AttendeeId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"181\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":13,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingAttendeeRemovedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingAttendeeRemovedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingAttendeeRemovedDomainEvent(MemberId memberId, MeetingId meetingId, string reason)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n            MeetingId = meetingId;\\r\\n            Reason = reason;\\r\\n        }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public string Reason { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"182\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":14,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingCanceledDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingCanceledDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCanceledDomainEvent(MeetingId meetingId, MemberId cancelMemberId, DateTime cancelDate)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            CancelMemberId = cancelMemberId;\\r\\n            CancelDate = cancelDate;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId CancelMemberId { get; }\\r\\n\\r\\n        public DateTime CancelDate { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"183\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":14,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingCreatedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingCreatedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingCreatedDomainEvent(MeetingId meetingId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"184\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":8,\"column\":9},\"end\":{\"line\":10,\"column\":10}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingEditedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingEditedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingEditedDomainEvent(Guid meetingId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n\\r\\n        public Guid MeetingId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"185\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":11,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingMainAttributesChangedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingMainAttributesChangedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingMainAttributesChangedDomainEvent(MeetingId meetingId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"186\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":8,\"column\":9},\"end\":{\"line\":10,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingNotAttendeeAddedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingNotAttendeeAddedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingNotAttendeeAddedDomainEvent(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            MemberId = memberId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"187\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MeetingWaitlistMemberAddedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MeetingWaitlistMemberAddedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MeetingWaitlistMemberAddedDomainEvent(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            MemberId = memberId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"188\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MemberSetAsAttendeeDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MemberSetAsAttendeeDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MemberSetAsAttendeeDomainEvent(MeetingId meetingId, MemberId hostId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            HostId = hostId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId HostId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"189\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\MemberSignedOffFromMeetingWaitlistDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class MemberSignedOffFromMeetingWaitlistDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MemberSignedOffFromMeetingWaitlistDomainEvent(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            MemberId = memberId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"190\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\Events\\\\NewMeetingHostSetDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\\r\\n{\\r\\n    public class NewMeetingHostSetDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public NewMeetingHostSetDomainEvent(MeetingId meetingId, MemberId hostId)\\r\\n        {\\r\\n            MeetingId = meetingId;\\r\\n            HostId = hostId;\\r\\n        }\\r\\n\\r\\n        public MeetingId MeetingId { get; }\\r\\n\\r\\n        public MemberId HostId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"191\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\IMeetingRepository.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Threading.Tasks;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public interface IMeetingRepository\\r\\n    {\\r\\n        Task AddAsync(Meeting meeting);\\r\\n\\r\\n        Task\\u003CMeeting\\u003E GetByIdAsync(MeetingId id);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Meetings\\\\Meeting.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class Meeting : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MeetingId Id { get; private set; }\\r\\n\\r\\n        private MeetingGroupId _meetingGroupId;\\r\\n\\r\\n        private string _title;\\r\\n\\r\\n        private MeetingTerm _term;\\r\\n\\r\\n        private string _description;\\r\\n\\r\\n        private MeetingLocation _location;\\r\\n\\r\\n        private List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n\\r\\n        private List\\u003CMeetingNotAttendee\\u003E _notAttendees;\\r\\n\\r\\n        private List\\u003CMeetingWaitlistMember\\u003E _waitlistMembers;\\r\\n\\r\\n        private MeetingLimits _meetingLimits;\\r\\n\\r\\n        private Term _rsvpTerm;\\r\\n\\r\\n        private MoneyValue _eventFee;\\r\\n\\r\\n        private MemberId _creatorId;\\r\\n\\r\\n        private DateTime _createDate;\\r\\n\\r\\n        private MemberId _changeMemberId;\\r\\n\\r\\n        private DateTime? _changeDate;\\r\\n\\r\\n        private DateTime? _cancelDate;\\r\\n\\r\\n        private MemberId _cancelMemberId;\\r\\n\\r\\n        private bool _isCanceled;\\r\\n\\r\\n        private Meeting()\\r\\n        {\\r\\n            _attendees = new List\\u003CMeetingAttendee\\u003E();\\r\\n            _notAttendees = new List\\u003CMeetingNotAttendee\\u003E();\\r\\n            _waitlistMembers = new List\\u003CMeetingWaitlistMember\\u003E();\\r\\n        }\\r\\n\\r\\n        internal static Meeting CreateNew(\\r\\n            MeetingGroupId meetingGroupId,\\r\\n            string title,\\r\\n            MeetingTerm term,\\r\\n            string description,\\r\\n            MeetingLocation location,\\r\\n            MeetingLimits meetingLimits,\\r\\n            Term rsvpTerm,\\r\\n            MoneyValue eventFee,\\r\\n            List\\u003CMemberId\\u003E hostsMembersIds,\\r\\n            MemberId creatorId)\\r\\n        {\\r\\n            return new Meeting(\\r\\n                meetingGroupId,\\r\\n                title,\\r\\n                term,\\r\\n                description,\\r\\n                location,\\r\\n                meetingLimits,\\r\\n                rsvpTerm,\\r\\n                eventFee,\\r\\n                hostsMembersIds,\\r\\n                creatorId);\\r\\n        }\\r\\n\\r\\n        private Meeting(\\r\\n            MeetingGroupId meetingGroupId,\\r\\n            string title,\\r\\n            MeetingTerm term,\\r\\n            string description,\\r\\n            MeetingLocation location,\\r\\n            MeetingLimits meetingLimits,\\r\\n            Term rsvpTerm,\\r\\n            MoneyValue eventFee,\\r\\n            List\\u003CMemberId\\u003E hostsMembersIds,\\r\\n            MemberId creatorId)\\r\\n        {\\r\\n            Id = new MeetingId(Guid.NewGuid());\\r\\n            _meetingGroupId = meetingGroupId;\\r\\n            _title = title;\\r\\n            _term = term;\\r\\n            _description = description;\\r\\n            _location = location;\\r\\n            _meetingLimits = meetingLimits;\\r\\n\\r\\n            this.SetRsvpTerm(rsvpTerm, _term);\\r\\n            _eventFee = eventFee;\\r\\n            _creatorId = creatorId;\\r\\n            _createDate = SystemClock.Now;\\r\\n\\r\\n            _attendees = new List\\u003CMeetingAttendee\\u003E();\\r\\n            _notAttendees = new List\\u003CMeetingNotAttendee\\u003E();\\r\\n            _waitlistMembers = new List\\u003CMeetingWaitlistMember\\u003E();\\r\\n\\r\\n            this.AddDomainEvent(new MeetingCreatedDomainEvent(this.Id));\\r\\n            var rsvpDate = SystemClock.Now;\\r\\n            if (hostsMembersIds.Any())\\r\\n            {\\r\\n                foreach (var hostMemberId in hostsMembersIds)\\r\\n                {\\r\\n                    _attendees.Add(MeetingAttendee.CreateNew(this.Id, hostMemberId, rsvpDate, MeetingAttendeeRole.Host, 0, MoneyValue.Undefined));\\r\\n                }\\r\\n            }\\r\\n            else\\r\\n            {\\r\\n                _attendees.Add(MeetingAttendee.CreateNew(this.Id, creatorId, rsvpDate, MeetingAttendeeRole.Host, 0, MoneyValue.Undefined));\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public void ChangeMainAttributes(\\r\\n            string title,\\r\\n            MeetingTerm term,\\r\\n            string description,\\r\\n            MeetingLocation location,\\r\\n            MeetingLimits meetingLimits,\\r\\n            Term rsvpTerm,\\r\\n            MoneyValue eventFee,\\r\\n            MemberId modifyUserId)\\r\\n        {\\r\\n            this.CheckRule(new AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule(\\r\\n                meetingLimits,\\r\\n                this.GetAllActiveAttendeesWithGuestsNumber()));\\r\\n\\r\\n            _title = title;\\r\\n            _term = term;\\r\\n            _description = description;\\r\\n            _location = location;\\r\\n            _meetingLimits = meetingLimits;\\r\\n            this.SetRsvpTerm(rsvpTerm, _term);\\r\\n            _eventFee = eventFee;\\r\\n\\r\\n            _changeDate = SystemClock.Now;\\r\\n            _changeMemberId = modifyUserId;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingMainAttributesChangedDomainEvent(this.Id));\\r\\n        }\\r\\n\\r\\n        public void AddAttendee(MeetingGroup meetingGroup, MemberId attendeeId, int guestsNumber)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new AttendeeCanBeAddedOnlyInRsvpTermRule(_rsvpTerm));\\r\\n\\r\\n            this.CheckRule(new MeetingAttendeeMustBeAMemberOfGroupRule(attendeeId, meetingGroup));\\r\\n\\r\\n            this.CheckRule(new MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule(attendeeId, _attendees));\\r\\n\\r\\n            this.CheckRule(new MeetingGuestsNumberIsAboveLimitRule(_meetingLimits.GuestsLimit, guestsNumber));\\r\\n\\r\\n            this.CheckRule(new MeetingAttendeesNumberIsAboveLimitRule(_meetingLimits.AttendeesLimit, this.GetAllActiveAttendeesWithGuestsNumber(), guestsNumber));\\r\\n\\r\\n            var notAttendee = this.GetActiveNotAttendee(attendeeId);\\r\\n            notAttendee?.ChangeDecision();\\r\\n\\r\\n            _attendees.Add(MeetingAttendee.CreateNew(\\r\\n                this.Id,\\r\\n                attendeeId,\\r\\n                SystemClock.Now,\\r\\n                MeetingAttendeeRole.Attendee,\\r\\n                guestsNumber,\\r\\n                _eventFee));\\r\\n        }\\r\\n\\r\\n        public void AddNotAttendee(MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new MemberCannotBeNotAttendeeTwiceRule(_notAttendees, memberId));\\r\\n\\r\\n            _notAttendees.Add(MeetingNotAttendee.CreateNew(this.Id, memberId));\\r\\n\\r\\n            var attendee = this.GetActiveAttendee(memberId);\\r\\n\\r\\n            attendee?.ChangeDecision();\\r\\n\\r\\n            var nextWaitlistMember = _waitlistMembers\\r\\n                .Where(x =\\u003E x.IsActive())\\r\\n                .OrderBy(x =\\u003E x.SignUpDate)\\r\\n                .FirstOrDefault();\\r\\n            if (nextWaitlistMember != null)\\r\\n            {\\r\\n                _attendees.Add(MeetingAttendee.CreateNew(\\r\\n                    this.Id,\\r\\n                    nextWaitlistMember.MemberId,\\r\\n                    nextWaitlistMember.SignUpDate,\\r\\n                    MeetingAttendeeRole.Attendee,\\r\\n                    0,\\r\\n                    this._eventFee));\\r\\n                nextWaitlistMember.MarkIsMovedToAttendees();\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public void ChangeNotAttendeeDecision(MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new NotActiveNotAttendeeCannotChangeDecisionRule(_notAttendees, memberId));\\r\\n\\r\\n            var notAttendee = _notAttendees.Single(x =\\u003E x.IsActiveNotAttendee(memberId));\\r\\n\\r\\n            notAttendee.ChangeDecision();\\r\\n        }\\r\\n\\r\\n        public void SignUpMemberToWaitlist(MeetingGroup meetingGroup, MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new AttendeeCanBeAddedOnlyInRsvpTermRule(_rsvpTerm));\\r\\n\\r\\n            this.CheckRule(new MemberOnWaitlistMustBeAMemberOfGroupRule(meetingGroup, memberId, _attendees));\\r\\n\\r\\n            this.CheckRule(new MemberCannotBeMoreThanOnceOnMeetingWaitlistRule(_waitlistMembers, memberId));\\r\\n\\r\\n            _waitlistMembers.Add(MeetingWaitlistMember.CreateNew(this.Id, memberId));\\r\\n        }\\r\\n\\r\\n        public void SignOffMemberFromWaitlist(MemberId memberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new NotActiveMemberOfWaitlistCannotBeSignedOffRule(_waitlistMembers, memberId));\\r\\n\\r\\n            var memberOnWaitlist = this.GetActiveMemberOnWaitlist(memberId);\\r\\n\\r\\n            memberOnWaitlist.SignOff();\\r\\n        }\\r\\n\\r\\n        public void SetHostRole(MeetingGroup meetingGroup, MemberId settingMemberId, MemberId newOrganizerId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(settingMemberId, meetingGroup, _attendees));\\r\\n\\r\\n            this.CheckRule(new OnlyMeetingAttendeeCanHaveChangedRoleRule(_attendees, newOrganizerId));\\r\\n\\r\\n            var attendee = this.GetActiveAttendee(newOrganizerId);\\r\\n\\r\\n            attendee.SetAsHost();\\r\\n        }\\r\\n\\r\\n        public void SetAttendeeRole(MeetingGroup meetingGroup, MemberId settingMemberId, MemberId newOrganizerId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            this.CheckRule(new OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(settingMemberId, meetingGroup, _attendees));\\r\\n\\r\\n            this.CheckRule(new OnlyMeetingAttendeeCanHaveChangedRoleRule(_attendees, newOrganizerId));\\r\\n\\r\\n            var attendee = this.GetActiveAttendee(newOrganizerId);\\r\\n\\r\\n            attendee.SetAsAttendee();\\r\\n\\r\\n            var meetingHostNumber = _attendees.Count(x =\\u003E x.IsActiveHost());\\r\\n\\r\\n            this.CheckRule(new MeetingMustHaveAtLeastOneHostRule(meetingHostNumber));\\r\\n        }\\r\\n\\r\\n        public MeetingGroupId GetMeetingGroupId() =\\u003E _meetingGroupId;\\r\\n\\r\\n        public void Cancel(MemberId cancelMemberId)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n\\r\\n            if (!_isCanceled)\\r\\n            {\\r\\n                _isCanceled = true;\\r\\n                _cancelDate = SystemClock.Now;\\r\\n                _cancelMemberId = cancelMemberId;\\r\\n\\r\\n                this.AddDomainEvent(new MeetingCanceledDomainEvent(this.Id, _cancelMemberId, _cancelDate.Value));\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public void RemoveAttendee(MemberId attendeeId, MemberId removingPersonId, string reason)\\r\\n        {\\r\\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\\r\\n            this.CheckRule(new OnlyActiveAttendeeCanBeRemovedFromMeetingRule(_attendees, attendeeId));\\r\\n\\r\\n            var attendee = this.GetActiveAttendee(attendeeId);\\r\\n\\r\\n            attendee.Remove(removingPersonId, reason);\\r\\n        }\\r\\n\\r\\n        public void MarkAttendeeFeeAsPayed(MemberId memberId)\\r\\n        {\\r\\n            var attendee = GetActiveAttendee(memberId);\\r\\n\\r\\n            attendee.MarkFeeAsPayed();\\r\\n        }\\r\\n\\r\\n        public MeetingComment AddComment(MemberId authorId, string comment, MeetingGroup meetingGroup, MeetingCommentingConfiguration meetingCommentingConfiguration)\\r\\n            =\\u003E MeetingComment.Create(\\r\\n                this.Id,\\r\\n                authorId,\\r\\n                comment,\\r\\n                meetingGroup,\\r\\n                meetingCommentingConfiguration);\\r\\n\\r\\n        public MeetingCommentingConfiguration CreateCommentingConfiguration()\\r\\n        {\\r\\n            return MeetingCommentingConfiguration.Create(this.Id);\\r\\n        }\\r\\n\\r\\n        private MeetingWaitlistMember GetActiveMemberOnWaitlist(MemberId memberId)\\r\\n        {\\r\\n            return _waitlistMembers.SingleOrDefault(x =\\u003E x.IsActiveOnWaitList(memberId));\\r\\n        }\\r\\n\\r\\n        private MeetingAttendee GetActiveAttendee(MemberId attendeeId)\\r\\n        {\\r\\n            return _attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(attendeeId));\\r\\n        }\\r\\n\\r\\n        private MeetingNotAttendee GetActiveNotAttendee(MemberId memberId)\\r\\n        {\\r\\n            return _notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(memberId));\\r\\n        }\\r\\n\\r\\n        private int GetAllActiveAttendeesWithGuestsNumber()\\r\\n        {\\r\\n            return _attendees.Where(x =\\u003E x.IsActive()).Sum(x =\\u003E x.GetAttendeeWithGuestsNumber());\\r\\n        }\\r\\n\\r\\n        private void SetRsvpTerm(Term rsvpTerm, MeetingTerm meetingTerm)\\r\\n        {\\r\\n            if (!rsvpTerm.EndDate.HasValue || rsvpTerm.EndDate \\u003E meetingTerm.StartDate)\\r\\n            {\\r\\n                _rsvpTerm = Term.CreateNewBetweenDates(rsvpTerm.StartDate, meetingTerm.StartDate);\\r\\n            }\\r\\n            else\\r\\n            {\\r\\n                _rsvpTerm = rsvpTerm;\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\",\"mutants\":[{\"id\":\"192\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":56,\"column\":9},\"end\":{\"line\":60,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"193\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":73,\"column\":9},\"end\":{\"line\":85,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"194\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":98,\"column\":9},\"end\":{\"line\":129,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"195\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":107,\"column\":13},\"end\":{\"line\":107,\"column\":47}},\"status\":\"Killed\",\"static\":false},{\"id\":\"196\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":116,\"column\":13},\"end\":{\"line\":116,\"column\":73}},\"status\":\"Killed\",\"static\":false},{\"id\":\"197\",\"mutatorName\":\"Negate expression\",\"replacement\":\"!(hostsMembersIds.Any())\",\"location\":{\"start\":{\"line\":118,\"column\":17},\"end\":{\"line\":118,\"column\":38}},\"status\":\"Killed\",\"static\":false},{\"id\":\"198\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":119,\"column\":13},\"end\":{\"line\":124,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"199\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":121,\"column\":17},\"end\":{\"line\":123,\"column\":18}},\"status\":\"Killed\",\"static\":false},{\"id\":\"200\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":122,\"column\":21},\"end\":{\"line\":122,\"column\":147}},\"status\":\"Killed\",\"static\":false},{\"id\":\"201\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":126,\"column\":13},\"end\":{\"line\":128,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"202\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":127,\"column\":17},\"end\":{\"line\":127,\"column\":140}},\"status\":\"Killed\",\"static\":false},{\"id\":\"203\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":140,\"column\":9},\"end\":{\"line\":157,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"204\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":141,\"column\":13},\"end\":{\"line\":143,\"column\":64}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"205\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":150,\"column\":13},\"end\":{\"line\":150,\"column\":47}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"206\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":156,\"column\":13},\"end\":{\"line\":156,\"column\":87}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"207\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":160,\"column\":9},\"end\":{\"line\":183,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"208\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":161,\"column\":13},\"end\":{\"line\":161,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"209\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":163,\"column\":13},\"end\":{\"line\":163,\"column\":81}},\"status\":\"Killed\",\"static\":false},{\"id\":\"210\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":165,\"column\":13},\"end\":{\"line\":165,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"211\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":167,\"column\":13},\"end\":{\"line\":167,\"column\":107}},\"status\":\"Killed\",\"static\":false},{\"id\":\"212\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":169,\"column\":13},\"end\":{\"line\":169,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"213\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":171,\"column\":13},\"end\":{\"line\":171,\"column\":163}},\"status\":\"Killed\",\"static\":false},{\"id\":\"214\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":174,\"column\":13},\"end\":{\"line\":174,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"215\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":176,\"column\":13},\"end\":{\"line\":182,\"column\":29}},\"status\":\"Killed\",\"static\":false},{\"id\":\"216\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":186,\"column\":9},\"end\":{\"line\":212,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"217\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":187,\"column\":13},\"end\":{\"line\":187,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"218\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":189,\"column\":13},\"end\":{\"line\":189,\"column\":93}},\"status\":\"Killed\",\"static\":false},{\"id\":\"219\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":191,\"column\":13},\"end\":{\"line\":191,\"column\":80}},\"status\":\"Killed\",\"static\":false},{\"id\":\"220\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":195,\"column\":13},\"end\":{\"line\":195,\"column\":40}},\"status\":\"Killed\",\"static\":false},{\"id\":\"221\",\"mutatorName\":\"Linq method mutation (FirstOrDefault() to First())\",\"replacement\":\"_waitlistMembers\\r\\n                .Where(x =\\u003E x.IsActive())\\r\\n                .OrderBy(x =\\u003E x.SignUpDate)\\r\\n                .First()\",\"location\":{\"start\":{\"line\":197,\"column\":38},\"end\":{\"line\":200,\"column\":34}},\"status\":\"Killed\",\"static\":false},{\"id\":\"222\",\"mutatorName\":\"Linq method mutation (OrderBy() to OrderByDescending())\",\"replacement\":\"_waitlistMembers\\r\\n                .Where(x =\\u003E x.IsActive())\\r\\n                .OrderByDescending(x =\\u003E x.SignUpDate)\\r\\n                .FirstOrDefault()\",\"location\":{\"start\":{\"line\":197,\"column\":38},\"end\":{\"line\":200,\"column\":34}},\"status\":\"Survived\",\"static\":false},{\"id\":\"223\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"nextWaitlistMember == null\",\"location\":{\"start\":{\"line\":201,\"column\":17},\"end\":{\"line\":201,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"224\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":202,\"column\":13},\"end\":{\"line\":211,\"column\":14}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"225\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":203,\"column\":17},\"end\":{\"line\":209,\"column\":38}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"226\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":210,\"column\":17},\"end\":{\"line\":210,\"column\":61}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"227\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":215,\"column\":9},\"end\":{\"line\":223,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"228\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":216,\"column\":13},\"end\":{\"line\":216,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"229\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":218,\"column\":13},\"end\":{\"line\":218,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"230\",\"mutatorName\":\"Linq method mutation (Single() to SingleOrDefault())\",\"replacement\":\"_notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(memberId))\",\"location\":{\"start\":{\"line\":220,\"column\":31},\"end\":{\"line\":220,\"column\":89}},\"status\":\"Survived\",\"static\":false},{\"id\":\"231\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":222,\"column\":13},\"end\":{\"line\":222,\"column\":42}},\"status\":\"Killed\",\"static\":false},{\"id\":\"232\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":226,\"column\":9},\"end\":{\"line\":236,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"233\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":227,\"column\":13},\"end\":{\"line\":227,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"234\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":229,\"column\":13},\"end\":{\"line\":229,\"column\":81}},\"status\":\"Killed\",\"static\":false},{\"id\":\"235\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":231,\"column\":13},\"end\":{\"line\":231,\"column\":110}},\"status\":\"Killed\",\"static\":false},{\"id\":\"236\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":233,\"column\":13},\"end\":{\"line\":233,\"column\":109}},\"status\":\"Killed\",\"static\":false},{\"id\":\"237\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":235,\"column\":13},\"end\":{\"line\":235,\"column\":86}},\"status\":\"Killed\",\"static\":false},{\"id\":\"238\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":239,\"column\":9},\"end\":{\"line\":247,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"239\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":240,\"column\":13},\"end\":{\"line\":240,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"240\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":242,\"column\":13},\"end\":{\"line\":242,\"column\":108}},\"status\":\"Killed\",\"static\":false},{\"id\":\"241\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":246,\"column\":13},\"end\":{\"line\":246,\"column\":40}},\"status\":\"Killed\",\"static\":false},{\"id\":\"242\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":250,\"column\":9},\"end\":{\"line\":260,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"243\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":251,\"column\":13},\"end\":{\"line\":251,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"244\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":253,\"column\":13},\"end\":{\"line\":253,\"column\":132}},\"status\":\"Killed\",\"static\":false},{\"id\":\"245\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":255,\"column\":13},\"end\":{\"line\":255,\"column\":103}},\"status\":\"Survived\",\"static\":false},{\"id\":\"246\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":259,\"column\":13},\"end\":{\"line\":259,\"column\":34}},\"status\":\"Killed\",\"static\":false},{\"id\":\"247\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":263,\"column\":9},\"end\":{\"line\":277,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"248\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":264,\"column\":13},\"end\":{\"line\":264,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"249\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":266,\"column\":13},\"end\":{\"line\":266,\"column\":132}},\"status\":\"Killed\",\"static\":false},{\"id\":\"250\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":268,\"column\":13},\"end\":{\"line\":268,\"column\":103}},\"status\":\"Survived\",\"static\":false},{\"id\":\"251\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":272,\"column\":13},\"end\":{\"line\":272,\"column\":38}},\"status\":\"Killed\",\"static\":false},{\"id\":\"252\",\"mutatorName\":\"Linq method mutation (Count() to Sum())\",\"replacement\":\"_attendees.Sum(x =\\u003E x.IsActiveHost())\",\"location\":{\"start\":{\"line\":274,\"column\":37},\"end\":{\"line\":274,\"column\":76}},\"status\":\"CompileError\",\"statusReason\":\"Mutant caused compile errors\",\"static\":false},{\"id\":\"253\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":276,\"column\":13},\"end\":{\"line\":276,\"column\":86}},\"status\":\"Killed\",\"static\":false},{\"id\":\"254\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":282,\"column\":9},\"end\":{\"line\":293,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"255\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":283,\"column\":13},\"end\":{\"line\":283,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"256\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_isCanceled\",\"location\":{\"start\":{\"line\":285,\"column\":17},\"end\":{\"line\":285,\"column\":29}},\"status\":\"Killed\",\"static\":false},{\"id\":\"257\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":286,\"column\":13},\"end\":{\"line\":292,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"258\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":287,\"column\":31},\"end\":{\"line\":287,\"column\":35}},\"status\":\"Survived\",\"static\":false},{\"id\":\"259\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":291,\"column\":17},\"end\":{\"line\":291,\"column\":114}},\"status\":\"Killed\",\"static\":false},{\"id\":\"260\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":296,\"column\":9},\"end\":{\"line\":303,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"261\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":297,\"column\":13},\"end\":{\"line\":297,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"262\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":298,\"column\":13},\"end\":{\"line\":298,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"263\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":302,\"column\":13},\"end\":{\"line\":302,\"column\":55}},\"status\":\"Killed\",\"static\":false},{\"id\":\"264\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":306,\"column\":9},\"end\":{\"line\":310,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"265\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":309,\"column\":13},\"end\":{\"line\":309,\"column\":39}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"266\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":321,\"column\":9},\"end\":{\"line\":323,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"267\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":326,\"column\":9},\"end\":{\"line\":328,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"268\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_waitlistMembers.Single(x =\\u003E x.IsActiveOnWaitList(memberId))\",\"location\":{\"start\":{\"line\":327,\"column\":20},\"end\":{\"line\":327,\"column\":89}},\"status\":\"Survived\",\"static\":false},{\"id\":\"269\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":331,\"column\":9},\"end\":{\"line\":333,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"270\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_attendees.Single(x =\\u003E x.IsActiveAttendee(attendeeId))\",\"location\":{\"start\":{\"line\":332,\"column\":20},\"end\":{\"line\":332,\"column\":83}},\"status\":\"Killed\",\"static\":false},{\"id\":\"271\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":336,\"column\":9},\"end\":{\"line\":338,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"272\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_notAttendees.Single(x =\\u003E x.IsActiveNotAttendee(memberId))\",\"location\":{\"start\":{\"line\":337,\"column\":20},\"end\":{\"line\":337,\"column\":87}},\"status\":\"Killed\",\"static\":false},{\"id\":\"273\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":341,\"column\":9},\"end\":{\"line\":343,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"274\",\"mutatorName\":\"Linq method mutation (Sum() to Max())\",\"replacement\":\"_attendees.Where(x =\\u003E x.IsActive()).Max(x =\\u003E x.GetAttendeeWithGuestsNumber())\",\"location\":{\"start\":{\"line\":342,\"column\":20},\"end\":{\"line\":342,\"column\":97}},\"status\":\"Killed\",\"static\":false},{\"id\":\"275\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":346,\"column\":9},\"end\":{\"line\":355,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"276\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!rsvpTerm.EndDate.HasValue \\u0026\\u0026 rsvpTerm.EndDate \\u003E meetingTerm.StartDate\",\"location\":{\"start\":{\"line\":347,\"column\":17},\"end\":{\"line\":347,\"column\":87}},\"status\":\"Survived\",\"static\":false},{\"id\":\"277\",\"mutatorName\":\"Negate expression\",\"replacement\":\"!(!rsvpTerm.EndDate.HasValue || rsvpTerm.EndDate \\u003E meetingTerm.StartDate)\",\"location\":{\"start\":{\"line\":347,\"column\":17},\"end\":{\"line\":347,\"column\":87}},\"status\":\"Killed\",\"static\":false},{\"id\":\"278\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"rsvpTerm.EndDate.HasValue \",\"location\":{\"start\":{\"line\":347,\"column\":17},\"end\":{\"line\":347,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"279\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"rsvpTerm.EndDate \\u003C meetingTerm.StartDate\",\"location\":{\"start\":{\"line\":347,\"column\":47},\"end\":{\"line\":347,\"column\":87}},\"status\":\"Killed\",\"static\":false},{\"id\":\"280\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"rsvpTerm.EndDate \\u003E= meetingTerm.StartDate\",\"location\":{\"start\":{\"line\":347,\"column\":47},\"end\":{\"line\":347,\"column\":87}},\"status\":\"Survived\",\"static\":false},{\"id\":\"281\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":348,\"column\":13},\"end\":{\"line\":350,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"282\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":352,\"column\":13},\"end\":{\"line\":354,\"column\":14}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\MeetingAttendee.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingAttendee : Entity\\r\\n    {\\r\\n        internal MemberId AttendeeId { get; private set; }\\r\\n\\r\\n        internal MeetingId MeetingId { get; private set; }\\r\\n\\r\\n        private DateTime _decisionDate;\\r\\n\\r\\n        private MeetingAttendeeRole _role;\\r\\n\\r\\n        private int _guestsNumber;\\r\\n\\r\\n        private bool _decisionChanged;\\r\\n\\r\\n        private DateTime? _decisionChangeDate;\\r\\n\\r\\n        private DateTime? _removedDate;\\r\\n\\r\\n        private MemberId _removingMemberId;\\r\\n\\r\\n        private string _removingReason;\\r\\n\\r\\n        private bool _isRemoved;\\r\\n\\r\\n        private MoneyValue _fee;\\r\\n\\r\\n        private bool _isFeePaid;\\r\\n\\r\\n        private MeetingAttendee()\\r\\n        {\\r\\n        }\\r\\n\\r\\n        internal static MeetingAttendee CreateNew(\\r\\n            MeetingId meetingId,\\r\\n            MemberId attendeeId,\\r\\n            DateTime decisionDate,\\r\\n            MeetingAttendeeRole role,\\r\\n            int guestsNumber,\\r\\n            MoneyValue eventFee)\\r\\n        {\\r\\n            return new MeetingAttendee(meetingId, attendeeId, decisionDate, role, guestsNumber, eventFee);\\r\\n        }\\r\\n\\r\\n        private MeetingAttendee(\\r\\n            MeetingId meetingId,\\r\\n            MemberId attendeeId,\\r\\n            DateTime decisionDate,\\r\\n            MeetingAttendeeRole role,\\r\\n            int guestsNumber,\\r\\n            MoneyValue eventFee)\\r\\n        {\\r\\n            this.AttendeeId = attendeeId;\\r\\n            this.MeetingId = meetingId;\\r\\n            this._decisionDate = decisionDate;\\r\\n            this._role = role;\\r\\n            _guestsNumber = guestsNumber;\\r\\n            _decisionChanged = false;\\r\\n            _isFeePaid = false;\\r\\n\\r\\n            if (eventFee != MoneyValue.Undefined)\\r\\n            {\\r\\n                _fee = (1 \\u002B guestsNumber) * eventFee;\\r\\n            }\\r\\n            else\\r\\n            {\\r\\n                _fee = MoneyValue.Undefined;\\r\\n            }\\r\\n\\r\\n            this.AddDomainEvent(new MeetingAttendeeAddedDomainEvent(\\r\\n                this.MeetingId,\\r\\n                AttendeeId,\\r\\n                decisionDate,\\r\\n                role.Value,\\r\\n                guestsNumber,\\r\\n                _fee.Value,\\r\\n                _fee.Currency));\\r\\n        }\\r\\n\\r\\n        internal void ChangeDecision()\\r\\n        {\\r\\n            _decisionChanged = true;\\r\\n            _decisionChangeDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingAttendeeChangedDecisionDomainEvent(this.AttendeeId, this.MeetingId));\\r\\n        }\\r\\n\\r\\n        internal bool IsActiveAttendee(MemberId attendeeId)\\r\\n        {\\r\\n            return this.AttendeeId == attendeeId \\u0026\\u0026 !_decisionChanged;\\r\\n        }\\r\\n\\r\\n        internal bool IsActive()\\r\\n        {\\r\\n            return !_decisionChangeDate.HasValue \\u0026\\u0026 !_isRemoved;\\r\\n        }\\r\\n\\r\\n        internal bool IsActiveHost()\\r\\n        {\\r\\n            return this.IsActive() \\u0026\\u0026 _role == MeetingAttendeeRole.Host;\\r\\n        }\\r\\n\\r\\n        internal int GetAttendeeWithGuestsNumber()\\r\\n        {\\r\\n            return 1 \\u002B _guestsNumber;\\r\\n        }\\r\\n\\r\\n        internal void SetAsHost()\\r\\n        {\\r\\n            _role = MeetingAttendeeRole.Host;\\r\\n\\r\\n            this.AddDomainEvent(new NewMeetingHostSetDomainEvent(this.MeetingId, this.AttendeeId));\\r\\n        }\\r\\n\\r\\n        internal void SetAsAttendee()\\r\\n        {\\r\\n            this.CheckRule(new MemberCannotHaveSetAttendeeRoleMoreThanOnceRule(_role));\\r\\n            _role = MeetingAttendeeRole.Attendee;\\r\\n\\r\\n            this.AddDomainEvent(new MemberSetAsAttendeeDomainEvent(this.MeetingId, this.AttendeeId));\\r\\n        }\\r\\n\\r\\n        internal void Remove(MemberId removingMemberId, string reason)\\r\\n        {\\r\\n            this.CheckRule(new ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule(reason));\\r\\n\\r\\n            _isRemoved = true;\\r\\n            _removedDate = SystemClock.Now;\\r\\n            _removingReason = reason;\\r\\n            _removingMemberId = removingMemberId;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingAttendeeRemovedDomainEvent(this.AttendeeId, this.MeetingId, reason));\\r\\n        }\\r\\n\\r\\n        internal void MarkFeeAsPayed()\\r\\n        {\\r\\n            _isFeePaid = true;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingAttendeeFeePaidDomainEvent(this.MeetingId, this.AttendeeId));\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"283\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":50,\"column\":9},\"end\":{\"line\":52,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"284\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":61,\"column\":9},\"end\":{\"line\":87,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"285\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":67,\"column\":32},\"end\":{\"line\":67,\"column\":37}},\"status\":\"Killed\",\"static\":false},{\"id\":\"286\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":68,\"column\":26},\"end\":{\"line\":68,\"column\":31}},\"status\":\"Survived\",\"static\":false},{\"id\":\"287\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"eventFee == MoneyValue.Undefined\",\"location\":{\"start\":{\"line\":70,\"column\":17},\"end\":{\"line\":70,\"column\":49}},\"status\":\"Survived\",\"static\":false},{\"id\":\"288\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":71,\"column\":13},\"end\":{\"line\":73,\"column\":14}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"289\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"(1 \\u002B guestsNumber) / eventFee\",\"location\":{\"start\":{\"line\":72,\"column\":24},\"end\":{\"line\":72,\"column\":53}},\"status\":\"CompileError\",\"statusReason\":\"Mutant caused compile errors\",\"static\":false},{\"id\":\"290\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"1 - guestsNumber\",\"location\":{\"start\":{\"line\":72,\"column\":25},\"end\":{\"line\":72,\"column\":41}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"291\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":75,\"column\":13},\"end\":{\"line\":77,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"292\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":79,\"column\":13},\"end\":{\"line\":86,\"column\":33}},\"status\":\"Killed\",\"static\":false},{\"id\":\"293\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":90,\"column\":9},\"end\":{\"line\":95,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"294\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":91,\"column\":32},\"end\":{\"line\":91,\"column\":36}},\"status\":\"Survived\",\"static\":false},{\"id\":\"295\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":94,\"column\":13},\"end\":{\"line\":94,\"column\":113}},\"status\":\"Killed\",\"static\":false},{\"id\":\"296\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":98,\"column\":9},\"end\":{\"line\":100,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"297\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this.AttendeeId == attendeeId || !_decisionChanged\",\"location\":{\"start\":{\"line\":99,\"column\":20},\"end\":{\"line\":99,\"column\":70}},\"status\":\"Killed\",\"static\":false},{\"id\":\"298\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.AttendeeId != attendeeId \",\"location\":{\"start\":{\"line\":99,\"column\":20},\"end\":{\"line\":99,\"column\":49}},\"status\":\"Killed\",\"static\":false},{\"id\":\"299\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_decisionChanged\",\"location\":{\"start\":{\"line\":99,\"column\":53},\"end\":{\"line\":99,\"column\":70}},\"status\":\"Killed\",\"static\":false},{\"id\":\"300\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":103,\"column\":9},\"end\":{\"line\":105,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"301\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!_decisionChangeDate.HasValue || !_isRemoved\",\"location\":{\"start\":{\"line\":104,\"column\":20},\"end\":{\"line\":104,\"column\":64}},\"status\":\"Survived\",\"static\":false},{\"id\":\"302\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_decisionChangeDate.HasValue \",\"location\":{\"start\":{\"line\":104,\"column\":20},\"end\":{\"line\":104,\"column\":49}},\"status\":\"Killed\",\"static\":false},{\"id\":\"303\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_isRemoved\",\"location\":{\"start\":{\"line\":104,\"column\":53},\"end\":{\"line\":104,\"column\":64}},\"status\":\"Killed\",\"static\":false},{\"id\":\"304\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":108,\"column\":9},\"end\":{\"line\":110,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"305\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this.IsActive() || _role == MeetingAttendeeRole.Host\",\"location\":{\"start\":{\"line\":109,\"column\":20},\"end\":{\"line\":109,\"column\":72}},\"status\":\"Killed\",\"static\":false},{\"id\":\"306\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_role != MeetingAttendeeRole.Host\",\"location\":{\"start\":{\"line\":109,\"column\":39},\"end\":{\"line\":109,\"column\":72}},\"status\":\"Killed\",\"static\":false},{\"id\":\"307\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":113,\"column\":9},\"end\":{\"line\":115,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"308\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"1 - _guestsNumber\",\"location\":{\"start\":{\"line\":114,\"column\":20},\"end\":{\"line\":114,\"column\":37}},\"status\":\"Killed\",\"static\":false},{\"id\":\"309\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":118,\"column\":9},\"end\":{\"line\":122,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"310\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":121,\"column\":13},\"end\":{\"line\":121,\"column\":100}},\"status\":\"Killed\",\"static\":false},{\"id\":\"311\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":125,\"column\":9},\"end\":{\"line\":130,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"312\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":126,\"column\":13},\"end\":{\"line\":126,\"column\":88}},\"status\":\"Killed\",\"static\":false},{\"id\":\"313\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":129,\"column\":13},\"end\":{\"line\":129,\"column\":102}},\"status\":\"Killed\",\"static\":false},{\"id\":\"314\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":133,\"column\":9},\"end\":{\"line\":142,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"315\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":134,\"column\":13},\"end\":{\"line\":134,\"column\":95}},\"status\":\"Killed\",\"static\":false},{\"id\":\"316\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":136,\"column\":26},\"end\":{\"line\":136,\"column\":30}},\"status\":\"Survived\",\"static\":false},{\"id\":\"317\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":141,\"column\":13},\"end\":{\"line\":141,\"column\":113}},\"status\":\"Killed\",\"static\":false},{\"id\":\"318\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":145,\"column\":9},\"end\":{\"line\":149,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"319\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":146,\"column\":26},\"end\":{\"line\":146,\"column\":30}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"320\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":148,\"column\":13},\"end\":{\"line\":148,\"column\":105}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\MeetingAttendeeRole.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingAttendeeRole : ValueObject\\r\\n    {\\r\\n        public static MeetingAttendeeRole Host =\\u003E new MeetingAttendeeRole(\\u0022Host\\u0022);\\r\\n\\r\\n        public static MeetingAttendeeRole Attendee =\\u003E new MeetingAttendeeRole(\\u0022Attendee\\u0022);\\r\\n\\r\\n        public string Value { get; }\\r\\n\\r\\n        private MeetingAttendeeRole(string value)\\r\\n        {\\r\\n            this.Value = value;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"321\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":7,\"column\":75},\"end\":{\"line\":7,\"column\":81}},\"status\":\"Survived\",\"static\":false},{\"id\":\"322\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":9,\"column\":79},\"end\":{\"line\":9,\"column\":89}},\"status\":\"Survived\",\"static\":false},{\"id\":\"323\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\MeetingId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingId : TypedIdValueBase\\r\\n    {\\r\\n        public MeetingId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Meetings\\\\MeetingLimits.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingLimits : ValueObject\\r\\n    {\\r\\n        public int? AttendeesLimit { get; }\\r\\n\\r\\n        public int GuestsLimit { get; }\\r\\n\\r\\n        private MeetingLimits(int? attendeesLimit, int guestsLimit)\\r\\n        {\\r\\n            AttendeesLimit = attendeesLimit;\\r\\n            GuestsLimit = guestsLimit;\\r\\n        }\\r\\n\\r\\n        public static MeetingLimits Create(int? attendeesLimit, int guestsLimit)\\r\\n        {\\r\\n            CheckRule(new MeetingAttendeesLimitCannotBeNegativeRule(attendeesLimit));\\r\\n\\r\\n            CheckRule(new MeetingGuestsLimitCannotBeNegativeRule(guestsLimit));\\r\\n\\r\\n            CheckRule(new MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule(attendeesLimit, guestsLimit));\\r\\n\\r\\n            return new MeetingLimits(attendeesLimit, guestsLimit);\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"324\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"325\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":19,\"column\":9},\"end\":{\"line\":27,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"326\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":20,\"column\":13},\"end\":{\"line\":20,\"column\":86}},\"status\":\"Killed\",\"static\":false},{\"id\":\"327\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":22,\"column\":13},\"end\":{\"line\":22,\"column\":80}},\"status\":\"Killed\",\"static\":false},{\"id\":\"328\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":24,\"column\":13},\"end\":{\"line\":24,\"column\":111}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\MeetingLocation.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingLocation : ValueObject\\r\\n    {\\r\\n        public static MeetingLocation CreateNew(string name, string address, string postalCode, string city)\\r\\n        {\\r\\n            return new MeetingLocation(name, address, postalCode, city);\\r\\n        }\\r\\n\\r\\n        private MeetingLocation(string name, string address, string postalCode, string city)\\r\\n        {\\r\\n            Name = name;\\r\\n            Address = address;\\r\\n            PostalCode = postalCode;\\r\\n            City = city;\\r\\n        }\\r\\n\\r\\n        public string Name { get; }\\r\\n\\r\\n        public string Address { get; }\\r\\n\\r\\n        public string PostalCode { get; }\\r\\n\\r\\n        public string City { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"329\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":8,\"column\":9},\"end\":{\"line\":10,\"column\":10}},\"status\":\"Survived\",\"static\":false},{\"id\":\"330\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":13,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\MeetingNotAttendee.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingNotAttendee : Entity\\r\\n    {\\r\\n        internal MemberId MemberId { get; private set; }\\r\\n\\r\\n        internal MeetingId MeetingId { get; private set; }\\r\\n\\r\\n        private DateTime _decisionDate;\\r\\n\\r\\n        private bool _decisionChanged;\\r\\n\\r\\n        private DateTime? _decisionChangeDate;\\r\\n\\r\\n        private MeetingNotAttendee()\\r\\n        {\\r\\n        }\\r\\n\\r\\n        private MeetingNotAttendee(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            this.MemberId = memberId;\\r\\n            this.MeetingId = meetingId;\\r\\n            _decisionDate = DateTime.UtcNow;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingNotAttendeeAddedDomainEvent(this.MeetingId, this.MemberId));\\r\\n        }\\r\\n\\r\\n        internal static MeetingNotAttendee CreateNew(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            return new MeetingNotAttendee(meetingId, memberId);\\r\\n        }\\r\\n\\r\\n        internal bool IsActiveNotAttendee(MemberId memberId)\\r\\n        {\\r\\n            return !this._decisionChanged \\u0026\\u0026 this.MemberId == memberId;\\r\\n        }\\r\\n\\r\\n        internal void ChangeDecision()\\r\\n        {\\r\\n            _decisionChanged = true;\\r\\n            _decisionChangeDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingNotAttendeeChangedDecisionDomainEvent(this.MemberId, this.MeetingId));\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"331\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":27,\"column\":9},\"end\":{\"line\":33,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"332\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":32,\"column\":13},\"end\":{\"line\":32,\"column\":104}},\"status\":\"Killed\",\"static\":false},{\"id\":\"333\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":36,\"column\":9},\"end\":{\"line\":38,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"334\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":41,\"column\":9},\"end\":{\"line\":43,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"335\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!this._decisionChanged || this.MemberId == memberId\",\"location\":{\"start\":{\"line\":42,\"column\":20},\"end\":{\"line\":42,\"column\":71}},\"status\":\"Survived\",\"static\":false},{\"id\":\"336\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"this._decisionChanged \",\"location\":{\"start\":{\"line\":42,\"column\":20},\"end\":{\"line\":42,\"column\":42}},\"status\":\"Killed\",\"static\":false},{\"id\":\"337\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.MemberId != memberId\",\"location\":{\"start\":{\"line\":42,\"column\":46},\"end\":{\"line\":42,\"column\":71}},\"status\":\"Killed\",\"static\":false},{\"id\":\"338\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":46,\"column\":9},\"end\":{\"line\":51,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"339\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":47,\"column\":32},\"end\":{\"line\":47,\"column\":36}},\"status\":\"Survived\",\"static\":false},{\"id\":\"340\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":50,\"column\":13},\"end\":{\"line\":50,\"column\":114}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\MeetingTerm.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingTerm : ValueObject\\r\\n    {\\r\\n        public DateTime StartDate { get; }\\r\\n\\r\\n        public DateTime EndDate { get; }\\r\\n\\r\\n        public static MeetingTerm CreateNewBetweenDates(DateTime startDate, DateTime endDate)\\r\\n        {\\r\\n            return new MeetingTerm(startDate, endDate);\\r\\n        }\\r\\n\\r\\n        private MeetingTerm(DateTime startDate, DateTime endDate)\\r\\n        {\\r\\n            this.StartDate = startDate;\\r\\n            this.EndDate = endDate;\\r\\n        }\\r\\n\\r\\n        internal bool IsAfterStart()\\r\\n        {\\r\\n            return SystemClock.Now \\u003E this.StartDate;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"341\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"342\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":19,\"column\":9},\"end\":{\"line\":22,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"343\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":25,\"column\":9},\"end\":{\"line\":27,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"344\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"SystemClock.Now \\u003C this.StartDate\",\"location\":{\"start\":{\"line\":26,\"column\":20},\"end\":{\"line\":26,\"column\":52}},\"status\":\"Killed\",\"static\":false},{\"id\":\"345\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"SystemClock.Now \\u003E= this.StartDate\",\"location\":{\"start\":{\"line\":26,\"column\":20},\"end\":{\"line\":26,\"column\":52}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\MeetingWaitlistMember.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MeetingWaitlistMember : Entity\\r\\n    {\\r\\n        internal MemberId MemberId { get; private set; }\\r\\n\\r\\n        internal MeetingId MeetingId { get; private set; }\\r\\n\\r\\n        internal DateTime SignUpDate { get; private set; }\\r\\n\\r\\n        private bool _isSignedOff;\\r\\n\\r\\n        private DateTime? _signOffDate;\\r\\n\\r\\n        private bool _isMovedToAttendees;\\r\\n\\r\\n        private DateTime? _movedToAttendeesDate;\\r\\n\\r\\n        private MeetingWaitlistMember()\\r\\n        {\\r\\n        }\\r\\n\\r\\n        private MeetingWaitlistMember(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            this.MemberId = memberId;\\r\\n            this.MeetingId = meetingId;\\r\\n            this.SignUpDate = SystemClock.Now;\\r\\n            _isMovedToAttendees = false;\\r\\n\\r\\n            this.AddDomainEvent(new MeetingWaitlistMemberAddedDomainEvent(this.MeetingId, this.MemberId));\\r\\n        }\\r\\n\\r\\n        internal static MeetingWaitlistMember CreateNew(MeetingId meetingId, MemberId memberId)\\r\\n        {\\r\\n            return new MeetingWaitlistMember(meetingId, memberId);\\r\\n        }\\r\\n\\r\\n        internal void MarkIsMovedToAttendees()\\r\\n        {\\r\\n            _isMovedToAttendees = true;\\r\\n            _movedToAttendeesDate = SystemClock.Now;\\r\\n        }\\r\\n\\r\\n        internal bool IsActiveOnWaitList(MemberId memberId)\\r\\n        {\\r\\n            return this.MemberId == memberId \\u0026\\u0026 this.IsActive();\\r\\n        }\\r\\n\\r\\n        internal bool IsActive()\\r\\n        {\\r\\n            return !_isSignedOff \\u0026\\u0026 !_isMovedToAttendees;\\r\\n        }\\r\\n\\r\\n        internal void SignOff()\\r\\n        {\\r\\n            _isSignedOff = true;\\r\\n            _signOffDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MemberSignedOffFromMeetingWaitlistDomainEvent(this.MeetingId, this.MemberId));\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"346\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":30,\"column\":9},\"end\":{\"line\":37,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"347\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"true\",\"location\":{\"start\":{\"line\":34,\"column\":35},\"end\":{\"line\":34,\"column\":40}},\"status\":\"Killed\",\"static\":false},{\"id\":\"348\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":36,\"column\":13},\"end\":{\"line\":36,\"column\":107}},\"status\":\"Killed\",\"static\":false},{\"id\":\"349\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":40,\"column\":9},\"end\":{\"line\":42,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"350\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":45,\"column\":9},\"end\":{\"line\":48,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"351\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":46,\"column\":35},\"end\":{\"line\":46,\"column\":39}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"352\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":51,\"column\":9},\"end\":{\"line\":53,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"353\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this.MemberId == memberId || this.IsActive()\",\"location\":{\"start\":{\"line\":52,\"column\":20},\"end\":{\"line\":52,\"column\":64}},\"status\":\"Survived\",\"static\":false},{\"id\":\"354\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.MemberId != memberId \",\"location\":{\"start\":{\"line\":52,\"column\":20},\"end\":{\"line\":52,\"column\":45}},\"status\":\"Killed\",\"static\":false},{\"id\":\"355\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":56,\"column\":9},\"end\":{\"line\":58,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"356\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!_isSignedOff || !_isMovedToAttendees\",\"location\":{\"start\":{\"line\":57,\"column\":20},\"end\":{\"line\":57,\"column\":57}},\"status\":\"Survived\",\"static\":false},{\"id\":\"357\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_isSignedOff \",\"location\":{\"start\":{\"line\":57,\"column\":20},\"end\":{\"line\":57,\"column\":33}},\"status\":\"Killed\",\"static\":false},{\"id\":\"358\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_isMovedToAttendees\",\"location\":{\"start\":{\"line\":57,\"column\":37},\"end\":{\"line\":57,\"column\":57}},\"status\":\"Killed\",\"static\":false},{\"id\":\"359\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":61,\"column\":9},\"end\":{\"line\":66,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"360\",\"mutatorName\":\"Boolean mutation\",\"replacement\":\"false\",\"location\":{\"start\":{\"line\":62,\"column\":28},\"end\":{\"line\":62,\"column\":32}},\"status\":\"Survived\",\"static\":false},{\"id\":\"361\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":65,\"column\":13},\"end\":{\"line\":65,\"column\":115}},\"status\":\"Killed\",\"static\":false}]},\"Meetings\\\\MoneyValue.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class MoneyValue : ValueObject\\r\\n    {\\r\\n        public static MoneyValue Undefined =\\u003E new MoneyValue(null, null);\\r\\n\\r\\n        public decimal? Value { get; }\\r\\n\\r\\n        public string Currency { get; }\\r\\n\\r\\n        public static MoneyValue Of(decimal value, string currency)\\r\\n        {\\r\\n            return new MoneyValue(value, currency);\\r\\n        }\\r\\n\\r\\n        private MoneyValue(decimal? value, string currency)\\r\\n        {\\r\\n            this.Value = value;\\r\\n            this.Currency = currency;\\r\\n        }\\r\\n\\r\\n        public static MoneyValue operator *(int left, MoneyValue right)\\r\\n        {\\r\\n            return new MoneyValue(right.Value * left, right.Currency);\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"362\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":16,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"363\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":19,\"column\":9},\"end\":{\"line\":22,\"column\":10}},\"status\":\"Survived\",\"static\":false},{\"id\":\"364\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":25,\"column\":9},\"end\":{\"line\":27,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"365\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"right.Value / left\",\"location\":{\"start\":{\"line\":26,\"column\":35},\"end\":{\"line\":26,\"column\":53}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Rules\\\\AttendeeCanBeAddedOnlyInRsvpTermRule.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class AttendeeCanBeAddedOnlyInRsvpTermRule : IBusinessRule\\r\\n    {\\r\\n        private readonly Term _rsvpTerm;\\r\\n\\r\\n        internal AttendeeCanBeAddedOnlyInRsvpTermRule(Term rsvpTerm)\\r\\n        {\\r\\n            _rsvpTerm = rsvpTerm;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_rsvpTerm.IsInTerm(SystemClock.Now);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Attendee can be added only in RSVP term\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"366\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":14,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"367\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_rsvpTerm.IsInTerm(SystemClock.Now)\",\"location\":{\"start\":{\"line\":16,\"column\":35},\"end\":{\"line\":16,\"column\":71}},\"status\":\"Killed\",\"static\":false},{\"id\":\"368\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":18,\"column\":34},\"end\":{\"line\":18,\"column\":75}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    internal class AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int? _attendeesLimit;\\r\\n\\r\\n        private readonly int _allActiveAttendeesWithGuestsNumber;\\r\\n\\r\\n        internal AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule(\\r\\n            MeetingLimits meetingLimits,\\r\\n            int allActiveAttendeesWithGuestsNumber)\\r\\n        {\\r\\n            this._attendeesLimit = meetingLimits.AttendeesLimit;\\r\\n            this._allActiveAttendeesWithGuestsNumber = allActiveAttendeesWithGuestsNumber;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendeesLimit.HasValue \\u0026\\u0026 _attendeesLimit.Value \\u003C _allActiveAttendeesWithGuestsNumber;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Attendees limit cannot be change to smaller than active attendees number\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"369\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":17,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"370\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"_attendeesLimit.HasValue || _attendeesLimit.Value \\u003C _allActiveAttendeesWithGuestsNumber\",\"location\":{\"start\":{\"line\":19,\"column\":35},\"end\":{\"line\":19,\"column\":122}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"371\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003E _allActiveAttendeesWithGuestsNumber\",\"location\":{\"start\":{\"line\":19,\"column\":63},\"end\":{\"line\":19,\"column\":122}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"372\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003C= _allActiveAttendeesWithGuestsNumber\",\"location\":{\"start\":{\"line\":19,\"column\":63},\"end\":{\"line\":19,\"column\":122}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"373\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":21,\"column\":34},\"end\":{\"line\":21,\"column\":108}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingAttendeeMustBeAMemberOfGroupRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingAttendeeMustBeAMemberOfGroupRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n\\r\\n        private readonly MemberId _attendeeId;\\r\\n\\r\\n        internal MeetingAttendeeMustBeAMemberOfGroupRule(MemberId attendeeId, MeetingGroup meetingGroup)\\r\\n        {\\r\\n            _attendeeId = attendeeId;\\r\\n            _meetingGroup = meetingGroup;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken()\\r\\n        {\\r\\n            return !_meetingGroup.IsMemberOfGroup(_attendeeId);\\r\\n        }\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting attendee must be a member of group\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"374\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":9},\"end\":{\"line\":17,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"375\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":20,\"column\":9},\"end\":{\"line\":22,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"376\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsMemberOfGroup(_attendeeId)\",\"location\":{\"start\":{\"line\":21,\"column\":20},\"end\":{\"line\":21,\"column\":63}},\"status\":\"Killed\",\"static\":false},{\"id\":\"377\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":24,\"column\":34},\"end\":{\"line\":24,\"column\":78}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingAttendeesLimitCannotBeNegativeRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingAttendeesLimitCannotBeNegativeRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int? _attendeesLimit;\\r\\n\\r\\n        public MeetingAttendeesLimitCannotBeNegativeRule(int? attendeesLimit)\\r\\n        {\\r\\n            _attendeesLimit = attendeesLimit;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendeesLimit.HasValue \\u0026\\u0026 _attendeesLimit.Value \\u003C 0;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Attendees limit cannot be negative\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"378\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"379\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"_attendeesLimit.HasValue || _attendeesLimit.Value \\u003C 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":88}},\"status\":\"Killed\",\"static\":false},{\"id\":\"380\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003E 0\",\"location\":{\"start\":{\"line\":14,\"column\":63},\"end\":{\"line\":14,\"column\":88}},\"status\":\"Killed\",\"static\":false},{\"id\":\"381\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003C= 0\",\"location\":{\"start\":{\"line\":14,\"column\":63},\"end\":{\"line\":14,\"column\":88}},\"status\":\"Survived\",\"static\":false},{\"id\":\"382\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":70}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int? _attendeesLimit;\\r\\n\\r\\n        private readonly int _guestsLimit;\\r\\n\\r\\n        public MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule(int? attendeesLimit, int guestsLimit)\\r\\n        {\\r\\n            _attendeesLimit = attendeesLimit;\\r\\n            _guestsLimit = guestsLimit;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendeesLimit.HasValue \\u0026\\u0026 _attendeesLimit.Value \\u003C _guestsLimit;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Attendees limit must be greater than guests limit\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"383\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"384\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"_attendeesLimit.HasValue || _attendeesLimit.Value \\u003C _guestsLimit\",\"location\":{\"start\":{\"line\":17,\"column\":35},\"end\":{\"line\":17,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"385\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003E _guestsLimit\",\"location\":{\"start\":{\"line\":17,\"column\":63},\"end\":{\"line\":17,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"386\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendeesLimit.Value \\u003C= _guestsLimit\",\"location\":{\"start\":{\"line\":17,\"column\":63},\"end\":{\"line\":17,\"column\":99}},\"status\":\"Survived\",\"static\":false},{\"id\":\"387\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":19,\"column\":34},\"end\":{\"line\":19,\"column\":85}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingAttendeesNumberIsAboveLimitRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingAttendeesNumberIsAboveLimitRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int? _attendeesLimit;\\r\\n\\r\\n        private readonly int _allActiveAttendeesWithGuestsNumber;\\r\\n\\r\\n        private readonly int _guestsNumber;\\r\\n\\r\\n        internal MeetingAttendeesNumberIsAboveLimitRule(\\r\\n            int? attendeesLimit,\\r\\n            int allActiveAttendeesWithGuestsNumber,\\r\\n            int guestsNumber)\\r\\n        {\\r\\n            _attendeesLimit = attendeesLimit;\\r\\n            _allActiveAttendeesWithGuestsNumber = allActiveAttendeesWithGuestsNumber;\\r\\n            _guestsNumber = guestsNumber;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E this._attendeesLimit.HasValue \\u0026\\u0026\\r\\n                                  this._attendeesLimit.Value \\u003C _allActiveAttendeesWithGuestsNumber \\u002B 1 \\u002B _guestsNumber;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting attendees number is above limit\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"388\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":17,\"column\":9},\"end\":{\"line\":21,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"389\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this._attendeesLimit.HasValue ||\\r\\n                                  this._attendeesLimit.Value \\u003C _allActiveAttendeesWithGuestsNumber \\u002B 1 \\u002B _guestsNumber\",\"location\":{\"start\":{\"line\":23,\"column\":35},\"end\":{\"line\":24,\"column\":119}},\"status\":\"Killed\",\"static\":false},{\"id\":\"390\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"                                  this._attendeesLimit.Value \\u003E _allActiveAttendeesWithGuestsNumber \\u002B 1 \\u002B _guestsNumber\",\"location\":{\"start\":{\"line\":24,\"column\":35},\"end\":{\"line\":24,\"column\":119}},\"status\":\"Killed\",\"static\":false},{\"id\":\"391\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"                                  this._attendeesLimit.Value \\u003C= _allActiveAttendeesWithGuestsNumber \\u002B 1 \\u002B _guestsNumber\",\"location\":{\"start\":{\"line\":24,\"column\":35},\"end\":{\"line\":24,\"column\":119}},\"status\":\"Killed\",\"static\":false},{\"id\":\"392\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"_allActiveAttendeesWithGuestsNumber \\u002B 1 - _guestsNumber\",\"location\":{\"start\":{\"line\":24,\"column\":64},\"end\":{\"line\":24,\"column\":119}},\"status\":\"Survived\",\"static\":false},{\"id\":\"393\",\"mutatorName\":\"Arithmetic mutation\",\"replacement\":\"_allActiveAttendeesWithGuestsNumber - 1 \",\"location\":{\"start\":{\"line\":24,\"column\":64},\"end\":{\"line\":24,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"394\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":26,\"column\":34},\"end\":{\"line\":26,\"column\":75}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingCannotBeChangedAfterStartRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingCannotBeChangedAfterStartRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingTerm _meetingTerm;\\r\\n\\r\\n        public MeetingCannotBeChangedAfterStartRule(MeetingTerm meetingTerm)\\r\\n        {\\r\\n            _meetingTerm = meetingTerm;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _meetingTerm.IsAfterStart();\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting cannot be changed after start\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"395\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"396\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":73}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingGuestsLimitCannotBeNegativeRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingGuestsLimitCannotBeNegativeRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int _guestsLimit;\\r\\n\\r\\n        public MeetingGuestsLimitCannotBeNegativeRule(int guestsLimit)\\r\\n        {\\r\\n            _guestsLimit = guestsLimit;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _guestsLimit \\u003C 0;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Guests limit cannot be negative\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"397\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"398\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_guestsLimit \\u003E 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":51}},\"status\":\"Killed\",\"static\":false},{\"id\":\"399\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_guestsLimit \\u003C= 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":51}},\"status\":\"Killed\",\"static\":false},{\"id\":\"400\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":67}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingGuestsNumberIsAboveLimitRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingGuestsNumberIsAboveLimitRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int _guestsNumber;\\r\\n\\r\\n        private readonly int _guestsLimit;\\r\\n\\r\\n        public MeetingGuestsNumberIsAboveLimitRule(int guestsLimit, int guestsNumber)\\r\\n        {\\r\\n            _guestsNumber = guestsNumber;\\r\\n            _guestsLimit = guestsLimit;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E this._guestsLimit \\u003E 0 \\u0026\\u0026 this._guestsLimit \\u003C _guestsNumber;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting guests number is above limit\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"401\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"402\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"this._guestsLimit \\u003E 0 || this._guestsLimit \\u003C _guestsNumber\",\"location\":{\"start\":{\"line\":17,\"column\":35},\"end\":{\"line\":17,\"column\":93}},\"status\":\"Killed\",\"static\":false},{\"id\":\"403\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._guestsLimit \\u003C 0 \",\"location\":{\"start\":{\"line\":17,\"column\":35},\"end\":{\"line\":17,\"column\":56}},\"status\":\"Killed\",\"static\":false},{\"id\":\"404\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._guestsLimit \\u003E= 0 \",\"location\":{\"start\":{\"line\":17,\"column\":35},\"end\":{\"line\":17,\"column\":56}},\"status\":\"Killed\",\"static\":false},{\"id\":\"405\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._guestsLimit \\u003E _guestsNumber\",\"location\":{\"start\":{\"line\":17,\"column\":60},\"end\":{\"line\":17,\"column\":93}},\"status\":\"Killed\",\"static\":false},{\"id\":\"406\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this._guestsLimit \\u003C= _guestsNumber\",\"location\":{\"start\":{\"line\":17,\"column\":60},\"end\":{\"line\":17,\"column\":93}},\"status\":\"Survived\",\"static\":false},{\"id\":\"407\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":19,\"column\":34},\"end\":{\"line\":19,\"column\":72}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MeetingMustHaveAtLeastOneHostRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MeetingMustHaveAtLeastOneHostRule : IBusinessRule\\r\\n    {\\r\\n        private readonly int _meetingHostNumber;\\r\\n\\r\\n        public MeetingMustHaveAtLeastOneHostRule(int meetingHostNumber)\\r\\n        {\\r\\n            _meetingHostNumber = meetingHostNumber;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _meetingHostNumber == 0;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Meeting must have at least one host\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"408\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"409\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_meetingHostNumber != 0\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":58}},\"status\":\"Killed\",\"static\":false},{\"id\":\"410\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":71}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MemberId _attendeeId;\\r\\n\\r\\n        private readonly List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n\\r\\n        public MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule(MemberId attendeeId, List\\u003CMeetingAttendee\\u003E attendees)\\r\\n        {\\r\\n            this._attendeeId = attendeeId;\\r\\n            _attendees = attendees;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_attendeeId)) != null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member is already an attendee of this meeting\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"411\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"412\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_attendeeId)) == null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":107}},\"status\":\"Killed\",\"static\":false},{\"id\":\"413\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_attendees.Single(x =\\u003E x.IsActiveAttendee(_attendeeId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"414\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":81}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MemberCannotBeMoreThanOnceOnMeetingWaitlistRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MemberCannotBeMoreThanOnceOnMeetingWaitlistRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingWaitlistMember\\u003E _waitListMembers;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        internal MemberCannotBeMoreThanOnceOnMeetingWaitlistRule(List\\u003CMeetingWaitlistMember\\u003E waitListMembers, MemberId memberId)\\r\\n        {\\r\\n            _waitListMembers = waitListMembers;\\r\\n            _memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _waitListMembers.SingleOrDefault(x =\\u003E x.IsActiveOnWaitList(_memberId)) != null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member cannot be more than once on the meeting waitlist\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"415\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"416\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_waitListMembers.SingleOrDefault(x =\\u003E x.IsActiveOnWaitList(_memberId)) == null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":113}},\"status\":\"Killed\",\"static\":false},{\"id\":\"417\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_waitListMembers.Single(x =\\u003E x.IsActiveOnWaitList(_memberId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":105}},\"status\":\"Killed\",\"static\":false},{\"id\":\"418\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":91}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MemberCannotBeNotAttendeeTwiceRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MemberCannotBeNotAttendeeTwiceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingNotAttendee\\u003E _notAttendees;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        public MemberCannotBeNotAttendeeTwiceRule(List\\u003CMeetingNotAttendee\\u003E notAttendees, MemberId memberId)\\r\\n        {\\r\\n            _notAttendees = notAttendees;\\r\\n            _memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(_memberId)) != null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member cannot be active not attendee twice\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"419\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"420\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(_memberId)) == null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"421\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_notAttendees.Single(x =\\u003E x.IsActiveNotAttendee(_memberId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"422\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":78}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MemberCannotHaveSetAttendeeRoleMoreThanOnceRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MemberCannotHaveSetAttendeeRoleMoreThanOnceRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingAttendeeRole _meetingAttendeeRole;\\r\\n\\r\\n        internal MemberCannotHaveSetAttendeeRoleMoreThanOnceRule(MeetingAttendeeRole meetingAttendeeRole)\\r\\n        {\\r\\n            _meetingAttendeeRole = meetingAttendeeRole;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _meetingAttendeeRole == MeetingAttendeeRole.Attendee;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member cannot be attendee of meeting more than once\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"423\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"424\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_meetingAttendeeRole != MeetingAttendeeRole.Attendee\",\"location\":{\"start\":{\"line\":14,\"column\":35},\"end\":{\"line\":14,\"column\":87}},\"status\":\"Killed\",\"static\":false},{\"id\":\"425\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":87}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\MemberOnWaitlistMustBeAMemberOfGroupRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class MemberOnWaitlistMustBeAMemberOfGroupRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        private readonly List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n\\r\\n        internal MemberOnWaitlistMustBeAMemberOfGroupRule(MeetingGroup meetingGroup, MemberId memberId, List\\u003CMeetingAttendee\\u003E attendees)\\r\\n            : base()\\r\\n        {\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _memberId = memberId;\\r\\n            _attendees = attendees;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E !_meetingGroup.IsMemberOfGroup(_memberId);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member on waitlist must be a member of group\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"426\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":18,\"column\":9},\"end\":{\"line\":22,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"427\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"_meetingGroup.IsMemberOfGroup(_memberId)\",\"location\":{\"start\":{\"line\":24,\"column\":35},\"end\":{\"line\":24,\"column\":76}},\"status\":\"Killed\",\"static\":false},{\"id\":\"428\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":26,\"column\":34},\"end\":{\"line\":26,\"column\":80}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\NotActiveMemberOfWaitlistCannotBeSignedOffRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class NotActiveMemberOfWaitlistCannotBeSignedOffRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingWaitlistMember\\u003E _waitlistMembers;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        public NotActiveMemberOfWaitlistCannotBeSignedOffRule(List\\u003CMeetingWaitlistMember\\u003E waitlistMembers, MemberId memberId)\\r\\n        {\\r\\n            _waitlistMembers = waitlistMembers;\\r\\n            _memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _waitlistMembers.SingleOrDefault(x =\\u003E x.IsActiveOnWaitList(_memberId)) == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Not active member of waitlist cannot be signed off\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"429\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"430\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_waitlistMembers.SingleOrDefault(x =\\u003E x.IsActiveOnWaitList(_memberId)) != null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":113}},\"status\":\"Killed\",\"static\":false},{\"id\":\"431\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_waitlistMembers.Single(x =\\u003E x.IsActiveOnWaitList(_memberId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":105}},\"status\":\"Killed\",\"static\":false},{\"id\":\"432\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":86}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\NotActiveNotAttendeeCannotChangeDecisionRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class NotActiveNotAttendeeCannotChangeDecisionRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingNotAttendee\\u003E _notAttendees;\\r\\n\\r\\n        private readonly MemberId _memberId;\\r\\n\\r\\n        internal NotActiveNotAttendeeCannotChangeDecisionRule(List\\u003CMeetingNotAttendee\\u003E notAttendees, MemberId memberId)\\r\\n        {\\r\\n            _notAttendees = notAttendees;\\r\\n            _memberId = memberId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(_memberId)) == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Member is not active not attendee\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"433\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"434\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_notAttendees.SingleOrDefault(x =\\u003E x.IsActiveNotAttendee(_memberId)) != null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"435\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_notAttendees.Single(x =\\u003E x.IsActiveNotAttendee(_memberId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":103}},\"status\":\"Killed\",\"static\":false},{\"id\":\"436\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":69}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\OnlyActiveAttendeeCanBeRemovedFromMeetingRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class OnlyActiveAttendeeCanBeRemovedFromMeetingRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n        private readonly MemberId _attendeeId;\\r\\n\\r\\n        internal OnlyActiveAttendeeCanBeRemovedFromMeetingRule(\\r\\n            List\\u003CMeetingAttendee\\u003E attendees,\\r\\n            MemberId attendeeId)\\r\\n        {\\r\\n            _attendees = attendees;\\r\\n            _attendeeId = attendeeId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_attendeeId)) == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only active attendee can be removed from meeting\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"437\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":16,\"column\":9},\"end\":{\"line\":19,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"438\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_attendeeId)) != null\",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":107}},\"status\":\"Killed\",\"static\":false},{\"id\":\"439\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_attendees.Single(x =\\u003E x.IsActiveAttendee(_attendeeId)) \",\"location\":{\"start\":{\"line\":21,\"column\":35},\"end\":{\"line\":21,\"column\":99}},\"status\":\"Killed\",\"static\":false},{\"id\":\"440\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":23,\"column\":34},\"end\":{\"line\":23,\"column\":84}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\OnlyMeetingAttendeeCanHaveChangedRoleRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    internal class OnlyMeetingAttendeeCanHaveChangedRoleRule : IBusinessRule\\r\\n    {\\r\\n        private readonly List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n\\r\\n        private readonly MemberId _newOrganizerId;\\r\\n\\r\\n        internal OnlyMeetingAttendeeCanHaveChangedRoleRule(List\\u003CMeetingAttendee\\u003E attendees, MemberId newOrganizerId)\\r\\n        {\\r\\n            _attendees = attendees;\\r\\n            _newOrganizerId = newOrganizerId;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E _attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_newOrganizerId)) == null;\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only meeting attendee can be se as organizer of meeting\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"441\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":18,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"442\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"_attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_newOrganizerId)) != null\",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":111}},\"status\":\"Killed\",\"static\":false},{\"id\":\"443\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_attendees.Single(x =\\u003E x.IsActiveAttendee(_newOrganizerId)) \",\"location\":{\"start\":{\"line\":20,\"column\":35},\"end\":{\"line\":20,\"column\":103}},\"status\":\"Survived\",\"static\":false},{\"id\":\"444\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":22,\"column\":34},\"end\":{\"line\":22,\"column\":91}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Meetings\\\\Rules\\\\OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule.cs\":{\"language\":\"cs\",\"source\":\"using System.Collections.Generic;\\r\\nusing System.Linq;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule : IBusinessRule\\r\\n    {\\r\\n        private readonly MemberId _settingMemberId;\\r\\n        private readonly MeetingGroup _meetingGroup;\\r\\n        private readonly List\\u003CMeetingAttendee\\u003E _attendees;\\r\\n\\r\\n        public OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(MemberId settingMemberId, MeetingGroup meetingGroup, List\\u003CMeetingAttendee\\u003E attendees)\\r\\n        {\\r\\n            _settingMemberId = settingMemberId;\\r\\n            _meetingGroup = meetingGroup;\\r\\n            _attendees = attendees;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken()\\r\\n        {\\r\\n            var settingMember = _attendees.SingleOrDefault(x =\\u003E x.IsActiveAttendee(_settingMemberId));\\r\\n\\r\\n            var isHost = settingMember != null \\u0026\\u0026 settingMember.IsActiveHost();\\r\\n            var isOrganizer = _meetingGroup.IsOrganizer(_settingMemberId);\\r\\n\\r\\n            return !isHost \\u0026\\u0026 !isOrganizer;\\r\\n        }\\r\\n\\r\\n        public string Message =\\u003E \\u0022Only meeting host or group organizer can set meeting member roles\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"445\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":16,\"column\":9},\"end\":{\"line\":20,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"446\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":23,\"column\":9},\"end\":{\"line\":30,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"447\",\"mutatorName\":\"Linq method mutation (SingleOrDefault() to Single())\",\"replacement\":\"_attendees.Single(x =\\u003E x.IsActiveAttendee(_settingMemberId))\",\"location\":{\"start\":{\"line\":24,\"column\":33},\"end\":{\"line\":24,\"column\":102}},\"status\":\"Killed\",\"static\":false},{\"id\":\"448\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"settingMember != null || settingMember.IsActiveHost()\",\"location\":{\"start\":{\"line\":26,\"column\":26},\"end\":{\"line\":26,\"column\":79}},\"status\":\"Killed\",\"static\":false},{\"id\":\"449\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"settingMember == null \",\"location\":{\"start\":{\"line\":26,\"column\":26},\"end\":{\"line\":26,\"column\":47}},\"status\":\"Killed\",\"static\":false},{\"id\":\"450\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!isHost || !isOrganizer\",\"location\":{\"start\":{\"line\":29,\"column\":20},\"end\":{\"line\":29,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"451\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"isHost \",\"location\":{\"start\":{\"line\":29,\"column\":20},\"end\":{\"line\":29,\"column\":27}},\"status\":\"Killed\",\"static\":false},{\"id\":\"452\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"isOrganizer\",\"location\":{\"start\":{\"line\":29,\"column\":31},\"end\":{\"line\":29,\"column\":43}},\"status\":\"Killed\",\"static\":false},{\"id\":\"453\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":32,\"column\":34},\"end\":{\"line\":32,\"column\":101}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Rules\\\\ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\\r\\n{\\r\\n    public class ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule : IBusinessRule\\r\\n    {\\r\\n        private readonly string _reason;\\r\\n\\r\\n        internal ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule(string reason)\\r\\n        {\\r\\n            _reason = reason;\\r\\n        }\\r\\n\\r\\n        public bool IsBroken() =\\u003E string.IsNullOrEmpty(_reason);\\r\\n\\r\\n        public string Message =\\u003E \\u0022Reason of removing attendee from meeting must be provided\\u0022;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"454\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"455\",\"mutatorName\":\"String mutation\",\"replacement\":\"\\u0022\\u0022\",\"location\":{\"start\":{\"line\":16,\"column\":34},\"end\":{\"line\":16,\"column\":93}},\"status\":\"Survived\",\"static\":false}]},\"Meetings\\\\Term.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\\r\\n{\\r\\n    public class Term : ValueObject\\r\\n    {\\r\\n        public static Term NoTerm =\\u003E new Term(null, null);\\r\\n\\r\\n        public DateTime? StartDate { get; }\\r\\n\\r\\n        public DateTime? EndDate { get; }\\r\\n\\r\\n        public static Term CreateNewBetweenDates(DateTime? startDate, DateTime? endDate)\\r\\n        {\\r\\n            return new Term(startDate, endDate);\\r\\n        }\\r\\n\\r\\n        private Term(DateTime? startDate, DateTime? endDate)\\r\\n        {\\r\\n            this.StartDate = startDate;\\r\\n            this.EndDate = endDate;\\r\\n        }\\r\\n\\r\\n        internal bool IsInTerm(DateTime date)\\r\\n        {\\r\\n            var left = !this.StartDate.HasValue || this.StartDate.Value \\u003C= date;\\r\\n\\r\\n            var right = !this.EndDate.HasValue || this.EndDate.Value \\u003E= date;\\r\\n\\r\\n            return left \\u0026\\u0026 right;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"456\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":15,\"column\":9},\"end\":{\"line\":17,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"457\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":20,\"column\":9},\"end\":{\"line\":23,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"458\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":26,\"column\":9},\"end\":{\"line\":32,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"459\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!this.StartDate.HasValue \\u0026\\u0026 this.StartDate.Value \\u003C= date\",\"location\":{\"start\":{\"line\":27,\"column\":24},\"end\":{\"line\":27,\"column\":80}},\"status\":\"Killed\",\"static\":false},{\"id\":\"460\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"this.StartDate.HasValue \",\"location\":{\"start\":{\"line\":27,\"column\":24},\"end\":{\"line\":27,\"column\":48}},\"status\":\"Killed\",\"static\":false},{\"id\":\"461\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.StartDate.Value \\u003E date\",\"location\":{\"start\":{\"line\":27,\"column\":52},\"end\":{\"line\":27,\"column\":80}},\"status\":\"Survived\",\"static\":false},{\"id\":\"462\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.StartDate.Value \\u003C date\",\"location\":{\"start\":{\"line\":27,\"column\":52},\"end\":{\"line\":27,\"column\":80}},\"status\":\"Survived\",\"static\":false},{\"id\":\"463\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"!this.EndDate.HasValue \\u0026\\u0026 this.EndDate.Value \\u003E= date\",\"location\":{\"start\":{\"line\":29,\"column\":25},\"end\":{\"line\":29,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"464\",\"mutatorName\":\"LogicalNotExpression to un-LogicalNotExpression mutation\",\"replacement\":\"this.EndDate.HasValue \",\"location\":{\"start\":{\"line\":29,\"column\":25},\"end\":{\"line\":29,\"column\":47}},\"status\":\"Killed\",\"static\":false},{\"id\":\"465\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.EndDate.Value \\u003C date\",\"location\":{\"start\":{\"line\":29,\"column\":51},\"end\":{\"line\":29,\"column\":77}},\"status\":\"Killed\",\"static\":false},{\"id\":\"466\",\"mutatorName\":\"Equality mutation\",\"replacement\":\"this.EndDate.Value \\u003E date\",\"location\":{\"start\":{\"line\":29,\"column\":51},\"end\":{\"line\":29,\"column\":77}},\"status\":\"Survived\",\"static\":false},{\"id\":\"467\",\"mutatorName\":\"Logical mutation\",\"replacement\":\"left || right\",\"location\":{\"start\":{\"line\":31,\"column\":20},\"end\":{\"line\":31,\"column\":33}},\"status\":\"Killed\",\"static\":false}]},\"Members\\\\Events\\\\MemberCreatedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.Events\\r\\n{\\r\\n    public class MemberCreatedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MemberCreatedDomainEvent(MemberId memberId)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"468\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":10,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"Killed\",\"static\":false}]},\"Members\\\\IMemberContext.cs\":{\"language\":\"cs\",\"source\":\"namespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\\r\\n{\\r\\n    public interface IMemberContext\\r\\n    {\\r\\n        MemberId MemberId { get; }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Members\\\\IMemberRepository.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Threading.Tasks;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\\r\\n{\\r\\n    public interface IMemberRepository\\r\\n    {\\r\\n        Task AddAsync(Member member);\\r\\n\\r\\n        Task\\u003CMember\\u003E GetByIdAsync(MemberId memberId);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Members\\\\MeetingGroupMemberData.cs\":{\"language\":\"cs\",\"source\":\"using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\\r\\n{\\r\\n    public class MeetingGroupMemberData\\r\\n    {\\r\\n        public MeetingGroupId MeetingGroupId { get; }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public MeetingGroupMemberData(MeetingGroupId meetingGroupId, MemberId memberId)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n            MeetingGroupId = meetingGroupId;\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"469\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":9},\"end\":{\"line\":15,\"column\":10}},\"status\":\"Survived\",\"static\":false}]},\"Members\\\\Member.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing System.Collections.Generic;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.Events;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\\r\\n{\\r\\n    public class Member : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MemberId Id { get; private set; }\\r\\n\\r\\n        private string _login;\\r\\n\\r\\n        private string _email;\\r\\n\\r\\n        private string _firstName;\\r\\n\\r\\n        private string _lastName;\\r\\n\\r\\n        private string _name;\\r\\n\\r\\n        private DateTime _createDate;\\r\\n\\r\\n        private Member()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        public static Member Create(Guid id, string login, string email, string firstName, string lastName, string name)\\r\\n        {\\r\\n            return new Member(id, login, email, firstName, lastName, name);\\r\\n        }\\r\\n\\r\\n        private Member(Guid id, string login, string email, string firstName, string lastName, string name)\\r\\n        {\\r\\n            this.Id = new MemberId(id);\\r\\n            _login = login;\\r\\n            _email = email;\\r\\n            _firstName = firstName;\\r\\n            _lastName = lastName;\\r\\n            _name = name;\\r\\n            _createDate = SystemClock.Now;\\r\\n\\r\\n            this.AddDomainEvent(new MemberCreatedDomainEvent(this.Id));\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"470\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":32,\"column\":9},\"end\":{\"line\":34,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"471\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":37,\"column\":9},\"end\":{\"line\":47,\"column\":10}},\"status\":\"Killed\",\"static\":false},{\"id\":\"472\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":46,\"column\":13},\"end\":{\"line\":46,\"column\":72}},\"status\":\"Killed\",\"static\":false}]},\"Members\\\\MemberId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\\r\\n{\\r\\n    public class MemberId : TypedIdValueBase\\r\\n    {\\r\\n        public MemberId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Members\\\\MemberSubscriptions\\\\Events\\\\MemberSubscriptionExpirationDateChangedDomainEvent.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions.Events\\r\\n{\\r\\n    public class MemberSubscriptionExpirationDateChangedDomainEvent : DomainEventBase\\r\\n    {\\r\\n        public MemberSubscriptionExpirationDateChangedDomainEvent(MemberId memberId, DateTime expirationDate)\\r\\n        {\\r\\n            MemberId = memberId;\\r\\n            ExpirationDate = expirationDate;\\r\\n        }\\r\\n\\r\\n        public MemberId MemberId { get; }\\r\\n\\r\\n        public DateTime ExpirationDate { get; }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"473\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":9,\"column\":9},\"end\":{\"line\":12,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Members\\\\MemberSubscriptions\\\\IMemberSubscriptionRepository.cs\":{\"language\":\"cs\",\"source\":\"using System.Threading.Tasks;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\\r\\n{\\r\\n    public interface IMemberSubscriptionRepository\\r\\n    {\\r\\n        Task\\u003CMemberSubscription\\u003E GetByIdOptionalAsync(MemberSubscriptionId memberSubscriptionId);\\r\\n\\r\\n        Task AddAsync(MemberSubscription memberSubscription);\\r\\n    }\\r\\n}\",\"mutants\":[]},\"Members\\\\MemberSubscriptions\\\\MemberSubscription.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions.Events;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\\r\\n{\\r\\n    public class MemberSubscription : Entity, IAggregateRoot\\r\\n    {\\r\\n        public MemberSubscriptionId Id { get; private set; }\\r\\n\\r\\n        private DateTime _expirationDate;\\r\\n\\r\\n        private MemberSubscription()\\r\\n        {\\r\\n            // Only for EF.\\r\\n        }\\r\\n\\r\\n        private MemberSubscription(MemberId memberId, DateTime expirationDate)\\r\\n        {\\r\\n            this.Id = new MemberSubscriptionId(memberId.Value);\\r\\n            _expirationDate = expirationDate;\\r\\n\\r\\n            this.AddDomainEvent(new MemberSubscriptionExpirationDateChangedDomainEvent(memberId, _expirationDate));\\r\\n        }\\r\\n\\r\\n        public static MemberSubscription CreateForMember(MemberId memberId, DateTime expirationDate)\\r\\n        {\\r\\n            return new MemberSubscription(memberId, expirationDate);\\r\\n        }\\r\\n\\r\\n        public void ChangeExpirationDate(DateTime expirationDate)\\r\\n        {\\r\\n            _expirationDate = expirationDate;\\r\\n\\r\\n            this.AddDomainEvent(new MemberSubscriptionExpirationDateChangedDomainEvent(\\r\\n                new MemberId(this.Id.Value),\\r\\n                _expirationDate));\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"474\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":19,\"column\":9},\"end\":{\"line\":24,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"475\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":23,\"column\":13},\"end\":{\"line\":23,\"column\":116}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"476\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":27,\"column\":9},\"end\":{\"line\":29,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"477\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":32,\"column\":9},\"end\":{\"line\":38,\"column\":10}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false},{\"id\":\"478\",\"mutatorName\":\"Statement mutation\",\"replacement\":\";\",\"location\":{\"start\":{\"line\":35,\"column\":13},\"end\":{\"line\":37,\"column\":35}},\"status\":\"NoCoverage\",\"statusReason\":\"Mutant has no test coverage\",\"static\":false}]},\"Members\\\\MemberSubscriptions\\\\MemberSubscriptionId.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\\r\\n{\\r\\n    public class MemberSubscriptionId : TypedIdValueBase\\r\\n    {\\r\\n        public MemberSubscriptionId(Guid value)\\r\\n            : base(value)\\r\\n        {\\r\\n        }\\r\\n    }\\r\\n}\",\"mutants\":[]},\"SharedKernel\\\\SystemClock.cs\":{\"language\":\"cs\",\"source\":\"using System;\\r\\n\\r\\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel\\r\\n{\\r\\n    public static class SystemClock\\r\\n    {\\r\\n        private static DateTime? _customDate;\\r\\n\\r\\n        public static DateTime Now\\r\\n        {\\r\\n            get\\r\\n            {\\r\\n                if (_customDate.HasValue)\\r\\n                {\\r\\n                    return _customDate.Value;\\r\\n                }\\r\\n\\r\\n                return DateTime.UtcNow;\\r\\n            }\\r\\n        }\\r\\n\\r\\n        public static void Set(DateTime customDate) =\\u003E _customDate = customDate;\\r\\n\\r\\n        public static void Reset() =\\u003E _customDate = null;\\r\\n    }\\r\\n}\",\"mutants\":[{\"id\":\"479\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":12,\"column\":13},\"end\":{\"line\":19,\"column\":14}},\"status\":\"Killed\",\"static\":false},{\"id\":\"480\",\"mutatorName\":\"Negate expression\",\"replacement\":\"!(_customDate.HasValue)\",\"location\":{\"start\":{\"line\":13,\"column\":21},\"end\":{\"line\":13,\"column\":41}},\"status\":\"Killed\",\"static\":false},{\"id\":\"481\",\"mutatorName\":\"Block removal mutation\",\"replacement\":\"{}\",\"location\":{\"start\":{\"line\":14,\"column\":17},\"end\":{\"line\":16,\"column\":18}},\"status\":\"Killed\",\"static\":false}]}}};\n\n            function updateTheme() {\n                document.body.style.backgroundColor = app.themeBackgroundColor;\n            }\n            app.addEventListener('theme-changed', updateTheme);\n            updateTheme();\n        </script>\n    </body>\n</html>\n\n"
  },
  {
    "path": "runIntegrationTests.cmd",
    "content": "@ECHO OFF\nSETLOCAL\nSET CONTAINER_ID=\nFOR /f %%i IN ('docker ps -q -f name^=myMeetings-integration-db') DO SET CONTAINER_ID=%%i\n\nIF \"%CONTAINER_ID%\"==\"\" (\n    ECHO \"not found\"\n) ELSE (\n\tdocker rm --force myMeetings-integration-db\n)\n\ndocker run --rm --name myMeetings-integration-db -e \"ACCEPT_EULA=Y\" -e \"SA_PASSWORD=61cD4gE6!\" -e \"MSSQL_PID=Express\" -p 1439:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu\nTIMEOUT 30\ndocker cp ./src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Linux.sql myMeetings-integration-db:/\ndocker exec -i myMeetings-integration-db sh -c \"/opt/mssql-tools/bin/sqlcmd -d master -i /CreateDatabase_Linux.sql -U sa -P 61cD4gE6!\"\ndotnet build src/ --configuration Release --no-restore\nSET ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString=Server=localhost,1439;Database=MyMeetings;User=sa;Password=61cD4gE6!\ndotnet \"src/Database/DatabaseMigrator/bin/Release/netcoreapp3.1/DatabaseMigrator.dll\" %ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString% \"src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations\"\ndotnet test --configuration Release --no-build --verbosity normal src/Modules/Administration/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Administration.IntegrationTests.csproj\ndotnet test --configuration Release --no-build --verbosity normal src/Modules/Payments/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Payments.IntegrationTests.csproj\ndotnet test --configuration Release --no-build --verbosity normal src/Modules/UserAccess/Tests/IntegrationTests/CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.csproj\ndotnet test --configuration Release --no-build --verbosity normal src/Modules/Meetings/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.csproj\ndotnet test --configuration Release --no-build --verbosity normal src/Tests/IntegrationTests/CompanyName.MyMeetings.IntegrationTests.csproj\n"
  },
  {
    "path": "src/.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"
  },
  {
    "path": "src/.editorconfig",
    "content": "﻿[*.cs]\n\n# SA1309: Field names should not begin with underscore\ndotnet_diagnostic.SA1309.severity = none\n\n# SA1600: Elements should be documented\ndotnet_diagnostic.SA1600.severity = none\n\n# SA1633: File should have header\ndotnet_diagnostic.SA1633.severity = none\n\n# SA1200: Using directives should be placed correctly\ndotnet_diagnostic.SA1200.severity = none\n\n# SA1402: File may only contain a single type\ndotnet_diagnostic.SA1402.severity = suggestion\n\n# SA1101: Prefix local calls with this\ndotnet_diagnostic.SA1101.severity = none\n\n# SA0001: All diagnostics of XML documentation comments has been disabled due to the current project configuration.\ndotnet_diagnostic.SA0001.severity = none\n\n# SA1201: Elements should appear in the correct order\ndotnet_diagnostic.SA1201.severity = none\n\n# SA1204: Static elements should appear before instance elements\ndotnet_diagnostic.SA1204.severity = none\n\n# SA1413: Use trailing comma in multi-line initializers\ndotnet_diagnostic.SA1413.severity = none\n\n# SA1623: Property summary documentation should match accessors\ndotnet_diagnostic.SA1623.severity = none\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/CompanyName.MyMeetings.API.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>\n    <UserSecretsId>2b9855d3-f073-44d2-aa45-b15e896794b9</UserSecretsId>\n    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>\n    <DockerfileContext>..\\..</DockerfileContext>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\n    <DocumentationFile>bin\\Debug\\CompanyName.MyMeetings.API.xml</DocumentationFile>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"IdentityServer4.AccessTokenValidation\" Version=\"3.0.1\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/AttributeAuthorizationHandler.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute>\n        : AuthorizationHandler<TRequirement>\n        where TRequirement : IAuthorizationRequirement\n        where TAttribute : Attribute\n    {\n        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)\n        {\n            var endpoint = (context.Resource as HttpContext).GetEndpoint() as RouteEndpoint;\n            var attribute = endpoint?.Metadata.GetMetadata<TAttribute>();\n\n            return HandleRequirementAsync(context, requirement, attribute);\n        }\n\n        protected abstract Task HandleRequirementAsync(\n            AuthorizationHandlerContext context,\n            TRequirement requirement,\n            TAttribute attribute);\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/AuthorizationChecker.cs",
    "content": "﻿using System.Reflection;\nusing System.Text;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    public static class AuthorizationChecker\n    {\n        public static void CheckAllEndpoints()\n        {\n            var assembly = typeof(Startup).Assembly;\n            var allControllerTypes = assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(ControllerBase)));\n\n            List<string> notProtectedActionMethods = [];\n            foreach (var controllerType in allControllerTypes)\n            {\n                var controllerHasPermissionAttribute = controllerType.GetCustomAttribute<HasPermissionAttribute>();\n                if (controllerHasPermissionAttribute != null)\n                {\n                    continue;\n                }\n\n                var actionMethods = controllerType.GetMethods()\n                    .Where(x => x.IsPublic && x.DeclaringType == controllerType)\n                    .ToList();\n\n                foreach (var publicMethod in actionMethods)\n                {\n                    var hasPermissionAttribute = publicMethod.GetCustomAttribute<HasPermissionAttribute>();\n                    if (hasPermissionAttribute == null)\n                    {\n                        var noPermissionRequired = publicMethod.GetCustomAttribute<NoPermissionRequiredAttribute>();\n\n                        if (noPermissionRequired == null)\n                        {\n                            notProtectedActionMethods.Add($\"{controllerType.Name}.{publicMethod.Name}\");\n                        }\n                    }\n                }\n            }\n\n            if (notProtectedActionMethods.Any())\n            {\n                var errorBuilder = new StringBuilder();\n                errorBuilder.AppendLine(\"Invalid authorization configuration: \");\n\n                foreach (var notProtectedActionMethod in notProtectedActionMethods)\n                {\n                    errorBuilder.AppendLine($\"Method {notProtectedActionMethod} is not protected. \");\n                }\n\n                throw new ApplicationException(errorBuilder.ToString());\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/HasPermissionAttribute.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    internal class HasPermissionAttribute : AuthorizeAttribute\n    {\n        internal const string HasPermissionPolicyName = \"HasPermission\";\n\n        public HasPermissionAttribute(string name)\n            : base(HasPermissionPolicyName)\n        {\n            Name = name;\n        }\n\n        public string Name { get; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/HasPermissionAuthorizationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Microsoft.AspNetCore.Authorization;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    internal class HasPermissionAuthorizationHandler : AttributeAuthorizationHandler<\n        HasPermissionAuthorizationRequirement, HasPermissionAttribute>\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly IUserAccessModule _userAccessModule;\n\n        public HasPermissionAuthorizationHandler(\n            IExecutionContextAccessor executionContextAccessor,\n            IUserAccessModule userAccessModule)\n        {\n            _executionContextAccessor = executionContextAccessor;\n            _userAccessModule = userAccessModule;\n        }\n\n        protected override async Task HandleRequirementAsync(\n            AuthorizationHandlerContext context,\n            HasPermissionAuthorizationRequirement requirement,\n            HasPermissionAttribute attribute)\n        {\n            var permissions = await _userAccessModule.ExecuteQueryAsync(new GetUserPermissionsQuery(_executionContextAccessor.UserId));\n\n            if (!await AuthorizeAsync(attribute.Name, permissions))\n            {\n                context.Fail();\n                return;\n            }\n\n            context.Succeed(requirement);\n        }\n\n        private Task<bool> AuthorizeAsync(string permission, List<UserPermissionDto> permissions)\n        {\n#if !DEBUG\n            return Task.FromResult(true);\n#endif\n#pragma warning disable CS0162 // Unreachable code detected\n            return Task.FromResult(permissions.Any(x => x.Code == permission));\n#pragma warning restore CS0162 // Unreachable code detected\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/HasPermissionAuthorizationRequirement.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    public class HasPermissionAuthorizationRequirement : IAuthorizationRequirement\n    {\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Authorization/NoPermissionRequiredAttribute.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Configuration.Authorization\n{\n    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]\n    public class NoPermissionRequiredAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/ExecutionContext/CorrelationMiddleware.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Configuration.ExecutionContext\n{\n    internal class CorrelationMiddleware\n    {\n        internal const string CorrelationHeaderKey = \"CorrelationId\";\n        private readonly RequestDelegate _next;\n\n        public CorrelationMiddleware(RequestDelegate next)\n        {\n            _next = next;\n        }\n\n        public async Task Invoke(HttpContext context)\n        {\n            var correlationId = Guid.NewGuid();\n\n            context.Request?.Headers.Append(CorrelationHeaderKey, correlationId.ToString());\n\n            await _next.Invoke(context);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/ExecutionContext/ExecutionContextAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.API.Configuration.ExecutionContext\n{\n    public class ExecutionContextAccessor : IExecutionContextAccessor\n    {\n        private readonly IHttpContextAccessor _httpContextAccessor;\n\n        public ExecutionContextAccessor(IHttpContextAccessor httpContextAccessor)\n        {\n            _httpContextAccessor = httpContextAccessor;\n        }\n\n        public Guid UserId\n        {\n            get\n            {\n                if (_httpContextAccessor\n                    .HttpContext?\n                    .User?\n                    .Claims?\n                    .SingleOrDefault(x => x.Type == \"sub\")?\n                    .Value != null)\n                {\n                    return Guid.Parse(_httpContextAccessor.HttpContext.User.Claims.Single(\n                        x => x.Type == \"sub\").Value);\n                }\n\n                throw new ApplicationException(\"User context is not available\");\n            }\n        }\n\n        public Guid CorrelationId\n        {\n            get\n            {\n                if (IsAvailable && _httpContextAccessor.HttpContext.Request.Headers.Keys.Any(\n                    x => x == CorrelationMiddleware.CorrelationHeaderKey))\n                {\n                    return Guid.Parse(\n                        _httpContextAccessor.HttpContext.Request.Headers[CorrelationMiddleware.CorrelationHeaderKey]);\n                }\n\n                throw new ApplicationException(\"Http context and correlation id is not available\");\n            }\n        }\n\n        public bool IsAvailable => _httpContextAccessor.HttpContext != null;\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Extensions/SwaggerExtensions.cs",
    "content": "﻿using System.Reflection;\r\nusing Microsoft.OpenApi.Models;\r\n\r\nnamespace CompanyName.MyMeetings.API.Configuration.Extensions\r\n{\r\n    internal static class SwaggerExtensions\r\n    {\r\n        internal static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services)\r\n        {\r\n            services.AddSwaggerGen(options =>\r\n            {\r\n                options.SwaggerDoc(\"v1\", new OpenApiInfo\r\n                {\r\n                    Title = \"MyMeetings API\",\r\n                    Version = \"v1\",\r\n                    Description = \"MyMeetings API for modular monolith .NET application.\"\r\n                });\r\n                options.CustomSchemaIds(t => t.ToString());\r\n\r\n                var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;\r\n                var commentsFileName = $\"{Assembly.GetExecutingAssembly().GetName().Name}.xml\";\r\n                var commentsFile = Path.Combine(baseDirectory, commentsFileName);\r\n                options.IncludeXmlComments(commentsFile);\r\n\r\n                options.AddSecurityDefinition(\"Bearer\", new OpenApiSecurityScheme\r\n                {\r\n                    Description =\r\n                        \"JWT Authorization header using the Bearer scheme. Example: \\\"Authorization: Bearer {token}\\\"\",\r\n                    Name = \"Authorization\",\r\n                    In = ParameterLocation.Header,\r\n                    Type = SecuritySchemeType.ApiKey\r\n                });\r\n\r\n                options.AddSecurityRequirement(new OpenApiSecurityRequirement\r\n                {\r\n                    {\r\n                        new OpenApiSecurityScheme\r\n                        {\r\n                            Reference = new OpenApiReference\r\n                            {\r\n                                Type = ReferenceType.SecurityScheme,\r\n                                Id = \"Bearer\"\r\n                            },\r\n                            Scheme = \"oauth2\",\r\n                            Name = \"Bearer\",\r\n                            In = ParameterLocation.Header\r\n                        },\r\n                        new List<string>()\r\n                    }\r\n                });\r\n            });\r\n\r\n            return services;\r\n        }\r\n\r\n        internal static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)\r\n        {\r\n            app.UseSwagger();\r\n\r\n            app.UseSwaggerUI(c => { c.SwaggerEndpoint(\"/swagger/v1/swagger.json\", \"MyMeetings API\"); });\r\n\r\n            return app;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Validation/BusinessRuleValidationExceptionProblemDetails.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Validation\n{\n    public class BusinessRuleValidationExceptionProblemDetails : ProblemDetails\n    {\n        public BusinessRuleValidationExceptionProblemDetails(BusinessRuleValidationException exception)\n        {\n            Title = \"Business rule broken\";\n            Status = StatusCodes.Status409Conflict;\n            Detail = exception.Message;\n            Type = \"https://somedomain/business-rule-validation-error\";\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Configuration/Validation/InvalidCommandProblemDetails.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Configuration.Validation\n{\n    public class InvalidCommandProblemDetails : ProblemDetails\n    {\n        public InvalidCommandProblemDetails(InvalidCommandException exception)\n        {\n            Title = \"Command validation error\";\n            Status = StatusCodes.Status400BadRequest;\n            Type = \"https://somedomain/validation-error\";\n            Errors = exception.Errors;\n        }\n\n        public List<string> Errors { get; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Administration/AdministrationAutofacModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\n\nnamespace CompanyName.MyMeetings.API.Modules.Administration\n{\n    internal class AdministrationAutofacModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<AdministrationModule>()\n                .As<IAdministrationModule>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Administration/AdministrationPermissions.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Administration\n{\n    public class AdministrationPermissions\n    {\n        public const string AcceptMeetingGroupProposal = \"AcceptMeetingGroupProposal\";\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Administration/MeetingGroupProposals/MeetingGroupProposalsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposals;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Administration.MeetingGroupProposals\n{\n    [Route(\"api/administration/meetingGroupProposals\")]\n    [ApiController]\n    public class MeetingGroupProposalsController : ControllerBase\n    {\n        private readonly IAdministrationModule _administrationModule;\n\n        public MeetingGroupProposalsController(IAdministrationModule administrationModule)\n        {\n            _administrationModule = administrationModule;\n        }\n\n        [HttpGet(\"\")]\n        [HasPermission(AdministrationPermissions.AcceptMeetingGroupProposal)]\n        [ProducesResponseType(typeof(List<MeetingGroupProposalDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetMeetingGroupProposals()\n        {\n            var meetingGroupProposals =\n                await _administrationModule.ExecuteQueryAsync(new GetMeetingGroupProposalsQuery());\n\n            return Ok(meetingGroupProposals);\n        }\n\n        [HttpPatch(\"{meetingGroupProposalId}/accept\")]\n        [HasPermission(AdministrationPermissions.AcceptMeetingGroupProposal)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> AcceptMeetingGroupProposal(Guid meetingGroupProposalId)\n        {\n            await _administrationModule.ExecuteCommandAsync(\n                new AcceptMeetingGroupProposalCommand(meetingGroupProposalId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Countries/CountriesController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Countries;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.Countries\n{\n    [Route(\"api/meetings/countries\")]\n    [ApiController]\n    public class CountriesController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        public CountriesController(IMeetingsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpGet(\"\")]\n        [HasPermission(MeetingsPermissions.GetMeetingGroupProposals)]\n        [ProducesResponseType(typeof(List<CountryDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAllCountries(int? page, int? perPage)\n        {\n            var countries = await _meetingsModule.ExecuteQueryAsync(\n                new GetAllCountriesQuery());\n\n            return Ok(countries);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingCommentingConfiguration/MeetingCommentingConfigurationController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.DisableMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.EnableMeetingCommentingConfiguration;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingCommentingConfiguration\n{\n    [Route(\"api/meetings/meetings/{meetingId}/configuration/commenting\")]\n    [ApiController]\n    public class MeetingCommentingConfigurationController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        public MeetingCommentingConfigurationController(IMeetingsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpPatch(\"disable\")]\n        [HasPermission(MeetingsPermissions.DisableMeetingCommenting)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> DisableCommenting(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new DisableMeetingCommentingConfigurationCommand(meetingId));\n            return Ok();\n        }\n\n        [HttpPatch(\"enable\")]\n        [HasPermission(MeetingsPermissions.EnableMeetingCommenting)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> EnableCommenting(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new EnableMeetingCommentingConfigurationCommand(meetingId));\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingComments/AddMeetingCommentRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingComments\n{\n    public class AddMeetingCommentRequest\n    {\n        public Guid MeetingId { get; set; }\n\n        public string Comment { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingComments/EditMeetingCommentRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingComments\n{\n    public class EditMeetingCommentRequest\n    {\n        public string EditedComment { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingComments/MeetingCommentsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentLike;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentReply;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.EditMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingCommentLike;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingComments\n{\n    [Route(\"api/meetings/[controller]\")]\n    [ApiController]\n    public class MeetingCommentsController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingModule;\n\n        public MeetingCommentsController(IMeetingsModule meetingModule)\n        {\n            _meetingModule = meetingModule;\n        }\n\n        [HttpPost]\n        [HasPermission(MeetingsPermissions.AddMeetingComment)]\n        [ProducesResponseType(typeof(Guid), StatusCodes.Status200OK)]\n        public async Task<IActionResult> AddComment([FromBody] AddMeetingCommentRequest request)\n        {\n            var commentId =\n                await _meetingModule.ExecuteCommandAsync(new AddMeetingCommentCommand(\n                    request.MeetingId,\n                    request.Comment));\n\n            return Ok(commentId);\n        }\n\n        [HttpPut(\"{meetingCommentId}\")]\n        [HasPermission(MeetingsPermissions.EditMeetingComment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> EditComment(\n            [FromRoute] Guid meetingCommentId,\n            [FromBody] EditMeetingCommentRequest request)\n        {\n            await _meetingModule.ExecuteCommandAsync(new EditMeetingCommentCommand(\n                meetingCommentId,\n                request.EditedComment));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingCommentId}\")]\n        [HasPermission(MeetingsPermissions.RemoveMeetingComment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> DeleteComment([FromRoute] Guid meetingCommentId, [FromQuery] string reason)\n        {\n            await _meetingModule.ExecuteCommandAsync(\n                new RemoveMeetingCommentCommand(meetingCommentId, reason));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingCommentId}/replies\")]\n        [HasPermission(MeetingsPermissions.AddMeetingCommentReply)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> AddReply([FromRoute] Guid meetingCommentId, [FromBody] string reply)\n        {\n            await _meetingModule.ExecuteCommandAsync(new AddReplyToMeetingCommentCommand(meetingCommentId, reply));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingCommentId}/likes\")]\n        [HasPermission(MeetingsPermissions.LikeMeetingComment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> LikeComment([FromRoute] Guid meetingCommentId)\n        {\n            await _meetingModule.ExecuteCommandAsync(\n                new AddMeetingCommentLikeCommand(meetingCommentId));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingCommentId}/likes\")]\n        [HasPermission(MeetingsPermissions.UnlikeMeetingComment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> UnlikeComment([FromRoute] Guid meetingCommentId)\n        {\n            await _meetingModule.ExecuteCommandAsync(\n                new RemoveMeetingCommentLikeCommand(meetingCommentId));\n\n            return Ok();\n        }\n    }\n}\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingGroupProposals/MeetingGroupProposalsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetAllMeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMemberMeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingGroupProposals\n{\n    [Route(\"api/meetings/[controller]\")]\n    [ApiController]\n    public class MeetingGroupProposalsController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        public MeetingGroupProposalsController(IMeetingsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpGet(\"\")]\n        [HasPermission(MeetingsPermissions.GetMeetingGroupProposals)]\n        [ProducesResponseType(typeof(List<MeetingGroupProposalDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetMemberMeetingGroupProposals()\n        {\n            var meetingGroupProposals = await _meetingsModule.ExecuteQueryAsync(\n                new GetMemberMeetingGroupProposalsQuery());\n\n            return Ok(meetingGroupProposals);\n        }\n\n        [HttpGet(\"all\")]\n        [HasPermission(MeetingsPermissions.GetMeetingGroupProposals)]\n        [ProducesResponseType(typeof(List<MeetingGroupProposalDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAllMeetingGroupProposals(int? page, int? perPage)\n        {\n            var meetingGroupProposals = await _meetingsModule.ExecuteQueryAsync(\n                new GetAllMeetingGroupProposalsQuery(page, perPage));\n\n            return Ok(meetingGroupProposals);\n        }\n\n        [HttpPost(\"\")]\n        [HasPermission(MeetingsPermissions.ProposeMeetingGroup)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> ProposeMeetingGroup(ProposeMeetingGroupRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(\n                new ProposeMeetingGroupCommand(\n                    request.Name,\n                    request.Description,\n                    request.LocationCity,\n                    request.LocationCountryCode));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingGroupProposals/ProposeMeetingGroupRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingGroupProposals\n{\n    public class ProposeMeetingGroupRequest\n    {\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationCountryCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingGroups/CreateNewMeetingGroupRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingGroups\n{\n    public class CreateNewMeetingGroupRequest\n    {\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationCountry { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingGroups/EditMeetingGroupGeneralAttributesRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingGroups\n{\n    public class EditMeetingGroupGeneralAttributesRequest\n    {\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationCountry { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingGroups/MeetingGroupsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.EditMeetingGroupGeneralAttributes;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAuthenticationMemberMeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetMeetingGroupDetails;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.JoinToGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.LeaveMeetingGroup;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.MeetingGroups\n{\n    [Route(\"api/meetings/[controller]\")]\n    [ApiController]\n    public class MeetingGroupsController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        public MeetingGroupsController(IMeetingsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpGet(\"\")]\n        [HasPermission(MeetingsPermissions.GetAuthenticatedMemberMeetingGroups)]\n        [ProducesResponseType(typeof(List<MemberMeetingGroupDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAuthenticatedMemberMeetingGroups()\n        {\n            var meetingGroups = await _meetingsModule.ExecuteQueryAsync(\n                new GetAuthenticationMemberMeetingGroupsQuery());\n\n            return Ok(meetingGroups);\n        }\n\n        [HttpGet(\"{meetingGroupId}\")]\n        [HasPermission(MeetingsPermissions.GetMeetingGroupDetails)]\n        [ProducesResponseType(typeof(MeetingGroupDetailsDto), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetMeetingGroupDetails(Guid meetingGroupId)\n        {\n            var meetingGroupDetails = await _meetingsModule.ExecuteQueryAsync(\n                new GetMeetingGroupDetailsQuery(meetingGroupId));\n\n            return Ok(meetingGroupDetails);\n        }\n\n        [HttpGet(\"all\")]\n        [HasPermission(MeetingsPermissions.GetAllMeetingGroups)]\n        [ProducesResponseType(typeof(List<MeetingGroupDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAllMeetingGroups()\n        {\n            var meetingGroups = await _meetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupsQuery());\n\n            return Ok(meetingGroups);\n        }\n\n        [HttpPut(\"{meetingGroupId}\")]\n        [HasPermission(MeetingsPermissions.EditMeetingGroupGeneralAttributes)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> EditMeetingGroupGeneralAttributes(\n            [FromRoute] Guid meetingGroupId,\n            [FromBody] EditMeetingGroupGeneralAttributesRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new EditMeetingGroupGeneralAttributesCommand(\n                meetingGroupId,\n                request.Name,\n                request.Description,\n                request.LocationCity,\n                request.LocationCountry));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingGroupId}/members\")]\n        [HasPermission(MeetingsPermissions.JoinToGroup)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> JoinToGroup(Guid meetingGroupId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new JoinToGroupCommand(meetingGroupId));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingGroupId}/members\")]\n        [HasPermission(MeetingsPermissions.LeaveMeetingGroup)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> LeaveMeetingGroup(Guid meetingGroupId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new LeaveMeetingGroupCommand(meetingGroupId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/AddMeetingAttendeeRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class AddMeetingAttendeeRequest\n    {\n        public int GuestsNumber { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/ChangeMeetingMainAttributesRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class ChangeMeetingMainAttributesRequest\n    {\n        public Guid MeetingId { get; set; }\n\n        public string Title { get; set; }\n\n        public DateTime TermStartDate { get; set; }\n\n        public DateTime TermEndDate { get; set; }\n\n        public string Description { get; set; }\n\n        public string MeetingLocationName { get; set; }\n\n        public string MeetingLocationAddress { get; set; }\n\n        public string MeetingLocationPostalCode { get; set; }\n\n        public string MeetingLocationCity { get; set; }\n\n        public int? AttendeesLimit { get; set; }\n\n        public int GuestsLimit { get; set; }\n\n        public DateTime? RSVPTermStartDate { get; set; }\n\n        public DateTime? RSVPTermEndDate { get; set; }\n\n        public decimal? EventFeeValue { get; set; }\n\n        public string EventFeeCurrency { get; set; }\n\n        public List<Guid> HostMemberIds { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/CreateMeetingRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class CreateMeetingRequest\n    {\n        public Guid MeetingGroupId { get; set; }\n\n        public string Title { get; set; }\n\n        public DateTime TermStartDate { get; set; }\n\n        public DateTime TermEndDate { get; set; }\n\n        public string Description { get; set; }\n\n        public string MeetingLocationName { get; set; }\n\n        public string MeetingLocationAddress { get; set; }\n\n        public string MeetingLocationPostalCode { get; set; }\n\n        public string MeetingLocationCity { get; set; }\n\n        public int? AttendeesLimit { get; set; }\n\n        public int GuestsLimit { get; set; }\n\n        public DateTime? RSVPTermStartDate { get; set; }\n\n        public DateTime? RSVPTermEndDate { get; set; }\n\n        public decimal? EventFeeValue { get; set; }\n\n        public string EventFeeCurrency { get; set; }\n\n        public List<Guid> HostMemberIds { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/MeetingsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingAttendee;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingNotAttendee;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CancelMeeting;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeMeetingMainAttributes;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeNotAttendeeDecision;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CreateMeeting;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetAuthenticatedMemberMeetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingAttendees;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingDetails;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.RemoveMeetingAttendee;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingAttendeeRole;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingHostRole;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignOffMemberFromWaitlist;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignUpMemberToWaitlist;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    [Route(\"api/meetings/meetings\")]\n    [ApiController]\n    public class MeetingsController : ControllerBase\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        public MeetingsController(IMeetingsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpGet(\"\")]\n        [HasPermission(MeetingsPermissions.GetAuthenticatedMemberMeetings)]\n        [ProducesResponseType(typeof(List<MemberMeetingDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAuthenticatedMemberMeetings()\n        {\n            var meetings = await _meetingsModule.ExecuteQueryAsync(new GetAuthenticatedMemberMeetingsQuery());\n\n            return Ok(meetings);\n        }\n\n        [HttpGet(\"{meetingId}\")]\n        [HasPermission(MeetingsPermissions.GetMeetingDetails)]\n        [ProducesResponseType(typeof(MeetingDetailsDto), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetMeetingDetails(Guid meetingId)\n        {\n            var meetingDetails = await _meetingsModule.ExecuteQueryAsync(new GetMeetingDetailsQuery(meetingId));\n\n            return Ok(meetingDetails);\n        }\n\n        [HttpPost(\"\")]\n        [HasPermission(MeetingsPermissions.CreateNewMeeting)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> CreateNewMeeting([FromBody] CreateMeetingRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new CreateMeetingCommand(\n                request.MeetingGroupId,\n                request.Title,\n                request.TermStartDate,\n                request.TermEndDate,\n                request.Description,\n                request.MeetingLocationName,\n                request.MeetingLocationAddress,\n                request.MeetingLocationPostalCode,\n                request.MeetingLocationCity,\n                request.AttendeesLimit,\n                request.GuestsLimit,\n                request.RSVPTermStartDate,\n                request.RSVPTermEndDate,\n                request.EventFeeValue,\n                request.EventFeeCurrency,\n                request.HostMemberIds));\n\n            return Ok();\n        }\n\n        [HttpPut(\"{meetingId}\")]\n        [HasPermission(MeetingsPermissions.EditMeeting)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> EditMeeting(\n            [FromRoute] Guid meetingId,\n            [FromBody] ChangeMeetingMainAttributesRequest mainAttributesRequest)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new ChangeMeetingMainAttributesCommand(\n                meetingId,\n                mainAttributesRequest.Title,\n                mainAttributesRequest.TermStartDate,\n                mainAttributesRequest.TermEndDate,\n                mainAttributesRequest.Description,\n                mainAttributesRequest.MeetingLocationName,\n                mainAttributesRequest.MeetingLocationAddress,\n                mainAttributesRequest.MeetingLocationPostalCode,\n                mainAttributesRequest.MeetingLocationCity,\n                mainAttributesRequest.AttendeesLimit,\n                mainAttributesRequest.GuestsLimit,\n                mainAttributesRequest.RSVPTermStartDate,\n                mainAttributesRequest.RSVPTermEndDate,\n                mainAttributesRequest.EventFeeValue,\n                mainAttributesRequest.EventFeeCurrency));\n\n            return Ok();\n        }\n\n        [HttpGet(\"{meetingId}/attendees\")]\n        [HasPermission(MeetingsPermissions.GetMeetingAttendees)]\n        [ProducesResponseType(typeof(List<MeetingAttendeeDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetMeetingAttendees(Guid meetingId)\n        {\n            var meetingAttendees = await _meetingsModule.ExecuteQueryAsync(new GetMeetingAttendeesQuery(meetingId));\n\n            return Ok(meetingAttendees);\n        }\n\n        [HttpPost(\"{meetingId}/attendees\")]\n        [HasPermission(MeetingsPermissions.AddMeetingAttendee)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> AddMeetingAttendee(\n            [FromRoute] Guid meetingId,\n            [FromBody] AddMeetingAttendeeRequest attendeeRequest)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new AddMeetingAttendeeCommand(\n                meetingId,\n                attendeeRequest.GuestsNumber));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingId}/attendees/{attendeeId}\")]\n        [HasPermission(MeetingsPermissions.RemoveMeetingAttendee)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> RemoveMeetingAttendee(\n            Guid meetingId,\n            Guid attendeeId,\n            RemoveMeetingAttendeeRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(\n                new RemoveMeetingAttendeeCommand(meetingId, attendeeId, request.RemovingReason));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingId}/notAttendees\")]\n        [HasPermission(MeetingsPermissions.AddNotAttendee)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> AddNotAttendee(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new AddMeetingNotAttendeeCommand(meetingId));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingId}/notAttendees\")]\n        [HasPermission(MeetingsPermissions.ChangeNotAttendeeDecision)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> ChangeNotAttendeeDecision(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new ChangeNotAttendeeDecisionCommand(meetingId));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingId}/waitlistMembers\")]\n        [HasPermission(MeetingsPermissions.SignUpMemberToWaitlist)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> SignUpMemberToWaitlist(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new SignUpMemberToWaitlistCommand(meetingId));\n\n            return Ok();\n        }\n\n        [HttpDelete(\"{meetingId}/waitlistMembers\")]\n        [HasPermission(MeetingsPermissions.SignOffMemberFromWaitlist)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> SignOffMemberFromWaitlist(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new SignOffMemberFromWaitlistCommand(meetingId));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingId}/hosts\")]\n        [HasPermission(MeetingsPermissions.SetMeetingHostRole)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> SetMeetingHostRole(Guid meetingId, SetMeetingHostRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new SetMeetingHostRoleCommand(request.AttendeeId, meetingId));\n\n            return Ok();\n        }\n\n        [HttpPost(\"{meetingId}/attendees/attendeeRole\")]\n        [HasPermission(MeetingsPermissions.SetMeetingAttendeeRole)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> SetMeetingAttendeeRole(Guid meetingId, SetMeetingHostRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new SetMeetingAttendeeRoleCommand(request.AttendeeId, meetingId));\n\n            return Ok();\n        }\n\n        [HttpPatch(\"{meetingId}/cancel\")]\n        [HasPermission(MeetingsPermissions.CancelMeeting)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> CancelMeeting(Guid meetingId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new CancelMeetingCommand(meetingId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/RemoveMeetingAttendeeRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class RemoveMeetingAttendeeRequest\n    {\n        public string RemovingReason { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/SetMeetingAttendeeRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class SetMeetingAttendeeRequest\n    {\n        public Guid AttendeeId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/Meetings/SetMeetingHostRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings.Meetings\n{\n    public class SetMeetingHostRequest\n    {\n        public Guid AttendeeId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingsAutofacModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\n\nnamespace CompanyName.MyMeetings.API.Modules.Meetings\n{\n    public class MeetingsAutofacModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<MeetingsModule>()\n                .As<IMeetingsModule>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Meetings/MeetingsPermissions.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Meetings\n{\n    public class MeetingsPermissions\n    {\n        public const string GetMeetingGroupProposals = \"GetMeetingGroupProposals\";\n        public const string ProposeMeetingGroup = \"ProposeMeetingGroup\";\n        public const string CreateNewMeeting = \"CreateNewMeeting\";\n        public const string EditMeeting = \"EditMeeting\";\n        public const string AddMeetingAttendee = \"AddMeetingAttendee\";\n        public const string RemoveMeetingAttendee = \"RemoveMeetingAttendee\";\n        public const string AddNotAttendee = \"AddNotAttendee\";\n        public const string ChangeNotAttendeeDecision = \"ChangeNotAttendeeDecision\";\n        public const string SignUpMemberToWaitlist = \"SignUpMemberToWaitlist\";\n        public const string SignOffMemberFromWaitlist = \"SignOffMemberFromWaitlist\";\n        public const string SetMeetingHostRole = \"SetMeetingHostRole\";\n        public const string SetMeetingAttendeeRole = \"SetMeetingAttendeeRole\";\n        public const string CancelMeeting = \"CancelMeeting\";\n        public const string GetAllMeetingGroups = \"GetAllMeetingGroups\";\n        public const string EditMeetingGroupGeneralAttributes = \"EditMeetingGroupGeneralAttributes\";\n        public const string JoinToGroup = \"JoinToGroup\";\n        public const string LeaveMeetingGroup = \"LeaveMeetingGroup\";\n        public const string AddMeetingComment = \"AddMeetingComment\";\n        public const string EditMeetingComment = \"EditMeetingComment\";\n        public const string RemoveMeetingComment = \"RemoveMeetingComment\";\n        public const string AddMeetingCommentReply = \"AddMeetingCommentReply\";\n        public const string LikeMeetingComment = \"LikeMeetingComment\";\n        public const string UnlikeMeetingComment = \"UnlikeMeetingComment\";\n        public const string EnableMeetingCommenting = \"EnableMeetingCommenting\";\n        public const string DisableMeetingCommenting = \"DisableMeetingCommenting\";\n        public const string GetAuthenticatedMemberMeetingGroups = \"GetAuthenticatedMemberMeetingGroups\";\n        public const string GetMeetingGroupDetails = \"GetMeetingGroupDetails\";\n        public const string GetMeetingDetails = \"GetMeetingDetails\";\n        public const string GetAuthenticatedMemberMeetings = \"GetAuthenticatedMemberMeetings\";\n        public const string GetMeetingAttendees = \"GetMeetingAttendees\";\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/MeetingFees/CreateMeetingFeePaymentRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.MeetingFees\n{\n    public class CreateMeetingFeePaymentRequest\n    {\n        public Guid MeetingFeeId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/MeetingFees/MeetingFeePaymentsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFeePayment;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments.MeetingFees\n{\n    [Route(\"api/payments/meetingFeePayments\")]\n    [ApiController]\n    public class MeetingFeePaymentsController : ControllerBase\n    {\n        private readonly IPaymentsModule _meetingsModule;\n\n        public MeetingFeePaymentsController(IPaymentsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpPost]\n        [HasPermission(PaymentsPermissions.RegisterPayment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> CreateMeetingFeePayment(CreateMeetingFeePaymentRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new CreateMeetingFeePaymentCommand(request.MeetingFeeId));\n\n            return Ok();\n        }\n\n        [HttpPut]\n        [Route(\"{meetingFeePaymentId}/purchased\")]\n        [HasPermission(PaymentsPermissions.RegisterPayment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> RegisterMeetingFeePayment(\n            Guid meetingFeePaymentId)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new MarkMeetingFeePaymentAsPaidCommand(meetingFeePaymentId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/MeetingFees/RegisterMeetingFeePaymentRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.MeetingFees\n{\n    public class RegisterMeetingFeePaymentRequest\n    {\n        public Guid PaymentId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Payers/PayersController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetPayerSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments.Payers\n{\n    [Route(\"api/payments/payers\")]\n    [ApiController]\n    public class PayersController : ControllerBase\n    {\n        private readonly IPaymentsModule _paymentsModule;\n\n        public PayersController(IPaymentsModule paymentsModule)\n        {\n            _paymentsModule = paymentsModule;\n        }\n\n        [HttpGet(\"authenticated/subscription\")]\n        [HasPermission(PaymentsPermissions.GetAuthenticatedPayerSubscription)]\n        [ProducesResponseType(typeof(SubscriptionDetailsDto), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAuthenticatedPayerSubscription()\n        {\n            var subscription = await _paymentsModule.ExecuteQueryAsync(new GetAuthenticatedPayerSubscriptionQuery());\n\n            return Ok(subscription);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PaymentsAutofacModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments\n{\n    public class PaymentsAutofacModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<PaymentsModule>()\n                .As<IPaymentsModule>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PaymentsPermissions.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments\n{\n    public class PaymentsPermissions\n    {\n        public const string RegisterPayment = \"RegisterPayment\";\n        public const string BuySubscription = \"BuySubscription\";\n        public const string RenewSubscription = \"RenewSubscription\";\n        public const string CreatePriceListItem = \"CreatePriceListItem\";\n        public const string ActivatePriceListItem = \"ActivatePriceListItem\";\n        public const string DeactivatePriceListItem = \"DeactivatePriceListItem\";\n        public const string ChangePriceListItemAttributes = \"ChangePriceListItemAttributes\";\n        public const string GetAuthenticatedPayerSubscription = \"GetAuthenticatedPayerSubscription\";\n        public const string GetPriceListItem = \"GetPriceListItem\";\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PriceListItems/ChangePriceListItemAttributesRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.PriceListItems\n{\n    public class ChangePriceListItemAttributesRequest\n    {\n        public Guid PriceListItemId { get; set; }\n\n        public string CountryCode { get; set; }\n\n        public string SubscriptionPeriodCode { get; set; }\n\n        public string CategoryCode { get; set; }\n\n        public decimal PriceValue { get; set; }\n\n        public string PriceCurrency { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PriceListItems/CreatePriceListItemRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.PriceListItems\n{\n    public class CreatePriceListItemRequest\n    {\n        public string CountryCode { get; set; }\n\n        public string SubscriptionPeriodCode { get; set; }\n\n        public string CategoryCode { get; set; }\n\n        public decimal PriceValue { get; set; }\n\n        public string PriceCurrency { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PriceListItems/GetPriceListItemRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.PriceListItems\n{\n    public class GetPriceListItemRequest\n    {\n        public string CountryCode { get; set; }\n\n        public string CategoryCode { get; set; }\n\n        public string PeriodTypeCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/PriceListItems/PriceListItemsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ActivatePriceListItem;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ChangePriceListItemAttributes;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.CreatePriceListItem;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.DeactivatePriceListItem;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItem;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments.PriceListItems\n{\n    [ApiController]\n    [Route(\"api/payments/priceListItems\")]\n    public class PriceListItemsController : ControllerBase\n    {\n        private readonly IPaymentsModule _paymentsModule;\n\n        public PriceListItemsController(IPaymentsModule paymentsModule)\n        {\n            _paymentsModule = paymentsModule;\n        }\n\n        [HttpGet]\n        [HasPermission(PaymentsPermissions.GetPriceListItem)]\n        [ProducesResponseType(typeof(PriceListItemMoneyValueDto), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetPriceListItem([FromQuery] GetPriceListItemRequest request)\n        {\n            var priceListItem = await _paymentsModule.ExecuteQueryAsync(new GetPriceListItemQuery(\n                request.CountryCode,\n                request.CategoryCode,\n                request.PeriodTypeCode));\n\n            return Ok(priceListItem);\n        }\n\n        [HttpPost]\n        [HasPermission(PaymentsPermissions.CreatePriceListItem)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> CreatePriceListItem([FromBody] CreatePriceListItemRequest request)\n        {\n            await _paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                request.SubscriptionPeriodCode,\n                request.CategoryCode,\n                request.CountryCode,\n                request.PriceValue,\n                request.PriceCurrency));\n\n            return Ok();\n        }\n\n        [HttpPatch(\"{priceListItemId}/activate\")]\n        [HasPermission(PaymentsPermissions.ActivatePriceListItem)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> ActivatePriceListItem([FromRoute] Guid priceListItemId)\n        {\n            await _paymentsModule.ExecuteCommandAsync(new ActivatePriceListItemCommand(priceListItemId));\n\n            return Ok();\n        }\n\n        [HttpPatch(\"{priceListItemId}/deactivate\")]\n        [HasPermission(PaymentsPermissions.DeactivatePriceListItem)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> DeactivatePriceListItem([FromRoute] Guid priceListItemId)\n        {\n            await _paymentsModule.ExecuteCommandAsync(new DeactivatePriceListItemCommand(priceListItemId));\n\n            return Ok();\n        }\n\n        [HttpPut]\n        [HasPermission(PaymentsPermissions.ChangePriceListItemAttributes)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> ChangePriceListItemAttributes(\n            [FromBody] ChangePriceListItemAttributesRequest request)\n        {\n            await _paymentsModule.ExecuteCommandAsync(new ChangePriceListItemAttributesCommand(\n                request.PriceListItemId,\n                request.CountryCode,\n                request.SubscriptionPeriodCode,\n                request.CategoryCode,\n                request.PriceValue,\n                request.PriceCurrency));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/RegisterSubscriptionRenewalPaymentRequest.cs",
    "content": "namespace CompanyName.MyMeetings.API.Modules.Payments\n{\n    public class RegisterSubscriptionRenewalPaymentRequest\n    {\n        public Guid PaymentId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/SubscriptionRenewalsController.cs",
    "content": "using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments\n{\n    [Route(\"api/payments/subscriptionRenewals\")]\n    [ApiController]\n    public class SubscriptionRenewalsController : ControllerBase\n    {\n        private readonly IPaymentsModule _paymentsModule;\n\n        public SubscriptionRenewalsController(IPaymentsModule paymentsModule)\n        {\n            _paymentsModule = paymentsModule;\n        }\n\n        [HttpPost]\n        [HasPermission(PaymentsPermissions.RegisterPayment)]\n        public async Task<IActionResult> RegisterSubscriptionPayment(RegisterSubscriptionRenewalPaymentRequest request)\n        {\n            await _paymentsModule.ExecuteCommandAsync(\n                new MarkSubscriptionRenewalPaymentAsPaidCommand(request.PaymentId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Subscriptions/BuySubscriptionRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.Subscriptions\n{\n    public class BuySubscriptionRequest\n    {\n        public string SubscriptionTypeCode { get; set; }\n\n        public string CountryCode { get; set; }\n\n        public decimal Value { get; set; }\n\n        public string Currency { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Subscriptions/RegisterSubscriptionPaymentRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.Subscriptions\n{\n    public class RegisterSubscriptionPaymentRequest\n    {\n        public Guid PaymentId { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Subscriptions/RenewSubscriptionRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.Payments.Subscriptions\n{\n    public class RenewSubscriptionRequest\n    {\n        public string SubscriptionTypeCode { get; set; }\n\n        public string CountryCode { get; set; }\n\n        public decimal Value { get; set; }\n\n        public string Currency { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Subscriptions/SubscriptionPaymentsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments.Subscriptions\n{\n    [Route(\"api/payments/subscriptionPayments\")]\n    [ApiController]\n    public class SubscriptionPaymentsController : ControllerBase\n    {\n        private readonly IPaymentsModule _meetingsModule;\n\n        public SubscriptionPaymentsController(IPaymentsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpPost]\n        [HasPermission(PaymentsPermissions.RegisterPayment)]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> RegisterSubscriptionPayment(RegisterSubscriptionPaymentRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(new MarkSubscriptionPaymentAsPaidCommand(request.PaymentId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/Payments/Subscriptions/SubscriptionsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscriptionRenewal;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.Payments.Subscriptions\n{\n    [Route(\"api/payments/subscriptions\")]\n    [ApiController]\n    public class SubscriptionsController : ControllerBase\n    {\n        private readonly IPaymentsModule _meetingsModule;\n\n        public SubscriptionsController(IPaymentsModule meetingsModule)\n        {\n            _meetingsModule = meetingsModule;\n        }\n\n        [HttpPost(\"\")]\n        [HasPermission(PaymentsPermissions.BuySubscription)]\n        public async Task<IActionResult> BuySubscription(BuySubscriptionRequest request)\n        {\n            var paymentId = await _meetingsModule.ExecuteCommandAsync(\n                new BuySubscriptionCommand(\n                    request.SubscriptionTypeCode,\n                    request.CountryCode,\n                    request.Value,\n                    request.Currency));\n\n            return Ok(paymentId);\n        }\n\n        [HttpPost(\"{subscriptionId}/renewals\")]\n        [HasPermission(PaymentsPermissions.RenewSubscription)]\n        public async Task<IActionResult> RenewSubscription(\n            Guid subscriptionId,\n            RenewSubscriptionRequest request)\n        {\n            await _meetingsModule.ExecuteCommandAsync(\n                new BuySubscriptionRenewalCommand(\n                    subscriptionId,\n                    request.SubscriptionTypeCode,\n                    request.CountryCode,\n                    request.Value,\n                    request.Currency));\n\n            return Accepted();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/UserAccess/AuthenticatedUserController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetAuthenticatedUserPermissions;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetAuthenticatedUser;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.UserAccess\n{\n    [Route(\"api/userAccess/authenticatedUser\")]\n    [ApiController]\n    public class AuthenticatedUserController : ControllerBase\n    {\n        private readonly IUserAccessModule _userAccessModule;\n\n        public AuthenticatedUserController(IUserAccessModule userAccessModule)\n        {\n            _userAccessModule = userAccessModule;\n        }\n\n        [NoPermissionRequired]\n        [HttpGet(\"\")]\n        [ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAuthenticatedUser()\n        {\n            var user = await _userAccessModule.ExecuteQueryAsync(new GetAuthenticatedUserQuery());\n\n            return Ok(user);\n        }\n\n        [NoPermissionRequired]\n        [HttpGet(\"permissions\")]\n        [ProducesResponseType(typeof(List<UserPermissionDto>), StatusCodes.Status200OK)]\n        public async Task<IActionResult> GetAuthenticatedUserPermissions()\n        {\n            var permissions = await _userAccessModule.ExecuteQueryAsync(new GetAuthenticatedUserPermissionsQuery());\n\n            return Ok(permissions);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/UserAccess/EmailsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Emails;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.UserAccess\n{\n    [Route(\"api/userAccess/emails\")]\n    [ApiController]\n    public class EmailsController : ControllerBase\n    {\n        private readonly IUserAccessModule _userAccessModule;\n\n        public EmailsController(IUserAccessModule userAccessModule)\n        {\n            _userAccessModule = userAccessModule;\n        }\n\n        [NoPermissionRequired]\n        [AllowAnonymous]\n        [HttpGet(\"\")]\n        public async Task<IActionResult> GetEmails()\n        {\n            var allEmails = await _userAccessModule.ExecuteQueryAsync(new GetAllEmailsQuery());\n\n            return Ok(allEmails);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/UserAccess/RegisterNewUserRequest.cs",
    "content": "﻿namespace CompanyName.MyMeetings.API.Modules.UserAccess\n{\n    public class RegisterNewUserRequest\n    {\n        public string Login { get; set; }\n\n        public string Password { get; set; }\n\n        public string Email { get; set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public string ConfirmLink { get; set; }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/UserAccess/UserAccessAutofacModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\n\nnamespace CompanyName.MyMeetings.API.Modules.UserAccess\n{\n    public class UserAccessAutofacModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<UserAccessModule>()\n                .As<IUserAccessModule>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Modules/UserAccess/UserRegistrationsController.cs",
    "content": "﻿using CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace CompanyName.MyMeetings.API.Modules.UserAccess\n{\n    [Route(\"userAccess/[controller]\")]\n    [ApiController]\n    public class UserRegistrationsController : ControllerBase\n    {\n        private readonly IRegistrationsModule _registrationsModule;\n\n        public UserRegistrationsController(IRegistrationsModule registrationsModule)\n        {\n            _registrationsModule = registrationsModule;\n        }\n\n        [NoPermissionRequired]\n        [AllowAnonymous]\n        [HttpPost(\"\")]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> RegisterNewUser(RegisterNewUserRequest request)\n        {\n            await _registrationsModule.ExecuteCommandAsync(new RegisterNewUserCommand(\n                request.Login,\n                request.Password,\n                request.Email,\n                request.FirstName,\n                request.LastName,\n                request.ConfirmLink));\n\n            return Ok();\n        }\n\n        [NoPermissionRequired]\n        [AllowAnonymous]\n        [HttpPatch(\"{userRegistrationId}/confirm\")]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> ConfirmRegistration(Guid userRegistrationId)\n        {\n            await _registrationsModule.ExecuteCommandAsync(new ConfirmUserRegistrationCommand(userRegistrationId));\n\n            return Ok();\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Program.cs",
    "content": "﻿using Autofac.Extensions.DependencyInjection;\n\nnamespace CompanyName.MyMeetings.API\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateWebHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateWebHostBuilder(string[] args)\n        {\n            return Host.CreateDefaultBuilder(args)\n                .UseServiceProviderFactory(new AutofacServiceProviderFactory())\n                .ConfigureWebHostDefaults(\n                    webBuilder => { webBuilder.UseStartup<Startup>(); });\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Properties/launchSettings.json",
    "content": "{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:57869\",\n      \"sslPort\": 44368\n    }\n  },\n  \"$schema\": \"http://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"api/values\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"DevWorkshops.Meetings.API\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"swagger\",\n        \"environmentVariables\": {\n            \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n        },\n      \"applicationUrl\": \"http://localhost:5000\"\n    },\n    \"Docker\": {\n      \"commandName\": \"Docker\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"{Scheme}://{ServiceHost}:{ServicePort}/api/values\",\n      \"publishAllPorts\": true,\n      \"useSSL\": true\n    }\n  }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/Startup.cs",
    "content": "﻿using Autofac;\nusing Autofac.Extensions.DependencyInjection;\nusing CompanyName.MyMeetings.API.Configuration.Authorization;\nusing CompanyName.MyMeetings.API.Configuration.ExecutionContext;\nusing CompanyName.MyMeetings.API.Configuration.Extensions;\nusing CompanyName.MyMeetings.API.Configuration.Validation;\nusing CompanyName.MyMeetings.API.Modules.Administration;\nusing CompanyName.MyMeetings.API.Modules.Meetings;\nusing CompanyName.MyMeetings.API.Modules.Payments;\nusing CompanyName.MyMeetings.API.Modules.UserAccess;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Identity;\nusing Hellang.Middleware.ProblemDetails;\nusing Microsoft.AspNetCore.Authentication;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Server.HttpSys;\nusing Serilog;\nusing Serilog.Formatting.Compact;\nusing ILogger = Serilog.ILogger;\n\nnamespace CompanyName.MyMeetings.API\n{\n    public class Startup\n    {\n        private const string MeetingsConnectionString = \"MeetingsConnectionString\";\n        private static ILogger _logger;\n        private static ILogger _loggerForApi;\n        private readonly IConfiguration _configuration;\n\n        public Startup(IWebHostEnvironment env)\n        {\n            ConfigureLogger();\n\n            _configuration = new ConfigurationBuilder()\n                .AddJsonFile(\"appsettings.json\")\n                .AddJsonFile($\"appsettings.{env.EnvironmentName}.json\")\n                .AddUserSecrets<Startup>()\n                .AddEnvironmentVariables(\"Meetings_\")\n                .Build();\n\n            _loggerForApi.Information(\"Connection string:\" + _configuration.GetConnectionString(MeetingsConnectionString));\n\n            AuthorizationChecker.CheckAllEndpoints();\n        }\n\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddControllers();\n\n            services.AddSwaggerDocumentation();\n\n            services.ConfigureIdentityService();\n\n            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();\n            services.AddSingleton<IExecutionContextAccessor, ExecutionContextAccessor>();\n\n            services.AddProblemDetails(x =>\n            {\n                x.Map<InvalidCommandException>(ex => new InvalidCommandProblemDetails(ex));\n                x.Map<BusinessRuleValidationException>(ex => new BusinessRuleValidationExceptionProblemDetails(ex));\n            });\n\n            services.AddAuthorization(options =>\n            {\n                options.AddPolicy(HasPermissionAttribute.HasPermissionPolicyName, policyBuilder =>\n                {\n                    policyBuilder.Requirements.Add(new HasPermissionAuthorizationRequirement());\n                    policyBuilder.AddAuthenticationSchemes(\"Bearer\");\n                });\n            });\n\n            services.AddScoped<IAuthorizationHandler, HasPermissionAuthorizationHandler>();\n        }\n\n        public void ConfigureContainer(ContainerBuilder containerBuilder)\n        {\n            containerBuilder.RegisterModule(new MeetingsAutofacModule());\n            containerBuilder.RegisterModule(new AdministrationAutofacModule());\n            containerBuilder.RegisterModule(new UserAccessAutofacModule());\n            containerBuilder.RegisterModule(new PaymentsAutofacModule());\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)\n        {\n            var container = app.ApplicationServices.GetAutofacRoot();\n\n            app.UseCors(builder =>\n                builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());\n\n            InitializeModules(container);\n\n            app.UseMiddleware<CorrelationMiddleware>();\n\n            app.UseSwaggerDocumentation();\n\n            app.AddIdentityService();\n\n            if (env.IsDevelopment())\n            {\n                app.UseProblemDetails();\n            }\n            else\n            {\n                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            // app.UseAuthentication();\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });\n        }\n\n        private static void ConfigureLogger()\n        {\n            _logger = new LoggerConfiguration()\n                .Enrich.FromLogContext()\n                .WriteTo.Console(\n                    outputTemplate:\n                    \"[{Timestamp:HH:mm:ss} {Level:u3}] [{Module}] [{Context}] {Message:lj}{NewLine}{Exception}\")\n                .WriteTo.File(new CompactJsonFormatter(), \"logs/logs\")\n                .CreateLogger();\n\n            _loggerForApi = _logger.ForContext(\"Module\", \"API\");\n\n            _loggerForApi.Information(\"Logger configured\");\n        }\n\n        private void InitializeModules(ILifetimeScope container)\n        {\n            var httpContextAccessor = container.Resolve<IHttpContextAccessor>();\n            var executionContextAccessor = new ExecutionContextAccessor(httpContextAccessor);\n\n            var emailsConfiguration = new EmailsConfiguration(_configuration[\"EmailsConfiguration:FromEmail\"]);\n\n            MeetingsStartup.Initialize(\n                _configuration.GetConnectionString(MeetingsConnectionString),\n                executionContextAccessor,\n                _logger,\n                emailsConfiguration,\n                null);\n\n            AdministrationStartup.Initialize(\n                _configuration.GetConnectionString(MeetingsConnectionString),\n                executionContextAccessor,\n                _logger,\n                null);\n\n            UserAccessStartup.Initialize(\n                _configuration.GetConnectionString(MeetingsConnectionString),\n                executionContextAccessor,\n                _logger,\n                emailsConfiguration,\n                _configuration[\"Security:TextEncryptionKey\"],\n                null,\n                null);\n\n            PaymentsStartup.Initialize(\n                _configuration.GetConnectionString(MeetingsConnectionString),\n                executionContextAccessor,\n                _logger,\n                emailsConfiguration,\n                null);\n\n            RegistrationsStartup.Initialize(\n                _configuration.GetConnectionString(MeetingsConnectionString),\n                executionContextAccessor,\n                _logger,\n                emailsConfiguration,\n                _configuration[\"Security:TextEncryptionKey\"],\n                null,\n                null);\n        }\n    }\n}"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/appsettings.Production.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Trace\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"None\"\n    }\n\n  },\n  \"AllowedHosts\": \"*\",\n\n  \"EmailsConfiguration\": {\n    \"FromEmail\": \"no-reply@mymeetings.com\"\n  },\n  \"Security\": {\n    /* NOTE! This is sensitive data and should be stored in secure way (not here). Added only for demo purpose. */\n    \"TextEncryptionKey\": \"E546C8DF278CK5990069B522\"\n  },\n  \"ConnectionStrings\": {\n    \"MeetingsConnectionString\": \"YourConnectioString\"\n  }\n}\n"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/entrypoint.sh",
    "content": "#!/bin/bash\nsleep 30 ;\n\ndotnet CompanyName.MyMeetings.API.dll"
  },
  {
    "path": "src/API/CompanyName.MyMeetings.API/tempkey.rsa",
    "content": "{\"KeyId\":\"6962297f9adb377dadb20e11b9d82f6c\",\"Parameters\":{\"D\":\"k4wzTPOMjoB3/gKcu/IGMXrLgZlmPR7NbtUb22Dkw8xhUMVGBV2fE7zEEZyR+jkvKTQbzL+vOA9pmAOxtgZk3AnB1c3ntreZjB3tjYdshglRq7I1VhVDdxJ6e8jwcXqdUhUMiXdYScdkA/jKUO9Ls1XVKA4iXl7fJ3nMhLNgsCXAzuS824XvDGEGJ6FZxjCNfGtTIgoZPFTyJvkHAqQ+Ll72BYdb0vS3gY7wNlAYScHdfBOhmeirvkN4Z9uXp1E/m+QGGlfgm7Eqdt0d4AjMQ8BeNR3wrMB4B5QN6ssP0ENVqIDSLxnq4NLL74fiqgBcFlu3nqSRcqgPB0tvMah2aQ==\",\"DP\":\"fTAwFVELf2DVCALpwParCuCChyFRgBWbgHanv4oRstuHHe2hgbasAKnXF+dO00D6k3Kvh5xFKlHr+e3W4hFI7nGM47DfVOX0L+DhsC2sa4qCHpMNU0EpJdrnASpPWWfBAiQPae+VC4WbzJQy1LOoH8Juqm5FqG8evZJ7otMzB9s=\",\"DQ\":\"hBz7Jz9TQoKsV//0KfXMlRFqO3v1qVe4A8b7knrTCL/0IjaD1edZvx3G6H6zkKXZkkXHVTYnJHMxIRm3Ds8C6EYwt9jfNtodQundv9w8xTKNJTemLKLtp9IuBBbL3X4dwZdriiI4woDRhe+ZD5fP25ElqbBlDC4ra1/N6KJUREU=\",\"Exponent\":\"AQAB\",\"InverseQ\":\"MrVycQYUEcmT6ddtkiXV4L3Qg+1iXgIbFF5OAtgXkD+lI+rclgUnFTYG3qgUhMn/ZtV/HhpW2FavUKCsmyv2Lmd1nVHe4LjgAjpKu9NlkripI/ROw8SculZEisI7P2lcAVI5kUSAQumiQg7kQcDqrTnrTI/T5m5LuygcGoYo3kA=\",\"Modulus\":\"nCbBW8+F6FuisseukkmknunroSMyJ8oi/yRyqWWBiVwiWYkvT88SfASyBLciDPXtV0PXsGkmxGyD4z/cQa5O5xU/gRHS3BKvxmuBribI+6JGBF1ukXoMooGIKEunDArgKb8O1bWDX7MyxU8sxyok73qOvtIqEb+ENKd1bFnP4PH/Yi3ZgHyTGcKfdRuB80WJQf8g9p1SFecg4Hhrh+j8XGeQow46bHgoKHelGSFlC6MFt12k0HISfty1AnHxrUP1IT5YpEWIDHNiexqJgc5Q2Bw9Tworux3sR6hQUh588NWSPw/9nhWT/l6AGifp7nJqiIEtgvrhWeVtUXJgZkWgnQ==\",\"P\":\"xSulQHBrGbZPrSqKiPBORAdK+ZHqg0VD6i9pCbzjDBWYGRS/ekbF/JQR81p/Wrm/K6hi1+eeDElZPK2e4WfyqQqVeDs6QQMjXjpSA/65WWdTDjNL7So2fYSUV70dwawo/EWtY1JHmBGEcKKDbeNGMwrP44iGQhE7wsGLQFB1NM8=\",\"Q\":\"yr34862ggc3OsYi8JFy83fmwiurGQc25+0U1UtiT0jhadSXcg+XEHjWUKTpHVJEIF+DKV+lwXTEtF5lsa1BAl5hHDwgcY19TJkaF4QIsfNMp0/s5iWNRdRhWKoqp9QGKxTOF9jpCeJgj0MUwLcFLZQ+UvWnqLv3yjsJ+De69xtM=\"}}"
  },
  {
    "path": "src/API/RequestExamples/Authentication.http",
    "content": "﻿### Authenticate Member\nPOST {{baseUrl}}/connect/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=testMember@mail.com&password=testMemberPass&client_id=ro.client&client_secret=secret\n\n### Authenticate Admin\nPOST {{baseUrl}}/connect/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=testAdmin@mail.com&password=testAdminPass&client_id=ro.client&client_secret=secret\n\n\n"
  },
  {
    "path": "src/API/RequestExamples/Users.http",
    "content": "﻿### Register a new user\nPOST {{baseUrl}}/userAccess/UserRegistrations\nContent-Type: application/json\n\n{\n  \"Login\": \"login\",\n  \"Password\": \"password\",\n  \"Email\": \"email@mail.com\",\n  \"FirstName\": \"John\",\n  \"LastName\": \"Doe\",\n  \"ConfirmLink\": \"Abc\"\n}\n\n\n### User registration confirmation\nPATCH {{baseUrl}}/userAccess/UserRegistrations/e80985c5-bf97-4bb3-b178-9423d70ef87b/confirm"
  },
  {
    "path": "src/API/RequestExamples/http-client.env.json",
    "content": "﻿{\n  \"dev\": {\n    \"baseUrl\": \"http://localhost:5000\"\n  }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/CompanyName.MyMeetings.BuildingBlocks.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/BuildingBlocks/Application/Data/ISqlConnectionFactory.cs",
    "content": "﻿using System.Data;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Application.Data\n{\n    public interface ISqlConnectionFactory\n    {\n        IDbConnection GetOpenConnection();\n\n        IDbConnection CreateNewConnection();\n\n        string GetConnectionString();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Emails/EmailMessage.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Emails\n{\n    public struct EmailMessage\n    {\n        public string To { get; }\n\n        public string Subject { get; }\n\n        public string Content { get; }\n\n        public EmailMessage(\n            string to,\n            string subject,\n            string content)\n        {\n            this.To = to;\n            this.Subject = subject;\n            this.Content = content;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Emails/IEmailSender.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Emails\n{\n    public interface IEmailSender\n    {\n        Task SendEmail(EmailMessage message);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Events/DomainNotificationBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Application.Events\n{\n    public class DomainNotificationBase<T> : IDomainEventNotification<T>\n        where T : IDomainEvent\n    {\n        public T DomainEvent { get; }\n\n        public Guid Id { get; }\n\n        public DomainNotificationBase(T domainEvent, Guid id)\n        {\n            this.Id = id;\n            this.DomainEvent = domainEvent;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Events/IDomainEventNotification.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Application.Events\n{\n    public interface IDomainEventNotification<out TEventType> : IDomainEventNotification\n    {\n        TEventType DomainEvent { get; }\n    }\n\n    public interface IDomainEventNotification : INotification\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/IExecutionContextAccessor.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application\n{\n    public interface IExecutionContextAccessor\n    {\n        Guid UserId { get; }\n\n        Guid CorrelationId { get; }\n\n        bool IsAvailable { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/InvalidCommandException.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application\n{\n    public class InvalidCommandException : Exception\n    {\n        public List<string> Errors { get; }\n\n        public InvalidCommandException(List<string> errors)\n        {\n            this.Errors = errors;\n        }\n    }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/Application/Outbox/IOutbox.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Outbox\n{\n    public interface IOutbox\n    {\n        void Add(OutboxMessage message);\n\n        Task Save();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Outbox/OutboxMessage.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Outbox\n{\n    public class OutboxMessage\n    {\n        public Guid Id { get; set; }\n\n        public DateTime OccurredOn { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n\n        public DateTime? ProcessedDate { get; set; }\n\n        public OutboxMessage(Guid id, DateTime occurredOn, string type, string data)\n        {\n            this.Id = id;\n            this.OccurredOn = occurredOn;\n            this.Type = type;\n            this.Data = data;\n        }\n\n        private OutboxMessage()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Queries/IPagedQuery.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Queries\n{\n    public interface IPagedQuery\n    {\n        /// <summary>\n        /// Page number. If null then default is 1.\n        /// </summary>\n        int? Page { get; }\n\n        /// <summary>\n        /// Records number per page (page size).\n        /// </summary>\n        int? PerPage { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Queries/PageData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Queries\n{\n    public struct PageData\n    {\n        public int Offset { get; }\n\n        public int Next { get; }\n\n        public PageData(int offset, int next)\n        {\n            this.Offset = offset;\n            this.Next = next;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Application/Queries/PagedQueryHelper.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Application.Queries\n{\n    public static class PagedQueryHelper\n    {\n        public const string Offset = \"Offset\";\n\n        public const string Next = \"Next\";\n\n        public static PageData GetPageData(IPagedQuery query)\n        {\n            int offset;\n            if (!query.Page.HasValue ||\n                !query.PerPage.HasValue)\n            {\n                offset = 0;\n            }\n            else\n            {\n                offset = (query.Page.Value - 1) * query.PerPage.Value;\n            }\n\n            int next;\n            if (!query.PerPage.HasValue)\n            {\n                next = int.MaxValue;\n            }\n            else\n            {\n                next = query.PerPage.Value;\n            }\n\n            return new PageData(offset, next);\n        }\n\n        public static string AppendPageStatement(string sql)\n        {\n            return $\"{sql} \" +\n                   $\"OFFSET @{Offset} ROWS FETCH NEXT @{Next} ROWS ONLY; \";\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/BusinessRuleValidationException.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public class BusinessRuleValidationException : Exception\n    {\n        public IBusinessRule BrokenRule { get; }\n\n        public string Details { get; }\n\n        public BusinessRuleValidationException(IBusinessRule brokenRule)\n            : base(brokenRule.Message)\n        {\n            BrokenRule = brokenRule;\n            this.Details = brokenRule.Message;\n        }\n\n        public override string ToString()\n        {\n            return $\"{BrokenRule.GetType().FullName}: {BrokenRule.Message}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/Domain/CompanyName.MyMeetings.BuildingBlocks.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/BuildingBlocks/Domain/DomainEventBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public class DomainEventBase : IDomainEvent\n    {\n        public Guid Id { get; }\n\n        public DateTime OccurredOn { get; }\n\n        public DomainEventBase()\n        {\n            this.Id = Guid.NewGuid();\n            this.OccurredOn = DateTime.UtcNow;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/Entity.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public abstract class Entity\n    {\n        private List<IDomainEvent> _domainEvents;\n\n        /// <summary>\n        /// Domain events occurred.\n        /// </summary>\n        public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents?.AsReadOnly();\n\n        public void ClearDomainEvents()\n        {\n            _domainEvents?.Clear();\n        }\n\n        /// <summary>\n        /// Add domain event.\n        /// </summary>\n        /// <param name=\"domainEvent\">Domain event.</param>\n        protected void AddDomainEvent(IDomainEvent domainEvent)\n        {\n            _domainEvents ??= [];\n\n            this._domainEvents.Add(domainEvent);\n        }\n\n        protected void CheckRule(IBusinessRule rule)\n        {\n            if (rule.IsBroken())\n            {\n                throw new BusinessRuleValidationException(rule);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/Domain/IAggregateRoot.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public interface IAggregateRoot\n    {\n    }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/Domain/IBusinessRule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public interface IBusinessRule\n    {\n        bool IsBroken();\n\n        string Message { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/IDomainEvent.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public interface IDomainEvent : INotification\n    {\n        Guid Id { get; }\n\n        DateTime OccurredOn { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/IgnoreMemberAttribute.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]\n    public class IgnoreMemberAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/TypedIdValueBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public abstract class TypedIdValueBase : IEquatable<TypedIdValueBase>\n    {\n        public Guid Value { get; }\n\n        protected TypedIdValueBase(Guid value)\n        {\n            if (value == Guid.Empty)\n            {\n                throw new InvalidOperationException(\"Id value cannot be empty!\");\n            }\n\n            Value = value;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj))\n            {\n                return false;\n            }\n\n            return obj is TypedIdValueBase other && Equals(other);\n        }\n\n        public override int GetHashCode()\n        {\n            return Value.GetHashCode();\n        }\n\n        public bool Equals(TypedIdValueBase other)\n        {\n            return this.Value == other?.Value;\n        }\n\n        public static bool operator ==(TypedIdValueBase obj1, TypedIdValueBase obj2)\n        {\n            if (object.Equals(obj1, null))\n            {\n                if (object.Equals(obj2, null))\n                {\n                    return true;\n                }\n\n                return false;\n            }\n\n            return obj1.Equals(obj2);\n        }\n\n        public static bool operator !=(TypedIdValueBase x, TypedIdValueBase y)\n        {\n            return !(x == y);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Domain/ValueObject.cs",
    "content": "﻿using System.Reflection;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Domain\n{\n    public abstract class ValueObject : IEquatable<ValueObject>\n    {\n        private List<PropertyInfo> _properties;\n\n        private List<FieldInfo> _fields;\n\n        public static bool operator ==(ValueObject obj1, ValueObject obj2)\n        {\n            if (object.Equals(obj1, null))\n            {\n                if (object.Equals(obj2, null))\n                {\n                    return true;\n                }\n\n                return false;\n            }\n\n            return obj1.Equals(obj2);\n        }\n\n        public static bool operator !=(ValueObject obj1, ValueObject obj2)\n        {\n            return !(obj1 == obj2);\n        }\n\n        public bool Equals(ValueObject obj)\n        {\n            return Equals(obj as object);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (obj == null || GetType() != obj.GetType())\n            {\n                return false;\n            }\n\n            return GetProperties().All(p => PropertiesAreEqual(obj, p))\n                && GetFields().All(f => FieldsAreEqual(obj, f));\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                int hash = 17;\n                foreach (var prop in GetProperties())\n                {\n                    var value = prop.GetValue(this, null);\n                    hash = HashValue(hash, value);\n                }\n\n                foreach (var field in GetFields())\n                {\n                    var value = field.GetValue(this);\n                    hash = HashValue(hash, value);\n                }\n\n                return hash;\n            }\n        }\n\n        protected static void CheckRule(IBusinessRule rule)\n        {\n            if (rule.IsBroken())\n            {\n                throw new BusinessRuleValidationException(rule);\n            }\n        }\n\n        private bool PropertiesAreEqual(object obj, PropertyInfo p)\n        {\n            return object.Equals(p.GetValue(this, null), p.GetValue(obj, null));\n        }\n\n        private bool FieldsAreEqual(object obj, FieldInfo f)\n        {\n            return object.Equals(f.GetValue(this), f.GetValue(obj));\n        }\n\n        private IEnumerable<PropertyInfo> GetProperties()\n        {\n            if (this._properties == null)\n            {\n                this._properties = GetType()\n                    .GetProperties(BindingFlags.Instance | BindingFlags.Public)\n                    .Where(p => p.GetCustomAttribute(typeof(IgnoreMemberAttribute)) == null)\n                    .ToList();\n\n                // Not available in Core\n                // !Attribute.IsDefined(p, typeof(IgnoreMemberAttribute))).ToList();\n            }\n\n            return this._properties;\n        }\n\n        private IEnumerable<FieldInfo> GetFields()\n        {\n            if (this._fields == null)\n            {\n                this._fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)\n                    .Where(p => p.GetCustomAttribute(typeof(IgnoreMemberAttribute)) == null)\n                    .ToList();\n            }\n\n            return this._fields;\n        }\n\n        private int HashValue(int seed, object value)\n        {\n            var currentHash = value?.GetHashCode() ?? 0;\n\n            return (seed * 23) + currentHash;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/BiDictionary.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public class BiDictionary<TFirst, TSecond>\n    {\n        private readonly IDictionary<TFirst, TSecond> _firstToSecond = new Dictionary<TFirst, TSecond>();\n\n        private readonly IDictionary<TSecond, TFirst> _secondToFirst = new Dictionary<TSecond, TFirst>();\n\n        public void Add(TFirst first, TSecond second)\n        {\n            if (_firstToSecond.ContainsKey(first) ||\n                _secondToFirst.ContainsKey(second))\n            {\n                throw new ArgumentException(\"Duplicate first or second\");\n            }\n\n            _firstToSecond.Add(first, second);\n            _secondToFirst.Add(second, first);\n        }\n\n        public bool TryGetByFirst(TFirst first, out TSecond second)\n        {\n            return _firstToSecond.TryGetValue(first, out second);\n        }\n\n        public bool TryGetBySecond(TSecond second, out TFirst first)\n        {\n            return _secondToFirst.TryGetValue(second, out first);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/CompanyName.MyMeetings.BuildingBlocks.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/DomainEventsAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public class DomainEventsAccessor : IDomainEventsAccessor\n    {\n        private readonly DbContext _dbContext;\n\n        public DomainEventsAccessor(DbContext dbContext)\n        {\n            _dbContext = dbContext;\n        }\n\n        public IReadOnlyCollection<IDomainEvent> GetAllDomainEvents()\n        {\n            var domainEntities = this._dbContext.ChangeTracker\n                .Entries<Entity>()\n                .Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()).ToList();\n\n            return domainEntities\n                .SelectMany(x => x.Entity.DomainEvents)\n                .ToList();\n        }\n\n        public void ClearAllDomainEvents()\n        {\n            var domainEntities = this._dbContext.ChangeTracker\n                .Entries<Entity>()\n                .Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()).ToList();\n\n            domainEntities\n                .ForEach(entity => entity.Entity.ClearDomainEvents());\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/DomainEventsDispatcher.cs",
    "content": "﻿using Autofac;\nusing Autofac.Core;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public class DomainEventsDispatcher : IDomainEventsDispatcher\n    {\n        private readonly IMediator _mediator;\n\n        private readonly ILifetimeScope _scope;\n\n        private readonly IOutbox _outbox;\n\n        private readonly IDomainEventsAccessor _domainEventsProvider;\n\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\n\n        public DomainEventsDispatcher(\n            IMediator mediator,\n            ILifetimeScope scope,\n            IOutbox outbox,\n            IDomainEventsAccessor domainEventsProvider,\n            IDomainNotificationsMapper domainNotificationsMapper)\n        {\n            _mediator = mediator;\n            _scope = scope;\n            _outbox = outbox;\n            _domainEventsProvider = domainEventsProvider;\n            _domainNotificationsMapper = domainNotificationsMapper;\n        }\n\n        public async Task DispatchEventsAsync()\n        {\n            var domainEvents = _domainEventsProvider.GetAllDomainEvents();\n\n            List<IDomainEventNotification<IDomainEvent>> domainEventNotifications = [];\n            foreach (var domainEvent in domainEvents)\n            {\n                Type domainEvenNotificationType = typeof(IDomainEventNotification<>);\n                var domainNotificationWithGenericType = domainEvenNotificationType.MakeGenericType(domainEvent.GetType());\n                var domainNotification = _scope.ResolveOptional(domainNotificationWithGenericType, new List<Parameter>\n                {\n                    new NamedParameter(\"domainEvent\", domainEvent),\n                    new NamedParameter(\"id\", domainEvent.Id)\n                });\n\n                if (domainNotification != null)\n                {\n                    domainEventNotifications.Add(domainNotification as IDomainEventNotification<IDomainEvent>);\n                }\n            }\n\n            _domainEventsProvider.ClearAllDomainEvents();\n\n            foreach (var domainEvent in domainEvents)\n            {\n                await _mediator.Publish(domainEvent);\n            }\n\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                var type = _domainNotificationsMapper.GetName(domainEventNotification.GetType());\n                var data = JsonConvert.SerializeObject(domainEventNotification, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                });\n\n                var outboxMessage = new OutboxMessage(\n                    domainEventNotification.Id,\n                    domainEventNotification.DomainEvent.OccurredOn,\n                    type,\n                    data);\n\n                _outbox.Add(outboxMessage);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/DomainEventsDispatcherNotificationHandlerDecorator.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public class DomainEventsDispatcherNotificationHandlerDecorator<T> : INotificationHandler<T>\n        where T : INotification\n    {\n        private readonly INotificationHandler<T> _decorated;\n        private readonly IDomainEventsDispatcher _domainEventsDispatcher;\n\n        public DomainEventsDispatcherNotificationHandlerDecorator(\n            IDomainEventsDispatcher domainEventsDispatcher,\n            INotificationHandler<T> decorated)\n        {\n            _domainEventsDispatcher = domainEventsDispatcher;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T notification, CancellationToken cancellationToken)\n        {\n            await this._decorated.Handle(notification, cancellationToken);\n\n            await this._domainEventsDispatcher.DispatchEventsAsync();\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/DomainNotificationsMapper.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public class DomainNotificationsMapper : IDomainNotificationsMapper\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public DomainNotificationsMapper(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        public string GetName(Type type)\n        {\n            return _domainNotificationsMap.TryGetBySecond(type, out var name) ? name : null;\n        }\n\n        public Type GetType(string name)\n        {\n            return _domainNotificationsMap.TryGetByFirst(name, out var type) ? type : null;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/IDomainEventsAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public interface IDomainEventsAccessor\n    {\n        IReadOnlyCollection<IDomainEvent> GetAllDomainEvents();\n\n        void ClearAllDomainEvents();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/IDomainEventsDispatcher.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public interface IDomainEventsDispatcher\n    {\n        Task DispatchEventsAsync();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/IDomainNotificationsMapper.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\n{\n    public interface IDomainNotificationsMapper\n    {\n        string GetName(Type type);\n\n        Type GetType(string name);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/DomainEventsDispatching/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using MediatR;\r\n\r\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching\r\n{\r\n    public class UnitOfWorkCommandHandlerDecorator<T> : IRequestHandler<T>\r\n        where T : IRequest\r\n    {\r\n        private readonly IRequestHandler<T> _decorated;\r\n        private readonly IUnitOfWork _unitOfWork;\r\n\r\n        public UnitOfWorkCommandHandlerDecorator(\r\n            IRequestHandler<T> decorated,\r\n            IUnitOfWork unitOfWork)\r\n        {\r\n            _decorated = decorated;\r\n            _unitOfWork = unitOfWork;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            await this._decorated.Handle(command, cancellationToken);\r\n\r\n            await this._unitOfWork.CommitAsync(cancellationToken);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/Emails/EmailSender.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing Dapper;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails\n{\n    public class EmailSender : IEmailSender\n    {\n        private readonly ILogger _logger;\n\n        private readonly EmailsConfiguration _configuration;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public EmailSender(\n            ILogger logger,\n            EmailsConfiguration configuration,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _logger = logger;\n            _configuration = configuration;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task SendEmail(EmailMessage message)\n        {\n            var sqlConnection = _sqlConnectionFactory.GetOpenConnection();\n\n            await sqlConnection.ExecuteScalarAsync(\n                \"INSERT INTO [app].[Emails] ([Id], [From], [To], [Subject], [Content], [Date]) \" +\n                \"VALUES (@Id, @From, @To, @Subject, @Content, @Date) \",\n                new\n                {\n                    Id = Guid.NewGuid(),\n                    From = _configuration.FromEmail,\n                    message.To,\n                    message.Subject,\n                    message.Content,\n                    Date = DateTime.UtcNow\n                });\n\n            _logger.Information(\n                \"Email sent. From: {From}, To: {To}, Subject: {Subject}, Content: {Content}.\",\n                _configuration.FromEmail,\n                message.To,\n                message.Subject,\n                message.Content);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/Emails/EmailsConfiguration.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails\n{\n    public class EmailsConfiguration\n    {\n        public EmailsConfiguration(string fromEmail)\n        {\n            FromEmail = fromEmail;\n        }\n\n        public string FromEmail { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/EventBus/IEventsBus.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus\n{\n    public interface IEventsBus : IDisposable\n    {\n        Task Publish<T>(T @event)\n            where T : IntegrationEvent;\n\n        void Subscribe<T>(IIntegrationEventHandler<T> handler)\n            where T : IntegrationEvent;\n\n        void StartConsuming();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/EventBus/IIntegrationEventHandler.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus\n{\n    public interface IIntegrationEventHandler<in TIntegrationEvent> : IIntegrationEventHandler\n        where TIntegrationEvent : IntegrationEvent\n    {\n        Task Handle(TIntegrationEvent @event);\n    }\n\n    public interface IIntegrationEventHandler\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/EventBus/InMemoryEventBus.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus\n{\n    public sealed class InMemoryEventBus\n    {\n        static InMemoryEventBus()\n        {\n        }\n\n        private InMemoryEventBus()\n        {\n            _handlersDictionary = new Dictionary<string, List<IIntegrationEventHandler>>();\n        }\n\n        public static InMemoryEventBus Instance { get; } = new InMemoryEventBus();\n\n        private readonly IDictionary<string, List<IIntegrationEventHandler>> _handlersDictionary;\n\n        public void Subscribe<T>(IIntegrationEventHandler<T> handler)\n            where T : IntegrationEvent\n        {\n            var eventType = typeof(T).FullName;\n            if (eventType != null)\n            {\n                if (_handlersDictionary.ContainsKey(eventType))\n                {\n                    var handlers = _handlersDictionary[eventType];\n                    handlers.Add(handler);\n                }\n                else\n                {\n                    _handlersDictionary.Add(eventType, [handler]);\n                }\n            }\n        }\n\n        public async Task Publish<T>(T @event)\n            where T : IntegrationEvent\n        {\n            var eventType = @event.GetType().FullName;\n\n            if (eventType == null)\n            {\n                return;\n            }\n\n            List<IIntegrationEventHandler> integrationEventHandlers = _handlersDictionary[eventType];\n\n            foreach (var integrationEventHandler in integrationEventHandlers)\n            {\n                if (integrationEventHandler is IIntegrationEventHandler<T> handler)\n                {\n                    await handler.Handle(@event);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/EventBus/InMemoryEventBusClient.cs",
    "content": "﻿using Serilog;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus\n{\n    public class InMemoryEventBusClient : IEventsBus\n    {\n        private readonly ILogger _logger;\n\n        public InMemoryEventBusClient(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public void Dispose()\n        {\n        }\n\n        public async Task Publish<T>(T @event)\n            where T : IntegrationEvent\n        {\n            _logger.Information(\"Publishing {Event}\", @event.GetType().FullName);\n            await InMemoryEventBus.Instance.Publish(@event);\n        }\n\n        public void Subscribe<T>(IIntegrationEventHandler<T> handler)\n            where T : IntegrationEvent\n        {\n            InMemoryEventBus.Instance.Subscribe(handler);\n        }\n\n        public void StartConsuming()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/EventBus/IntegrationEvent.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus\n{\n    public abstract class IntegrationEvent : INotification\n    {\n        public Guid Id { get; }\n\n        public DateTime OccurredOn { get; }\n\n        protected IntegrationEvent(Guid id, DateTime occurredOn)\n        {\n            this.Id = id;\n            this.OccurredOn = occurredOn;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/IUnitOfWork.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public interface IUnitOfWork\n    {\n        Task<int> CommitAsync(\n            CancellationToken cancellationToken = default,\n            Guid? internalCommandId = null);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/Inbox/InboxMessage.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Inbox\n{\n    public class InboxMessage\n    {\n        public Guid Id { get; set; }\n\n        public DateTime OccurredOn { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n\n        public DateTime? ProcessedDate { get; set; }\n\n        public InboxMessage(DateTime occurredOn, string type, string data)\n        {\n            this.Id = Guid.NewGuid();\n            this.OccurredOn = occurredOn;\n            this.Type = type;\n            this.Data = data;\n        }\n\n        private InboxMessage()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/InternalCommands/IInternalCommandsMapper.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands\n{\n    public interface IInternalCommandsMapper\n    {\n        string GetName(Type type);\n\n        Type GetType(string name);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/InternalCommands/InternalCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands\n{\n    public class InternalCommand\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n\n        public DateTime? ProcessedDate { get; set; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/InternalCommands/InternalCommandsMapper.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands\n{\n    public class InternalCommandsMapper : IInternalCommandsMapper\n    {\n        private readonly BiDictionary<string, Type> _internalCommandsMap;\n\n        public InternalCommandsMapper(BiDictionary<string, Type> internalCommandsMap)\n        {\n            _internalCommandsMap = internalCommandsMap;\n        }\n\n        public string GetName(Type type)\n        {\n            return _internalCommandsMap.TryGetBySecond(type, out var name) ? name : null;\n        }\n\n        public Type GetType(string name)\n        {\n            return _internalCommandsMap.TryGetByFirst(name, out var type) ? type : null;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/Serialization/AllPropertiesContractResolver.cs",
    "content": "﻿using System.Reflection;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization\n{\n    public class AllPropertiesContractResolver : DefaultContractResolver\n    {\n        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)\n        {\n            var properties = type.GetProperties(\n                    BindingFlags.Public |\n                    BindingFlags.NonPublic |\n                    BindingFlags.Instance)\n                .Select(p => this.CreateProperty(p, memberSerialization))\n                .ToList();\n\n            properties.ForEach(p =>\n            {\n                p.Writable = true;\n                p.Readable = true;\n            });\n\n            return properties;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/ServiceProviderWrapper.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public class ServiceProviderWrapper : IServiceProvider\n    {\n        private readonly ILifetimeScope lifeTimeScope;\n\n        public ServiceProviderWrapper(ILifetimeScope lifeTimeScope)\n        {\n            this.lifeTimeScope = lifeTimeScope;\n        }\n\n        #nullable enable\n        public object? GetService(Type serviceType) => this.lifeTimeScope.ResolveOptional(serviceType);\n    }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/SqlConnectionFactory.cs",
    "content": "﻿using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public class SqlConnectionFactory : ISqlConnectionFactory, IDisposable\n    {\n        private readonly string _connectionString;\n        private IDbConnection _connection;\n\n        public SqlConnectionFactory(string connectionString)\n        {\n            this._connectionString = connectionString;\n        }\n\n        public IDbConnection GetOpenConnection()\n        {\n            if (this._connection == null || this._connection.State != ConnectionState.Open)\n            {\n                this._connection = new SqlConnection(_connectionString);\n                this._connection.Open();\n            }\n\n            return this._connection;\n        }\n\n        public IDbConnection CreateNewConnection()\n        {\n            var connection = new SqlConnection(_connectionString);\n            connection.Open();\n\n            return connection;\n        }\n\n        public string GetConnectionString()\n        {\n            return _connectionString;\n        }\n\n        public void Dispose()\n        {\n            if (this._connection != null && this._connection.State == ConnectionState.Open)\n            {\n                this._connection.Dispose();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/StronglyTypedIdValueConverterSelector.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    /// <summary>\n    /// Based on https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-4/.\n    /// </summary>\n    public class StronglyTypedIdValueConverterSelector : ValueConverterSelector\n    {\n        private readonly ConcurrentDictionary<(Type ModelClrType, Type ProviderClrType), ValueConverterInfo> _converters\n            = new ConcurrentDictionary<(Type ModelClrType, Type ProviderClrType), ValueConverterInfo>();\n\n        public StronglyTypedIdValueConverterSelector(ValueConverterSelectorDependencies dependencies)\n            : base(dependencies)\n        {\n        }\n\n        public override IEnumerable<ValueConverterInfo> Select(Type modelClrType, Type providerClrType = null)\n        {\n            var baseConverters = base.Select(modelClrType, providerClrType);\n            foreach (var converter in baseConverters)\n            {\n                yield return converter;\n            }\n\n            var underlyingModelType = UnwrapNullableType(modelClrType);\n            var underlyingProviderType = UnwrapNullableType(providerClrType);\n\n            if (underlyingProviderType is null || underlyingProviderType == typeof(Guid))\n            {\n                var isTypedIdValue = typeof(TypedIdValueBase).IsAssignableFrom(underlyingModelType);\n                if (isTypedIdValue)\n                {\n                    var converterType = typeof(TypedIdValueConverter<>).MakeGenericType(underlyingModelType);\n\n                    yield return _converters.GetOrAdd((underlyingModelType, typeof(Guid)), _ =>\n                    {\n                        return new ValueConverterInfo(\n                            modelClrType: modelClrType,\n                            providerClrType: typeof(Guid),\n                            factory: valueConverterInfo => (ValueConverter)Activator.CreateInstance(converterType, valueConverterInfo.MappingHints));\n                    });\n                }\n            }\n        }\n\n        private static Type UnwrapNullableType(Type type)\n        {\n            if (type is null)\n            {\n                return null;\n            }\n\n            return Nullable.GetUnderlyingType(type) ?? type;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/TypedIdValueConverter.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public class TypedIdValueConverter<TTypedIdValue> : ValueConverter<TTypedIdValue, Guid>\n        where TTypedIdValue : TypedIdValueBase\n    {\n        public TypedIdValueConverter(ConverterMappingHints mappingHints = null)\n            : base(id => id.Value, value => Create(value), mappingHints)\n        {\n        }\n\n        private static TTypedIdValue Create(Guid id) => Activator.CreateInstance(typeof(TTypedIdValue), id) as TTypedIdValue;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Infrastructure/UnitOfWork.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Infrastructure\n{\n    public class UnitOfWork : IUnitOfWork\n    {\n        private readonly DbContext _context;\n        private readonly IDomainEventsDispatcher _domainEventsDispatcher;\n\n        public UnitOfWork(\n            DbContext context,\n            IDomainEventsDispatcher domainEventsDispatcher)\n        {\n            this._context = context;\n            this._domainEventsDispatcher = domainEventsDispatcher;\n        }\n\n        public async Task<int> CommitAsync(\n            CancellationToken cancellationToken = default,\n            Guid? internalCommandId = null)\n        {\n            await this._domainEventsDispatcher.DispatchEventsAsync();\n\n            return await _context.SaveChangesAsync(cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/Application.UnitTests/CompanyName.MyMeetings.BuildingBlocks.Application.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/BuildingBlocks/Tests/Application.UnitTests/Queries/PagedQueryHelperTests.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Queries;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.BuildingBlocks.Application.UnitTests.Queries\n{\n    [TestFixture]\n    public class PagedQueryHelperTests\n    {\n        [TestCase(1, 5, 0, 5)]\n        [TestCase(3, 10, 20, 10)]\n        [TestCase(null, 20, 0, 20)]\n        [TestCase(5, null, 0, int.MaxValue)]\n        [TestCase(null, null, 0, int.MaxValue)]\n        public void PagedQueryHelper_GetPageData_Test(int? page, int? perPage, int offset, int next)\n        {\n            IPagedQuery query = new TestQuery(page, perPage);\n            var pageData = PagedQueryHelper.GetPageData(query);\n\n            Assert.That(pageData, Is.EqualTo(new PageData(offset, next)));\n        }\n\n        private class TestQuery : IPagedQuery\n        {\n            public TestQuery(int? page, int? perPage)\n            {\n                Page = page;\n                PerPage = perPage;\n            }\n\n            public int? Page { get; }\n\n            public int? PerPage { get; }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/EnvironmentVariablesProvider.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.IntegrationTests\n{\n    public static class EnvironmentVariablesProvider\n    {\n        public static string GetVariable(string variableName)\n        {\n            var environmentVariable = Environment.GetEnvironmentVariable(variableName);\n\n            if (!string.IsNullOrEmpty(environmentVariable))\n            {\n                return environmentVariable;\n            }\n\n            environmentVariable = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.User);\n\n            if (!string.IsNullOrEmpty(environmentVariable))\n            {\n                return environmentVariable;\n            }\n\n            return Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Machine);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/Probing/AssertErrorException.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing\n{\n    public class AssertErrorException : Exception\n    {\n        public AssertErrorException(string message)\n            : base(message)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/Probing/IProbe.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing\n{\n    public interface IProbe\n    {\n        bool IsSatisfied();\n\n        Task SampleAsync();\n\n        string DescribeFailureTo();\n    }\n\n    public interface IProbe<T>\n    {\n        bool IsSatisfied(T sample);\n\n        Task<T> GetSampleAsync();\n\n        string DescribeFailureTo();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/Probing/Poller.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing\n{\n    public class Poller\n    {\n        private readonly int _timeoutMillis;\n\n        private readonly int _pollDelayMillis;\n\n        public Poller(int timeoutMillis)\n        {\n            _timeoutMillis = timeoutMillis;\n            _pollDelayMillis = 1000;\n        }\n\n        public async Task CheckAsync(IProbe probe)\n        {\n            var timeout = new Timeout(_timeoutMillis);\n            while (!probe.IsSatisfied())\n            {\n                if (timeout.HasTimedOut())\n                {\n                    throw new AssertErrorException(DescribeFailureOf(probe));\n                }\n\n                await Task.Delay(_pollDelayMillis);\n                await probe.SampleAsync();\n            }\n        }\n\n        public async Task<T> GetAsync<T>(IProbe<T> probe)\n            where T : class\n        {\n            var timeout = new Timeout(_timeoutMillis);\n            T sample = null;\n            while (!probe.IsSatisfied(sample))\n            {\n                if (timeout.HasTimedOut())\n                {\n                    throw new AssertErrorException(DescribeFailureOf(probe));\n                }\n\n                await Task.Delay(_pollDelayMillis);\n                sample = await probe.GetSampleAsync();\n            }\n\n            return sample;\n        }\n\n        private static string DescribeFailureOf(IProbe probe)\n        {\n            return probe.DescribeFailureTo();\n        }\n\n        private static string DescribeFailureOf<T>(IProbe<T> probe)\n        {\n            return probe.DescribeFailureTo();\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Tests/IntegrationTests/Probing/Timeout.cs",
    "content": "﻿namespace CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing\n{\n    public class Timeout\n    {\n        private readonly DateTime _endTime;\n\n        public Timeout(int duration)\n        {\n            this._endTime = DateTime.Now.AddMilliseconds(duration);\n        }\n\n        public bool HasTimedOut()\n        {\n            return DateTime.Now > _endTime;\n        }\n    }\n}\n"
  },
  {
    "path": "src/CompanyName.MyMeetings.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.8.34330.188\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.API\", \"API\\CompanyName.MyMeetings.API\\CompanyName.MyMeetings.API.csproj\", \"{49D08B64-AC8E-4607-820F-8A0B989CFD33}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"BuildingBlocks\", \"BuildingBlocks\", \"{E91D4BE3-61FE-441C-A227-29850D414216}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Modules\", \"Modules\", \"{BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Meetings\", \"Meetings\", \"{9CD43CAC-C149-41E1-9654-157D578143B7}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"UserAccess\", \"UserAccess\", \"{AE6D0618-60E1-40B2-A46F-664A19C9503C}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"API\", \"API\", \"{BC9DDFD1-FB81-4996-812A-68BEBCA33A97}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.Application\", \"Modules\\UserAccess\\Application\\CompanyName.MyMeetings.Modules.UserAccess.Application.csproj\", \"{F34C6504-590B-480A-A239-F230CDFF8CED}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.Application\", \"Modules\\Meetings\\Application\\CompanyName.MyMeetings.Modules.Meetings.Application.csproj\", \"{5C2C1630-8A7A-451F-81A8-8547C939F5FD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.Domain\", \"Modules\\Meetings\\Domain\\CompanyName.MyMeetings.Modules.Meetings.Domain.csproj\", \"{F71CFDA8-0770-4761-896A-FB0098113F87}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.Infrastructure\", \"Modules\\Meetings\\Infrastructure\\CompanyName.MyMeetings.Modules.Meetings.Infrastructure.csproj\", \"{93F3D023-37BD-4C5C-9442-DE2631CD4954}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.BuildingBlocks.Domain\", \"BuildingBlocks\\Domain\\CompanyName.MyMeetings.BuildingBlocks.Domain.csproj\", \"{CA91F71E-8067-4E98-A4D4-E17F5880DE39}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.BuildingBlocks.Infrastructure\", \"BuildingBlocks\\Infrastructure\\CompanyName.MyMeetings.BuildingBlocks.Infrastructure.csproj\", \"{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Administration\", \"Administration\", \"{5F398170-87FD-4368-9930-FAAAD2D9FDCC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.Domain\", \"Modules\\Administration\\Domain\\CompanyName.MyMeetings.Modules.Administration.Domain.csproj\", \"{590517F8-686B-460A-97B3-0A09A8BA443C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.Application\", \"Modules\\Administration\\Application\\CompanyName.MyMeetings.Modules.Administration.Application.csproj\", \"{6F039231-8745-4171-B5CA-8688E4683CFC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.Infrastructure\", \"Modules\\Administration\\Infrastructure\\CompanyName.MyMeetings.Modules.Administration.Infrastructure.csproj\", \"{CD765A37-EB16-4E35-AA03-6E706D70E8A0}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents\", \"Modules\\Meetings\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj\", \"{3ED61776-83A0-426C-9B3A-3AB755DA01EF}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Database\", \"Database\", \"{C733D087-7051-4E35-BCDB-081252A108E5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.IntegrationEvents\", \"Modules\\Administration\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.csproj\", \"{396817BD-94A7-4559-A7F1-2FAB8009BCF8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.Infrastructure\", \"Modules\\UserAccess\\Infrastructure\\CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.csproj\", \"{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.Domain\", \"Modules\\UserAccess\\Domain\\CompanyName.MyMeetings.Modules.UserAccess.Domain.csproj\", \"{F364B0C4-1882-46A1-9B08-22587BEF05A2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents\", \"Modules\\UserAccess\\IntegrationEvents\\CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj\", \"{0C31EA31-6A10-47D0-82E5-6D224E1CE532}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Payments\", \"Payments\", \"{13E4D721-2E96-497E-9657-503D09468F9F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.Application\", \"Modules\\Payments\\Application\\CompanyName.MyMeetings.Modules.Payments.Application.csproj\", \"{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.Domain\", \"Modules\\Payments\\Domain\\CompanyName.MyMeetings.Modules.Payments.Domain.csproj\", \"{C457929B-91BE-48CC-A714-217D9CABD3CC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.Infrastructure\", \"Modules\\Payments\\Infrastructure\\CompanyName.MyMeetings.Modules.Payments.Infrastructure.csproj\", \"{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.IntegrationEvents\", \"Modules\\Payments\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Payments.IntegrationEvents.csproj\", \"{8DF88C85-594D-45D7-B12E-6B641D497853}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.BuildingBlocks.Application\", \"BuildingBlocks\\Application\\CompanyName.MyMeetings.BuildingBlocks.Application.csproj\", \"{9EAA687B-951E-4D89-8857-99151FF1BCD7}\"\nEndProject\nProject(\"{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}\") = \"CompanyName.MyMeetings.Database\", \"Database\\CompanyName.MyMeetings.Database\\CompanyName.MyMeetings.Database.sqlproj\", \"{43DBBB02-CA43-42AD-BE21-04AC867BA168}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{0FF699EF-8156-43CB-8D18-8EA28F30E9EE}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.Domain.UnitTests\", \"Modules\\UserAccess\\Tests\\UnitTests\\CompanyName.MyMeetings.Modules.UserAccess.Domain.UnitTests.csproj\", \"{0BC12804-A858-427B-88E2-F9CDE9E97986}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{53E4F002-E708-45F7-8444-19EB8977B5C9}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests\", \"Modules\\Payments\\Tests\\UnitTests\\CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.csproj\", \"{602768DD-F063-469D-9CD3-95CB02F6E441}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{F544D6DA-740A-4313-9542-D989666EA9DE}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests\", \"Modules\\Administration\\Tests\\UnitTests\\CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.csproj\", \"{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{237A249C-B589-49B8-9B84-CA504DE5D137}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests\", \"Modules\\Meetings\\Tests\\UnitTests\\CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.csproj\", \"{E13970C6-87EE-40B1-854A-3053C95BC4C9}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{8B08A9EE-CE27-4CC3-ACB3-3BD9628E5479}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.ArchTests\", \"Tests\\ArchTests\\CompanyName.MyMeetings.ArchTests.csproj\", \"{88081DDB-2FBD-4F7D-830F-24F5F6B78294}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.ArchTests\", \"Modules\\Administration\\Tests\\ArchTests\\CompanyName.MyMeetings.Modules.Administration.ArchTests.csproj\", \"{F2B164AC-99AC-4906-A133-85D6BB8432B4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.ArchTests\", \"Modules\\Meetings\\Tests\\ArchTests\\CompanyName.MyMeetings.Modules.Meetings.ArchTests.csproj\", \"{475AF987-1458-447E-8504-4F1040B56A2C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.ArchTests\", \"Modules\\Payments\\Tests\\ArchTests\\CompanyName.MyMeetings.Modules.Payments.ArchTests.csproj\", \"{1885C71E-1624-4673-B0BC-BF4035CFFE72}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.UserAccess.ArchTests\", \"Modules\\UserAccess\\Tests\\ArchTests\\CompanyName.MyMeetings.Modules.UserAccess.ArchTests.csproj\", \"{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests\", \"Modules\\UserAccess\\Tests\\IntegrationTests\\CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.csproj\", \"{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Payments.IntegrationTests\", \"Modules\\Payments\\Tests\\IntegrationTests\\CompanyName.MyMeetings.Modules.Payments.IntegrationTests.csproj\", \"{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Administration.IntegrationTests\", \"Modules\\Administration\\Tests\\IntegrationTests\\CompanyName.MyMeetings.Modules.Administration.IntegrationTests.csproj\", \"{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.IntegrationTests\", \"Tests\\IntegrationTests\\CompanyName.MyMeetings.IntegrationTests.csproj\", \"{586DB9FA-CBBF-4867-A57D-E2359925D09A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Modules.Meetings.IntegrationTests\", \"Modules\\Meetings\\Tests\\IntegrationTests\\CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.csproj\", \"{785E93F2-3415-4215-BD85-1CED429CF260}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{B1D398A1-7005-4792-8D7F-CD9E5F3C29B7}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.BuildingBlocks.Application.UnitTests\", \"BuildingBlocks\\Tests\\Application.UnitTests\\CompanyName.MyMeetings.BuildingBlocks.Application.UnitTests.csproj\", \"{32915CF6-62D9-4121-8650-6279D5154B4B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.BuildingBlocks.IntegrationTests\", \"BuildingBlocks\\Tests\\IntegrationTests\\CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.csproj\", \"{8CCB9013-92CE-4A26-B649-0997F5444161}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"CI\", \"CI\", \"{63502820-A1A1-442D-A30E-4F43E722D1B0}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\.github\\workflows\\buildPipeline.yml = ..\\.github\\workflows\\buildPipeline.yml\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"_Solution Items\", \"_Solution Items\", \"{8172C84D-A01E-4B56-8A41-498E5DB9E395}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.editorconfig = .editorconfig\n\t\tDirectory.Build.props = Directory.Build.props\n\t\tDirectory.Build.targets = Directory.Build.targets\n\t\tDirectory.Packages.props = Directory.Packages.props\n\t\tglobal.json = global.json\n\t\t..\\README.md = ..\\README.md\n\t\tstylecop.json = stylecop.json\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DatabaseMigrator\", \"Database\\DatabaseMigrator\\DatabaseMigrator.csproj\", \"{9189FC86-116F-49D4-900E-DEC434136C6D}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"_build\", \"..\\build\\_build.csproj\", \"{866A329C-E942-46D1-AF37-BB617F7F4AC2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.Database.Build\", \"Database\\CompanyName.MyMeetings.Database.Build\\CompanyName.MyMeetings.Database.Build.csproj\", \"{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"RequestExamples\", \"RequestExamples\", \"{00B904C6-D29A-4F26-B7AD-116C701DB73F}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tAPI\\RequestExamples\\Authentication.http = API\\RequestExamples\\Authentication.http\n\t\tAPI\\RequestExamples\\http-client.env.json = API\\RequestExamples\\http-client.env.json\n\t\tAPI\\RequestExamples\\Users.http = API\\RequestExamples\\Users.http\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CompanyName.MyMeetings.SUT\", \"Tests\\SUT\\CompanyName.MyMeetings.SUT.csproj\", \"{1853847F-9988-43A1-B3E1-DDBE4B2F3365}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Registrations\", \"Registrations\", \"{8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.Application\", \"Modules\\Registrations\\Application\\CompanyName.MyMeetings.Modules.Registrations.Application.csproj\", \"{3D5E4893-E48A-4553-B036-724A8F809656}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.Domain\", \"Modules\\Registrations\\Domain\\CompanyName.MyMeetings.Modules.Registrations.Domain.csproj\", \"{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.Infrastructure\", \"Modules\\Registrations\\Infrastructure\\CompanyName.MyMeetings.Modules.Registrations.Infrastructure.csproj\", \"{5F24D649-5684-458E-8C67-CCEC85E271A0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{646E463D-F0E2-4BA4-9B5E-434ABE26EC07}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.ArchTests\", \"Modules\\Registrations\\Tests\\ArchTests\\CompanyName.MyMeetings.Modules.Registrations.ArchTests.csproj\", \"{96639493-5D2D-4F61-B399-600673D6912D}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests\", \"Modules\\Registrations\\Tests\\IntegrationTests\\CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.csproj\", \"{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests\", \"Modules\\Registrations\\Tests\\UnitTests\\CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.csproj\", \"{0535D1F2-FA8B-4093-9987-7533F8D07605}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents\", \"Modules\\Registrations\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents.csproj\", \"{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tProduction|Any CPU = Production|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168}.Debug|Any CPU.Deploy.0 = Debug|Any CPU\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168}.Production|Any CPU.Deploy.0 = Production|Any CPU\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{866A329C-E942-46D1-AF37-BB617F7F4AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{866A329C-E942-46D1-AF37-BB617F7F4AC2}.Production|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{866A329C-E942-46D1-AF37-BB617F7F4AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Production|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Production|Any CPU.Build.0 = Debug|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Production|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Production|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{96639493-5D2D-4F61-B399-600673D6912D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Production|Any CPU.ActiveCfg = Production|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Production|Any CPU.Build.0 = Production|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{49D08B64-AC8E-4607-820F-8A0B989CFD33} = {BC9DDFD1-FB81-4996-812A-68BEBCA33A97}\n\t\t{9CD43CAC-C149-41E1-9654-157D578143B7} = {BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\n\t\t{AE6D0618-60E1-40B2-A46F-664A19C9503C} = {BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\n\t\t{F34C6504-590B-480A-A239-F230CDFF8CED} = {AE6D0618-60E1-40B2-A46F-664A19C9503C}\n\t\t{5C2C1630-8A7A-451F-81A8-8547C939F5FD} = {9CD43CAC-C149-41E1-9654-157D578143B7}\n\t\t{F71CFDA8-0770-4761-896A-FB0098113F87} = {9CD43CAC-C149-41E1-9654-157D578143B7}\n\t\t{93F3D023-37BD-4C5C-9442-DE2631CD4954} = {9CD43CAC-C149-41E1-9654-157D578143B7}\n\t\t{CA91F71E-8067-4E98-A4D4-E17F5880DE39} = {E91D4BE3-61FE-441C-A227-29850D414216}\n\t\t{2EEAFD26-A0A9-4F91-BEB7-B0F8ED85ACBA} = {E91D4BE3-61FE-441C-A227-29850D414216}\n\t\t{5F398170-87FD-4368-9930-FAAAD2D9FDCC} = {BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\n\t\t{590517F8-686B-460A-97B3-0A09A8BA443C} = {5F398170-87FD-4368-9930-FAAAD2D9FDCC}\n\t\t{6F039231-8745-4171-B5CA-8688E4683CFC} = {5F398170-87FD-4368-9930-FAAAD2D9FDCC}\n\t\t{CD765A37-EB16-4E35-AA03-6E706D70E8A0} = {5F398170-87FD-4368-9930-FAAAD2D9FDCC}\n\t\t{3ED61776-83A0-426C-9B3A-3AB755DA01EF} = {9CD43CAC-C149-41E1-9654-157D578143B7}\n\t\t{396817BD-94A7-4559-A7F1-2FAB8009BCF8} = {5F398170-87FD-4368-9930-FAAAD2D9FDCC}\n\t\t{55E1C531-2B9B-49B1-BDFE-9DE322E7FE00} = {AE6D0618-60E1-40B2-A46F-664A19C9503C}\n\t\t{F364B0C4-1882-46A1-9B08-22587BEF05A2} = {AE6D0618-60E1-40B2-A46F-664A19C9503C}\n\t\t{0C31EA31-6A10-47D0-82E5-6D224E1CE532} = {AE6D0618-60E1-40B2-A46F-664A19C9503C}\n\t\t{13E4D721-2E96-497E-9657-503D09468F9F} = {BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\n\t\t{6E013582-9E44-4D7E-8CFE-5F6FB6757B03} = {13E4D721-2E96-497E-9657-503D09468F9F}\n\t\t{C457929B-91BE-48CC-A714-217D9CABD3CC} = {13E4D721-2E96-497E-9657-503D09468F9F}\n\t\t{1F4EAF3D-F5B8-473B-871F-606191D4AB9F} = {13E4D721-2E96-497E-9657-503D09468F9F}\n\t\t{8DF88C85-594D-45D7-B12E-6B641D497853} = {13E4D721-2E96-497E-9657-503D09468F9F}\n\t\t{9EAA687B-951E-4D89-8857-99151FF1BCD7} = {E91D4BE3-61FE-441C-A227-29850D414216}\n\t\t{43DBBB02-CA43-42AD-BE21-04AC867BA168} = {C733D087-7051-4E35-BCDB-081252A108E5}\n\t\t{0FF699EF-8156-43CB-8D18-8EA28F30E9EE} = {AE6D0618-60E1-40B2-A46F-664A19C9503C}\n\t\t{0BC12804-A858-427B-88E2-F9CDE9E97986} = {0FF699EF-8156-43CB-8D18-8EA28F30E9EE}\n\t\t{53E4F002-E708-45F7-8444-19EB8977B5C9} = {13E4D721-2E96-497E-9657-503D09468F9F}\n\t\t{602768DD-F063-469D-9CD3-95CB02F6E441} = {53E4F002-E708-45F7-8444-19EB8977B5C9}\n\t\t{F544D6DA-740A-4313-9542-D989666EA9DE} = {5F398170-87FD-4368-9930-FAAAD2D9FDCC}\n\t\t{AC73F391-BC1F-4B7F-AF49-BD87223E2BB0} = {F544D6DA-740A-4313-9542-D989666EA9DE}\n\t\t{237A249C-B589-49B8-9B84-CA504DE5D137} = {9CD43CAC-C149-41E1-9654-157D578143B7}\n\t\t{E13970C6-87EE-40B1-854A-3053C95BC4C9} = {237A249C-B589-49B8-9B84-CA504DE5D137}\n\t\t{88081DDB-2FBD-4F7D-830F-24F5F6B78294} = {8B08A9EE-CE27-4CC3-ACB3-3BD9628E5479}\n\t\t{F2B164AC-99AC-4906-A133-85D6BB8432B4} = {F544D6DA-740A-4313-9542-D989666EA9DE}\n\t\t{475AF987-1458-447E-8504-4F1040B56A2C} = {237A249C-B589-49B8-9B84-CA504DE5D137}\n\t\t{1885C71E-1624-4673-B0BC-BF4035CFFE72} = {53E4F002-E708-45F7-8444-19EB8977B5C9}\n\t\t{F8EE61DA-0E8B-4074-A0AF-433244EC1FB8} = {0FF699EF-8156-43CB-8D18-8EA28F30E9EE}\n\t\t{396A6C3F-74BA-4D85-8BF3-1182F9DE9D95} = {0FF699EF-8156-43CB-8D18-8EA28F30E9EE}\n\t\t{B448FDC3-5F85-47EE-9F4A-2654E8CC67E1} = {53E4F002-E708-45F7-8444-19EB8977B5C9}\n\t\t{3D7FDF4A-6B8B-49CA-8E28-5B292DC0954F} = {F544D6DA-740A-4313-9542-D989666EA9DE}\n\t\t{586DB9FA-CBBF-4867-A57D-E2359925D09A} = {8B08A9EE-CE27-4CC3-ACB3-3BD9628E5479}\n\t\t{785E93F2-3415-4215-BD85-1CED429CF260} = {237A249C-B589-49B8-9B84-CA504DE5D137}\n\t\t{B1D398A1-7005-4792-8D7F-CD9E5F3C29B7} = {E91D4BE3-61FE-441C-A227-29850D414216}\n\t\t{32915CF6-62D9-4121-8650-6279D5154B4B} = {B1D398A1-7005-4792-8D7F-CD9E5F3C29B7}\n\t\t{8CCB9013-92CE-4A26-B649-0997F5444161} = {B1D398A1-7005-4792-8D7F-CD9E5F3C29B7}\n\t\t{9189FC86-116F-49D4-900E-DEC434136C6D} = {C733D087-7051-4E35-BCDB-081252A108E5}\n\t\t{165E76B9-DB0C-49B7-B3DC-52DFBEA55A79} = {C733D087-7051-4E35-BCDB-081252A108E5}\n\t\t{00B904C6-D29A-4F26-B7AD-116C701DB73F} = {BC9DDFD1-FB81-4996-812A-68BEBCA33A97}\n\t\t{1853847F-9988-43A1-B3E1-DDBE4B2F3365} = {8B08A9EE-CE27-4CC3-ACB3-3BD9628E5479}\n\t\t{8F0598A5-2F0C-4FA6-82F6-938F1830ADB7} = {BCE1EE3C-ADB1-48CC-9FD1-C7324D886964}\n\t\t{3D5E4893-E48A-4553-B036-724A8F809656} = {8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\n\t\t{98CE491C-8A52-4FC9-87BD-36FE63CB37E6} = {8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\n\t\t{5F24D649-5684-458E-8C67-CCEC85E271A0} = {8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\n\t\t{646E463D-F0E2-4BA4-9B5E-434ABE26EC07} = {8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\n\t\t{96639493-5D2D-4F61-B399-600673D6912D} = {646E463D-F0E2-4BA4-9B5E-434ABE26EC07}\n\t\t{9AB969B5-4215-4ACF-8D48-EC0A6F35BC46} = {646E463D-F0E2-4BA4-9B5E-434ABE26EC07}\n\t\t{0535D1F2-FA8B-4093-9987-7533F8D07605} = {646E463D-F0E2-4BA4-9B5E-434ABE26EC07}\n\t\t{2E71D2B2-516D-4B0D-8DE6-B9F3105B9C95} = {8F0598A5-2F0C-4FA6-82F6-938F1830ADB7}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {6B94C21A-AA6D-4D82-963E-C69C0353B938}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Database/.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"
  },
  {
    "path": "src/Database/ClearDatabase.sql",
    "content": "﻿DELETE FROM [administration].[MeetingGroupProposals]\nGO\n\nDELETE FROM [administration].[OutboxMessages]\nGO\n\nDELETE FROM [administration].[InboxMessages]\nGO\n\nDELETE FROM [administration].[InternalCommands]\nGO\n\nDELETE FROM [meetings].[InboxMessages]\nGO\n\nDELETE FROM [meetings].[OutboxMessages]\nGO\n\nDELETE FROM [meetings].[InternalCommands]\nGO\n\nDELETE FROM [meetings].[MeetingGroupProposals]\nGO\n\nDELETE FROM [meetings].[MeetingGroupMembers]\nGO\n\nDELETE FROM [meetings].[MeetingAttendees]\nGO\n\nDELETE FROM [meetings].[MeetingGroups]\nGO\n\nDROP TABLE [administration].[MeetingGroupProposals]\nGO\n\nDROP TABLE [administration].[OutboxMessages]\nGO\n\nDROP TABLE [administration].[InboxMessages]\nGO\n\nDROP TABLE [administration].[InternalCommands]\nGO\n\nDROP TABLE [meetings].[InboxMessages]\nGO\n\nDROP TABLE [meetings].[OutboxMessages]\nGO\n\nDROP TABLE [meetings].[InternalCommands]\nGO\n\nDROP TABLE [meetings].[MeetingGroupProposals]\nGO\n\nDROP TABLE [meetings].[MeetingGroupMembers]\nGO\n\nDROP TABLE [meetings].[MeetingAttendees]\nGO\n\nDROP TABLE [meetings].[MeetingGroups]\nGO\n\nDROP TABLE [meetings].[Meetings]\nGO\n\nDROP VIEW [meetings].[v_MeetingGroups]\nGO\n\n\nDROP TABLE [administration].[Members]\nGO\n\nDROP VIEW [administration].[v_MeetingGroupProposals]\nGO\n\nDROP VIEW [administration].[v_Members]\nGO\n\nDROP SCHEMA [administration]\nGO\n\nDROP TABLE [meetings].[MeetingNotAttendees]\nGO\n\nDROP TABLE [meetings].[MeetingWaitlistMembers]\nGO\n\nDROP TABLE [meetings].[Members]\nGO\n\nDROP VIEW [meetings].[v_Meetings]\nGO\n\nDROP VIEW [meetings].[v_Members]\nGO\n\nDROP VIEW [meetings].[v_MeetingGroupProposals]\nGO\n\n\n\nDROP TABLE payments.InboxMessages\n\nDROP TABLE payments.InternalCommands\nGO\n\nDROP TABLE payments.OutboxMessages\nGO\n\nDROP TABLE payments.Payers\nGO\n\nDROP TABLE users.InboxMessages\nGO\n\nDROP TABLE users.InternalCommands\nGO\n\nDROP TABLE users.OutboxMessages\nGO\n\nDROP TABLE users.[RolesToPermissions]\nGO\n\nDROP TABLE users.[Permissions]\nGO\n\nDROP TABLE users.[Users]\nGO\n\nDROP TABLE users.[UserRoles]\nGO\n\nDROP TABLE users.[UserRegistrations]\nGO\n\nDROP VIEW users.[v_UserPermissions]\nGO\n\nDROP VIEW users.[v_UserRegistrations]\nGO\n\nDROP VIEW users.[v_UserRoles]\nGO\n\nDROP VIEW users.[v_Users]\nGO\n\nDROP SCHEMA [users]\nGO\n\nDROP TABLE payments.[Messages]\nGO\n\n\nDROP TABLE payments.Streams\nGO\n\n\nDROP TYPE payments.NewStreamMessages\nGO\n\nDROP TABLE payments.SubscriptionDetails\nGO\n\nDROP TABLE payments.SubscriptionCheckpoints\nGO\n\nDROP TABLE payments.PriceListItems\nGO\n\nDROP TABLE payments.SubscriptionPayments\nGO\n\nDROP TABLE [meetings].[MemberSubscriptions]\nGO\n\nDROP SCHEMA [payments]\nGO\n\nDROP VIEW meetings.v_MeetingGroupMembers\n\nDROP SCHEMA [meetings]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/CompanyName.MyMeetings.Database.sqlproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" ToolsVersion=\"4.0\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <Name>CompanyName.MyMeetings.Database</Name>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectVersion>4.1</ProjectVersion>\n    <ProjectGuid>{43dbbb02-ca43-42ad-be21-04ac867ba168}</ProjectGuid>\n    <DSP>Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider</DSP>\n    <OutputType>Database</OutputType>\n    <RootPath>\n    </RootPath>\n    <RootNamespace>CompanyName.MyMeetings.Database</RootNamespace>\n    <AssemblyName>CompanyName.MyMeetings.Database</AssemblyName>\n    <ModelCollation>1033, CI</ModelCollation>\n    <DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>\n    <DeployToDatabase>True</DeployToDatabase>\n    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>\n    <TargetLanguage>CS</TargetLanguage>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <SqlServerVerification>False</SqlServerVerification>\n    <IncludeCompositeObjects>True</IncludeCompositeObjects>\n    <TargetDatabaseSet>True</TargetDatabaseSet>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>\n    <TreatWarningsAsErrors>False</TreatWarningsAsErrors>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <DefineDebug>false</DefineDebug>\n    <DefineTrace>true</DefineTrace>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>\n    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <DefineDebug>true</DefineDebug>\n    <DefineTrace>true</DefineTrace>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <RunSqlCodeAnalysis>True</RunSqlCodeAnalysis>\n  </PropertyGroup>\n  <PropertyGroup>\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">11.0</VisualStudioVersion>\n    <!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->\n    <SSDTExists Condition=\"Exists('$(MSBuildExtensionsPath)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\SSDT\\Microsoft.Data.Tools.Schema.SqlTasks.targets')\">True</SSDTExists>\n    <VisualStudioVersion Condition=\"'$(SSDTExists)' == ''\">11.0</VisualStudioVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Production|AnyCPU' \">\n    <OutputPath>bin\\Release\\</OutputPath>\n    <BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>\n    <TreatWarningsAsErrors>False</TreatWarningsAsErrors>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <DefineDebug>false</DefineDebug>\n    <DefineTrace>true</DefineTrace>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <Import Condition=\"'$(SQLDBExtensionsRefPath)' != ''\" Project=\"$(SQLDBExtensionsRefPath)\\Microsoft.Data.Tools.Schema.SqlTasks.targets\" />\n  <Import Condition=\"'$(SQLDBExtensionsRefPath)' == ''\" Project=\"$(MSBuildExtensionsPath)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\SSDT\\Microsoft.Data.Tools.Schema.SqlTasks.targets\" />\n  <ItemGroup>\n    <Folder Include=\"Properties\" />\n    <Folder Include=\"Scripts\" />\n    <Folder Include=\"Scripts\\Migrations\" />\n    <Folder Include=\"Scripts\\Seeds\" />\n    <Folder Include=\"Scripts\\Migrations\\1_0_0_0\\\" />\n    <Folder Include=\"Structure\\administration\\\" />\n    <Folder Include=\"Structure\\administration\\Tables\\\" />\n    <Folder Include=\"Structure\\administration\\Views\\\" />\n    <Folder Include=\"Structure\\app\\\" />\n    <Folder Include=\"Structure\\app\\Tables\\\" />\n    <Folder Include=\"Structure\\meetings\\\" />\n    <Folder Include=\"Structure\\meetings\\Tables\\\" />\n    <Folder Include=\"Structure\\meetings\\Views\\\" />\n    <Folder Include=\"Structure\\payments\\\" />\n    <Folder Include=\"Structure\\payments\\Tables\\\" />\n    <Folder Include=\"Structure\\payments\\Types\\\" />\n    <Folder Include=\"Structure\\Security\\\" />\n    <Folder Include=\"Structure\\users\\\" />\n    <Folder Include=\"Structure\\users\\Tables\\\" />\n    <Folder Include=\"Structure\\users\\Views\\\" />\n    <Folder Include=\"Structure\\registrations\\\" />\n    <Folder Include=\"Structure\\registrations\\Tables\\\" />\n    <Folder Include=\"Structure\\registrations\\Views\\\" />\n    <Folder Include=\"Structure\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Build Include=\"Structure\\administration\\Tables\\InboxMessages.sql\" />\n    <Build Include=\"Structure\\administration\\Tables\\InternalCommands.sql\" />\n    <Build Include=\"Structure\\administration\\Tables\\MeetingGroupProposals.sql\" />\n    <Build Include=\"Structure\\administration\\Tables\\Members.sql\" />\n    <Build Include=\"Structure\\administration\\Tables\\OutboxMessages.sql\" />\n    <Build Include=\"Structure\\administration\\Views\\v_MeetingGroupProposals.sql\" />\n    <Build Include=\"Structure\\administration\\Views\\v_Members.sql\" />\n    <Build Include=\"Structure\\app\\Tables\\Emails.sql\" />\n    <Build Include=\"Structure\\app\\Tables\\MigrationsJournal.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\Countries.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\InboxMessages.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\InternalCommands.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingAttendees.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingCommentingConfigurations.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingComments.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingGroupMembers.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingGroupProposals.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingGroups.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingMemberCommentLikes.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingNotAttendees.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\Meetings.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MeetingWaitlistMembers.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\Members.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\MemberSubscriptions.sql\" />\n    <Build Include=\"Structure\\meetings\\Tables\\OutboxMessages.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_Countries.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingAttendees.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingComments.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingDetails.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingGroupMembers.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingGroupProposals.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MeetingGroups.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_Meetings.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MemberMeetingGroups.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_MemberMeetings.sql\" />\n    <Build Include=\"Structure\\meetings\\Views\\v_Members.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\InboxMessages.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\InternalCommands.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\MeetingFees.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\Messages.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\OutboxMessages.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\Payers.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\PriceListItems.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\Streams.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\SubscriptionCheckpoints.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\SubscriptionDetails.sql\" />\n    <Build Include=\"Structure\\payments\\Tables\\SubscriptionPayments.sql\" />\n    <Build Include=\"Structure\\payments\\Types\\NewStreamMessages.sql\" />\n    <Build Include=\"Structure\\registrations\\Tables\\UserRegistrations.sql\" />\n    <Build Include=\"Structure\\registrations\\Tables\\OutboxMessages.sql\" />\n    <Build Include=\"Structure\\registrations\\Tables\\InboxMessages.sql\" />\n    <Build Include=\"Structure\\registrations\\Tables\\InternalCommands.sql\" />\n    <Build Include=\"Structure\\registrations\\Views\\v_UserRegistrations.sql\" />\n    <Build Include=\"Structure\\Security\\Schemas.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\InboxMessages.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\InternalCommands.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\OutboxMessages.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\Permissions.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\RolesToPermissions.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\UserRoles.sql\" />\n    <Build Include=\"Structure\\users\\Tables\\Users.sql\" />\n    <Build Include=\"Structure\\users\\Views\\v_UserPermissions.sql\" />\n    <Build Include=\"Structure\\users\\Views\\v_UserRoles.sql\" />\n    <Build Include=\"Structure\\users\\Views\\v_Users.sql\" />\n    <None Include=\"Scripts\\CreateStructure.sql\" />\n    <None Include=\"Scripts\\SeedDatabase.sql\" />\n    <None Include=\"Scripts\\CreateDatabase_Linux.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0001_initial_structure.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0002_change_meeting_comments_edit_date_type_and_add_meeting_comments_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0004_add_meeting_commenting_configurations_table.sql\" />\n    <None Include=\"Scripts\\CreateDatabase_Windows.sql\" />\n    <None Include=\"Scripts\\Seeds\\0001_SeedCountries.sql\">\n      <CopyToOutputDirectory>DoNotCopy</CopyToOutputDirectory>\n    </None>\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0003_add_meetings_countries_table.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0005_add_payer_id_to_subcription_details_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0006_add_member_meeting_groups_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0007_add_meeting_attendees_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0008_add_meeting_details_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0009_add_mock_emails_table.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0010_add_member_meetings_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0011_add_likes_count_to_meeting_comments_table.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0012_add_likes_count_to_meeting_comments_view.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0013_add_meeting_member_comment_likes_table.sql\" />\n    <None Include=\"Scripts\\Migrations\\1_0_0_0\\0014_add_missing_tables_for_registrations.sql\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Scripts\\ClearDatabase.sql\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/ClearDatabase.sql",
    "content": "﻿DELETE FROM [administration].[InboxMessages]\n\nDELETE FROM [administration].[InternalCommands]\n\nDELETE FROM [administration].[OutboxMessages]\n\nDELETE FROM [administration].[MeetingGroupProposals]\n\nDELETE FROM [administration].[Members]\n\nDELETE FROM [meetings].[InboxMessages]\n\nDELETE FROM [meetings].[InternalCommands]\n\nDELETE FROM [meetings].[OutboxMessages]\n\nDELETE FROM [meetings].[MeetingAttendees]\n\nDELETE FROM [meetings].[MeetingGroupMembers]\n\nDELETE FROM [meetings].[MeetingGroupProposals]\n\nDELETE FROM [meetings].[MeetingGroups]\n\nDELETE FROM [meetings].[MeetingNotAttendees]\n\nDELETE FROM [meetings].[Meetings]\n\nDELETE FROM [meetings].[MeetingWaitlistMembers]\n\nDELETE FROM [meetings].[MeetingMemberCommentLikes]\n\nDELETE FROM [meetings].[Members]\n\nDELETE FROM [meetings].[MeetingComments]\n\nDELETE FROM [payments].[InboxMessages]\n\nDELETE FROM [payments].[InternalCommands]\n\nDELETE FROM [payments].[OutboxMessages]\n\nDELETE FROM payments.[Messages]\n\nDBCC CHECKIDENT ('payments.Messages', RESEED, 0);\n\nDELETE FROM payments.Streams\n\nDBCC CHECKIDENT ('payments.Streams', RESEED, 0);\n\nDELETE FROM payments.SubscriptionDetails\n\nDELETE FROM [payments].[SubscriptionCheckpoints]\n\nDELETE FROM [payments].PriceListItems\n\nDELETE FROM [payments].SubscriptionPayments\n\nDELETE FROM [payments].MeetingFees\n\nDELETE FROM [payments].[Payers]\n\nDELETE FROM [users].[InboxMessages]\n\nDELETE FROM [users].[InternalCommands]\n\nDELETE FROM [users].[OutboxMessages]\n\nDELETE FROM [users].[Users]\n\nDELETE FROM [users].[RolesToPermissions]\n\nDELETE FROM [users].[UserRoles]\n\nDELETE FROM [users].[Permissions]\n\nDELETE FROM [registrations].[UserRegistrations]"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase.sql",
    "content": "﻿CREATE DATABASE [MyMeetings]\n CONTAINMENT = NONE\n ON  PRIMARY \n( NAME = N'MyMeetings', FILENAME = N'/var/opt/mssql/data/MyMeetings.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )\n LOG ON \n( NAME = N'MyMeetings_log', FILENAME = N'/var/opt/mssql/data/MyMeetings_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )\nGO\n\nCREATE SCHEMA app AUTHORIZATION dbo\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Linux.sql",
    "content": "﻿CREATE DATABASE [MyMeetings] \nCONTAINMENT = NONE \nGO\n\nUSE [MyMeetings]\nGO\n\nCREATE SCHEMA app AUTHORIZATION dbo\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Windows.sql",
    "content": "﻿CREATE DATABASE [MyMeetings]\n CONTAINMENT = NONE\n GO\n\nUSE [MyMeetings]\nGO\n\nCREATE SCHEMA app AUTHORIZATION dbo\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/CreateStructure.sql",
    "content": "﻿\nPRINT N'Creating [administration]...';\n\n\nGO\nCREATE SCHEMA [administration]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [meetings]...';\n\n\nGO\nCREATE SCHEMA [meetings]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [payments]...';\n\n\nGO\nCREATE SCHEMA [payments]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [users]...';\n\n\nGO\nCREATE SCHEMA [users]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [registrations]...';\n\n\nGO\nCREATE SCHEMA [registrations]\n    AUTHORIZATION [dbo];\n\n\nGO\n\nPRINT N'Creating [payments].[NewStreamMessages]...';\n\n\nGO\nCREATE TYPE [payments].[NewStreamMessages] AS TABLE (\n    [StreamVersion] INT              IDENTITY (0, 1) NOT NULL,\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [Created]       DATETIME         DEFAULT (GETUTCDATE()) NOT NULL,\n    [Type]          NVARCHAR (128)   NOT NULL,\n    [JsonData]      NVARCHAR (MAX)   NULL,\n    [JsonMetadata]  NVARCHAR (MAX)   NULL);\n\n\nGO\nPRINT N'Creating [administration].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [administration].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_administration_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[Members]...';\n\n\nGO\nCREATE TABLE [administration].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_administration_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [administration].[MeetingGroupProposals] (\n    [Id]                   UNIQUEIDENTIFIER NOT NULL,\n    [Name]                 NVARCHAR (255)   NOT NULL,\n    [Description]          VARCHAR (200)    NULL,\n    [LocationCity]         NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode]  NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]       UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]         DATETIME         NOT NULL,\n    [StatusCode]           NVARCHAR (50)    NOT NULL,\n    [DecisionDate]         DATETIME         NULL,\n    [DecisionUserId]       UNIQUEIDENTIFIER NULL,\n    [DecisionCode]         NVARCHAR (50)    NULL,\n    [DecisionRejectReason] NVARCHAR (250)   NULL,\n    CONSTRAINT [PK_administration_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingWaitlistMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingWaitlistMembers] (\n    [MeetingId]            UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]             UNIQUEIDENTIFIER NOT NULL,\n    [SignUpDate]           DATETIME2 (7)    NOT NULL,\n    [IsSignedOff]          BIT              NOT NULL,\n    [SignOffDate]          DATETIME2 (7)    NULL,\n    [IsMovedToAttendees]   BIT              NOT NULL,\n    [MovedToAttendeesDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingWaitlistMembers_MeetingId_MemberId_SignUpDate] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [SignUpDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingNotAttendees]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingNotAttendees] (\n    [MeetingId]          UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]           UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate]       DATETIME2 (7)    NOT NULL,\n    [DecisionChanged]    BIT              NOT NULL,\n    [DecisionChangeDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingNotAttendees_Id] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [DecisionDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[Meetings]...';\n\n\nGO\nCREATE TABLE [meetings].[Meetings] (\n    [Id]                 UNIQUEIDENTIFIER NOT NULL,\n    [MeetingGroupId]     UNIQUEIDENTIFIER NOT NULL,\n    [CreatorId]          UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]         DATETIME2 (7)    NOT NULL,\n    [Title]              NVARCHAR (200)   NOT NULL,\n    [Description]        NVARCHAR (4000)  NOT NULL,\n    [TermStartDate]      DATETIME         NOT NULL,\n    [TermEndDate]        DATETIME         NOT NULL,\n    [LocationName]       NVARCHAR (200)   NOT NULL,\n    [LocationAddress]    NVARCHAR (200)   NOT NULL,\n    [LocationPostalCode] NVARCHAR (200)   NULL,\n    [LocationCity]       NVARCHAR (50)    NOT NULL,\n    [AttendeesLimit]     INT              NULL,\n    [GuestsLimit]        INT              NOT NULL,\n    [RSVPTermStartDate]  DATETIME         NULL,\n    [RSVPTermEndDate]    DATETIME         NULL,\n    [EventFeeValue]      DECIMAL (5)      NULL,\n    [EventFeeCurrency]   VARCHAR (3)      NULL,\n    [ChangeDate]         DATETIME2 (7)    NULL,\n    [ChangeMemberId]     UNIQUEIDENTIFIER NULL,\n    [CancelDate]         DATETIME         NULL,\n    [CancelMemberId]     UNIQUEIDENTIFIER NULL,\n    [IsCanceled]         BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_Meetings_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupMembers] (\n    [MeetingGroupId] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]       UNIQUEIDENTIFIER NOT NULL,\n    [JoinedDate]     DATETIME2 (7)    NOT NULL,\n    [RoleCode]       VARCHAR (50)     NOT NULL,\n    [IsActive]       BIT              NOT NULL,\n    [LeaveDate]      DATETIME         NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupMembers_MeetingGroupId_MemberId_JoinedDate] PRIMARY KEY CLUSTERED ([MeetingGroupId] ASC, [MemberId] ASC, [JoinedDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroups]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroups] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [CreatorId]           UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]          DATETIME         NOT NULL,\n    [PaymentDateTo]       DATE             NULL,\n    CONSTRAINT [PK_meetings_MeetingGroups_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[Members]...';\n\n\nGO\nCREATE TABLE [meetings].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_meetings_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupProposals] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]      UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]        DATETIME         NOT NULL,\n    [StatusCode]          NVARCHAR (50)    NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [meetings].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_meetings_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MemberSubscriptions]...';\n\n\nGO\nCREATE TABLE [meetings].[MemberSubscriptions] (\n    [Id]             UNIQUEIDENTIFIER NOT NULL,\n    [ExpirationDate] DATETIME         NOT NULL,\n    CONSTRAINT [PK_meetings_MemberSubscriptions_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingAttendees]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingAttendees] (\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [AttendeeId]            UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate]          DATETIME2 (7)    NOT NULL,\n    [RoleCode]              VARCHAR (50)     NULL,\n    [GuestsNumber]          INT              NULL,\n    [DecisionChanged]       BIT              NOT NULL,\n    [DecisionChangeDate]    DATETIME2 (7)    NULL,\n    [IsRemoved]             BIT              NOT NULL,\n    [RemovingMemberId]      UNIQUEIDENTIFIER NULL,\n    [RemovingReason]        NVARCHAR (500)   NULL,\n    [RemovedDate]           DATETIME2 (7)    NULL,\n    [BecameNotAttendeeDate] DATETIME2 (7)    NULL,\n    [FeeValue]              DECIMAL (5)      NULL,\n    [FeeCurrency]           VARCHAR (3)      NULL,\n    [IsFeePaid]             BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingAttendees_Id] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [AttendeeId] ASC, [DecisionDate] ASC)\n);\n\nGO\nPRINT N'Creating [meetings].[MeetingComments]...';\n\n\nGO\nCREATE TABLE meetings.MeetingComments\n(\n    [Id]                    UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [AuthorId]              UNIQUEIDENTIFIER NOT NULL,\n    [InReplyToCommentId]    UNIQUEIDENTIFIER NULL,\n    [Comment]               VARCHAR(300)     NULL,\n    [IsRemoved]             BIT              NOT NULL,\n    [RemovedByReason]       VARCHAR(300)     NULL,\n    [CreateDate]            DATETIME         NOT NULL,\n    [EditDate]              DATETIME         NULL,\n    [LikesCount]            INT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingComments_Id] PRIMARY KEY ([Id] ASC)\n)\n\nGO\nPRINT N'Creating [meetings].[MeetingMemberCommentLikes]...';\n\n\nCREATE TABLE [meetings].[MeetingMemberCommentLikes]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]  UNIQUEIDENTIFIER NOT NULL,\n    [MeetingCommentId] UNIQUEIDENTIFIER NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingMemberCommentLikes_Id] PRIMARY KEY ([Id] ASC),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_Members] FOREIGN KEY ([MemberId]) REFERENCES meetings.Members ([Id]),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_MeetingComments] FOREIGN KEY ([MeetingCommentId]) REFERENCES meetings.MeetingComments ([Id])\n)\n\nGO\nPRINT N'Creating [payments].[Payers]...';\n\n\nGO\nCREATE TABLE [payments].[Payers] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_payments_Payers_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [payments].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_payments_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[Messages]...';\n\n\nGO\nCREATE TABLE [payments].[Messages] (\n    [StreamIdInternal] INT              NOT NULL,\n    [StreamVersion]    INT              NOT NULL,\n    [Position]         BIGINT           IDENTITY (0, 1) NOT NULL,\n    [Id]               UNIQUEIDENTIFIER NOT NULL,\n    [Created]          DATETIME         NOT NULL,\n    [Type]             NVARCHAR (128)   NOT NULL,\n    [JsonData]         NVARCHAR (MAX)   NOT NULL,\n    [JsonMetadata]     NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_Events] PRIMARY KEY NONCLUSTERED ([Position] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[Messages].[IX_Messages_Position]...';\n\n\nGO\nCREATE UNIQUE NONCLUSTERED INDEX [IX_Messages_Position]\n    ON [payments].[Messages]([Position] ASC);\n\n\nGO\nPRINT N'Creating [payments].[Messages].[IX_Messages_StreamIdInternal_Id]...';\n\n\nGO\nCREATE UNIQUE NONCLUSTERED INDEX [IX_Messages_StreamIdInternal_Id]\n    ON [payments].[Messages]([StreamIdInternal] ASC, [Id] ASC);\n\n\nGO\nPRINT N'Creating [payments].[Messages].[IX_Messages_StreamIdInternal_Revision]...';\n\n\nGO\nCREATE UNIQUE NONCLUSTERED INDEX [IX_Messages_StreamIdInternal_Revision]\n    ON [payments].[Messages]([StreamIdInternal] ASC, [StreamVersion] ASC);\n\n\nGO\nPRINT N'Creating [payments].[Messages].[IX_Messages_StreamIdInternal_Created]...';\n\n\nGO\nCREATE NONCLUSTERED INDEX [IX_Messages_StreamIdInternal_Created]\n    ON [payments].[Messages]([StreamIdInternal] ASC, [Created] ASC);\n\n\nGO\nPRINT N'Creating [payments].[MeetingFees]...';\n\n\nGO\nCREATE TABLE [payments].[MeetingFees] (\n    [MeetingFeeId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId]      UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]    UNIQUEIDENTIFIER NOT NULL,\n    [FeeValue]     DECIMAL (18, 2)  NOT NULL,\n    [FeeCurrency]  VARCHAR (50)     NOT NULL,\n    [Status]       VARCHAR (50)     NOT NULL,\n    CONSTRAINT [PK_payments_MeetingFees_MeetingFeeId] PRIMARY KEY CLUSTERED ([MeetingFeeId] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[PriceListItems]...';\n\n\nGO\nCREATE TABLE [payments].[PriceListItems] (\n    [Id]                     UNIQUEIDENTIFIER NOT NULL,\n    [SubscriptionPeriodCode] VARCHAR (50)     NOT NULL,\n    [CategoryCode]           VARCHAR (50)     NOT NULL,\n    [CountryCode]            VARCHAR (50)     NOT NULL,\n    [MoneyValue]             DECIMAL (18, 2)  NOT NULL,\n    [MoneyCurrency]          VARCHAR (50)     NOT NULL,\n    [IsActive]               BIT              NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionPayments]...';\n\n\nGO\nCREATE TABLE [payments].[SubscriptionPayments] (\n    [PaymentId]      UNIQUEIDENTIFIER NOT NULL,\n    [PayerId]        UNIQUEIDENTIFIER NOT NULL,\n    [Type]           VARCHAR (50)     NOT NULL,\n    [Status]         VARCHAR (50)     NOT NULL,\n    [Period]         VARCHAR (50)     NOT NULL,\n    [Date]           DATETIME         NOT NULL,\n    [SubscriptionId] UNIQUEIDENTIFIER NULL,\n    [MoneyValue]     DECIMAL (18, 2)  NOT NULL,\n    [MoneyCurrency]  VARCHAR (50)     NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionCheckpoints]...';\n\n\nGO\nCREATE TABLE [payments].[SubscriptionCheckpoints] (\n    [Code]     VARCHAR (50) NOT NULL,\n    [Position] BIGINT       NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionDetails]...';\n\n\nGO\nCREATE TABLE [payments].[SubscriptionDetails] (\n    [Id]             UNIQUEIDENTIFIER NOT NULL,\n    [Period]         VARCHAR (50)     NOT NULL,\n    [Status]         VARCHAR (50)     NOT NULL,\n    [CountryCode]    VARCHAR (50)     NOT NULL,\n    [ExpirationDate] DATETIME         NOT NULL,\n    CONSTRAINT [PK_payments_SubscriptionDetails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[Streams]...';\n\n\nGO\nCREATE TABLE [payments].[Streams] (\n    [Id]         CHAR (42)       NOT NULL,\n    [IdOriginal] NVARCHAR (1000) NOT NULL,\n    [IdInternal] INT             IDENTITY (1, 1) NOT NULL,\n    [Version]    INT             NOT NULL,\n    [Position]   BIGINT          NOT NULL,\n    CONSTRAINT [PK_Streams] PRIMARY KEY CLUSTERED ([IdInternal] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[Streams].[IX_Streams_Id]...';\n\n\nGO\nCREATE UNIQUE NONCLUSTERED INDEX [IX_Streams_Id]\n    ON [payments].[Streams]([Id] ASC);\n\n\nGO\nPRINT N'Creating [users].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\nPRINT N'Creating [registrations].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [registrations].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_registrations_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n    );\n\n\nGO\nPRINT N'Creating [users].[UserRoles]...';\n\n\nGO\nCREATE TABLE [users].[UserRoles] (\n    [UserId]   UNIQUEIDENTIFIER NOT NULL,\n    [RoleCode] NVARCHAR (50)    NULL\n);\n\n\nGO\nPRINT N'Creating [registrations].[UserRegistrations]...';\n\n\nGO\nCREATE TABLE [registrations].[UserRegistrations] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [Login]         NVARCHAR (100)   NOT NULL,\n    [Email]         NVARCHAR (255)   NOT NULL,\n    [Password]      NVARCHAR (255)   NOT NULL,\n    [FirstName]     NVARCHAR (50)    NOT NULL,\n    [LastName]      NVARCHAR (50)    NOT NULL,\n    [Name]          NVARCHAR (255)   NOT NULL,\n    [StatusCode]    VARCHAR (50)     NOT NULL,\n    [RegisterDate]  DATETIME         NOT NULL,\n    [ConfirmedDate] DATETIME         NULL,\n    CONSTRAINT [PK_registrations_UserRegistrations_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Users]...';\n\n\nGO\nCREATE TABLE [users].[Users] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [Password]  NVARCHAR (255)   NOT NULL,\n    [IsActive]  BIT              NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_users_Users_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[RolesToPermissions]...';\n\n\nGO\nCREATE TABLE [users].[RolesToPermissions] (\n    [RoleCode]       VARCHAR (50) NOT NULL,\n    [PermissionCode] VARCHAR (50) NOT NULL,\n    CONSTRAINT [PK_RolesToPermissions_RoleCode_PermissionCode] PRIMARY KEY CLUSTERED ([RoleCode] ASC, [PermissionCode] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Permissions]...';\n\n\nGO\nCREATE TABLE [users].[Permissions] (\n    [Code]        VARCHAR (50)  NOT NULL,\n    [Name]        VARCHAR (100) NOT NULL,\n    [Description] VARCHAR (255) NULL,\n    CONSTRAINT [PK_users_Permissions_Code] PRIMARY KEY CLUSTERED ([Code] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [users].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_users_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\n\nPRINT N'Creating [registrations].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [registrations].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_registrations_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n    );\n\n\nGO\n\nPRINT N'Creating [users].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\nPRINT N'Creating [registrations].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [registrations].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n    );\n\n\nGO\nPRINT N'Creating [payments].[DF_payments_Streams_Version]...';\n\n\nGO\nALTER TABLE [payments].[Streams]\n    ADD CONSTRAINT [DF_payments_Streams_Version] DEFAULT (-1) FOR [Version];\n\n\nGO\nPRINT N'Creating [payments].[DF_payments_Streams_Position]...';\n\n\nGO\nALTER TABLE [payments].[Streams]\n    ADD CONSTRAINT [DF_payments_Streams_Position] DEFAULT (-1) FOR [Position];\n\n\nGO\nPRINT N'Creating [payments].[FK_Events_Streams]...';\n\n\nGO\nALTER TABLE [payments].[Messages] WITH NOCHECK\n    ADD CONSTRAINT [FK_Events_Streams] FOREIGN KEY ([StreamIdInternal]) REFERENCES [payments].[Streams] ([IdInternal]);\n\n\nGO\nPRINT N'Creating [administration].[v_MeetingGroupProposals]...';\n\n\nGO\nCREATE VIEW [administration].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode],\n    [MeetingGroupProposal].[DecisionDate],\n    [MeetingGroupProposal].[DecisionUserId],\n    [MeetingGroupProposal].[DecisionCode],\n    [MeetingGroupProposal].[DecisionRejectReason]\nFROM [administration].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\nPRINT N'Creating [administration].[v_Members]...';\n\n\nGO\nCREATE VIEW [administration].[v_Members]\nAS\nSELECT\n    [Member].[Id],\n    [Member].[Login],\n    [Member].[Email],\n    [Member].[FirstName],\n    [Member].[LastName],\n    [Member].[Name]\nFROM [administration].[Members] AS [Member]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroups]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_MeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity]\nFROM meetings.MeetingGroups AS [MeetingGroup]\nGO\nPRINT N'Creating [meetings].[v_Meetings]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_Meetings]\nAS\nSELECT\n\tMeeting.[Id],\n    Meeting.[Title],\n    Meeting.[Description],\n    Meeting.LocationAddress,\n    Meeting.LocationCity,\n    Meeting.LocationPostalCode,\n    Meeting.TermStartDate,\n    Meeting.TermEndDate\nFROM meetings.Meetings AS [Meeting]\nGO\nPRINT N'Creating [meetings].[v_Members]...';\n\n\nGO\nCREATE VIEW [meetings].[v_Members]\nAS\nSELECT\n    [Member].Id,\n    [Member].[Name],\n    [Member].[Login],\n    [Member].[Email]\nFROM meetings.Members AS [Member]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroupMembers]...';\n\n\nGO\nCREATE VIEW [meetings].[v_MeetingGroupMembers]\nAS\nSELECT\n    [MeetingGroupMember].MeetingGroupId,\n    [MeetingGroupMember].MemberId,\n    [MeetingGroupMember].RoleCode\nFROM meetings.MeetingGroupMembers AS [MeetingGroupMember]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroupProposals]...';\n\n\nGO\nCREATE VIEW [meetings].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode]\nFROM [meetings].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\nPRINT N'Creating [users].[v_UserRoles]...';\n\n\nGO\nCREATE VIEW [users].[v_UserRoles]\nAS\nSELECT\n    [UserRole].[UserId],\n    [UserRole].[RoleCode]\nFROM [users].[UserRoles] AS [UserRole]\nGO\nPRINT N'Creating [users].[v_Users]...';\n\n\nGO\nCREATE VIEW [users].[v_Users]\nAS\nSELECT\n    [User].[Id],\n    [User].[IsActive],\n    [User].[Login],\n    [User].[Password],\n    [User].[Email],\n    [User].[Name]\nFROM [users].[Users] AS [User]\nGO\nPRINT N'Creating [registrations].[v_UserRegistrations]...';\n\n\nGO\nCREATE VIEW [users].[v_UserRegistrations]\nAS\nSELECT\n    [UserRegistration].[Id],\n    [UserRegistration].[Login],\n    [UserRegistration].[Email],\n    [UserRegistration].[FirstName],\n    [UserRegistration].[LastName],\n    [UserRegistration].[Name],\n    [UserRegistration].[StatusCode]\nFROM [registrations].[UserRegistrations] AS [UserRegistration]\nGO\nPRINT N'Creating [registrations].[v_UserPermissions]...';\n\n\nGO\nCREATE VIEW [users].[v_UserPermissions]\nAS\nSELECT \n\tDISTINCT\n\t[UserRole].UserId,\n\t[RolesToPermission].PermissionCode\nFROM [users].UserRoles AS [UserRole]\n\tINNER JOIN [users].RolesToPermissions AS [RolesToPermission]\n\t\tON [UserRole].RoleCode = [RolesToPermission].RoleCode\nGO\nPRINT N'Checking existing data against newly created constraints';\n\n\nGO\n\nALTER TABLE [payments].[Messages] WITH CHECK CHECK CONSTRAINT [FK_Events_Streams];\n\n\nGO\nPRINT N'Update complete.';\n\n\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0001_initial_structure.sql",
    "content": "﻿\nPRINT N'Creating [administration]...';\n\n\nGO\nCREATE SCHEMA [administration]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [meetings]...';\n\n\nGO\nCREATE SCHEMA [meetings]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [payments]...';\n\n\nGO\nCREATE SCHEMA [payments]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [users]...';\n\n\nGO\nCREATE SCHEMA [users]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [registrations]...';\n\n\nGO\nCREATE SCHEMA [registrations]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [payments].[NewStreamMessages]...';\n\n\nGO\nCREATE TYPE [payments].[NewStreamMessages] AS TABLE (\n    [StreamVersion] INT              IDENTITY (0, 1) NOT NULL,\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [Created]       DATETIME         DEFAULT (GETUTCDATE()) NOT NULL,\n    [Type]          NVARCHAR (128)   NOT NULL,\n    [JsonData]      NVARCHAR (MAX)   NULL,\n    [JsonMetadata]  NVARCHAR (MAX)   NULL);\n\n\nGO\nPRINT N'Creating [administration].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [administration].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_administration_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[Members]...';\n\n\nGO\nCREATE TABLE [administration].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_administration_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [administration].[MeetingGroupProposals] (\n    [Id]                   UNIQUEIDENTIFIER NOT NULL,\n    [Name]                 NVARCHAR (255)   NOT NULL,\n    [Description]          VARCHAR (200)    NULL,\n    [LocationCity]         NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode]  NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]       UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]         DATETIME         NOT NULL,\n    [StatusCode]           NVARCHAR (50)    NOT NULL,\n    [DecisionDate]         DATETIME         NULL,\n    [DecisionUserId]       UNIQUEIDENTIFIER NULL,\n    [DecisionCode]         NVARCHAR (50)    NULL,\n    [DecisionRejectReason] NVARCHAR (250)   NULL,\n    CONSTRAINT [PK_administration_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingWaitlistMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingWaitlistMembers] (\n    [MeetingId]            UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]             UNIQUEIDENTIFIER NOT NULL,\n    [SignUpDate]           DATETIME2 (7)    NOT NULL,\n    [IsSignedOff]          BIT              NOT NULL,\n    [SignOffDate]          DATETIME2 (7)    NULL,\n    [IsMovedToAttendees]   BIT              NOT NULL,\n    [MovedToAttendeesDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingWaitlistMembers_MeetingId_MemberId_SignUpDate] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [SignUpDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingNotAttendees]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingNotAttendees] (\n    [MeetingId]          UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]           UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate]       DATETIME2 (7)    NOT NULL,\n    [DecisionChanged]    BIT              NOT NULL,\n    [DecisionChangeDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingNotAttendees_Id] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [DecisionDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[Meetings]...';\n\n\nGO\nCREATE TABLE [meetings].[Meetings] (\n    [Id]                 UNIQUEIDENTIFIER NOT NULL,\n    [MeetingGroupId]     UNIQUEIDENTIFIER NOT NULL,\n    [CreatorId]          UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]         DATETIME2 (7)    NOT NULL,\n    [Title]              NVARCHAR (200)   NOT NULL,\n    [Description]        NVARCHAR (4000)  NOT NULL,\n    [TermStartDate]      DATETIME         NOT NULL,\n    [TermEndDate]        DATETIME         NOT NULL,\n    [LocationName]       NVARCHAR (200)   NOT NULL,\n    [LocationAddress]    NVARCHAR (200)   NOT NULL,\n    [LocationPostalCode] NVARCHAR (200)   NULL,\n    [LocationCity]       NVARCHAR (50)    NOT NULL,\n    [AttendeesLimit]     INT              NULL,\n    [GuestsLimit]        INT              NOT NULL,\n    [RSVPTermStartDate]  DATETIME         NULL,\n    [RSVPTermEndDate]    DATETIME         NULL,\n    [EventFeeValue]      DECIMAL (5)      NULL,\n    [EventFeeCurrency]   VARCHAR (3)      NULL,\n    [ChangeDate]         DATETIME2 (7)    NULL,\n    [ChangeMemberId]     UNIQUEIDENTIFIER NULL,\n    [CancelDate]         DATETIME         NULL,\n    [CancelMemberId]     UNIQUEIDENTIFIER NULL,\n    [IsCanceled]         BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_Meetings_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupMembers] (\n    [MeetingGroupId] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]       UNIQUEIDENTIFIER NOT NULL,\n    [JoinedDate]     DATETIME2 (7)    NOT NULL,\n    [RoleCode]       VARCHAR (50)     NOT NULL,\n    [IsActive]       BIT              NOT NULL,\n    [LeaveDate]      DATETIME         NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupMembers_MeetingGroupId_MemberId_JoinedDate] PRIMARY KEY CLUSTERED ([MeetingGroupId] ASC, [MemberId] ASC, [JoinedDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroups]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroups] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [CreatorId]           UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]          DATETIME         NOT NULL,\n    [PaymentDateTo]       DATE             NULL,\n    CONSTRAINT [PK_meetings_MeetingGroups_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[Members]...';\n\n\nGO\nCREATE TABLE [meetings].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_meetings_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupProposals] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]      UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]        DATETIME         NOT NULL,\n    [StatusCode]          NVARCHAR (50)    NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [meetings].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_meetings_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MemberSubscriptions]...';\n\n\nGO\nCREATE TABLE [meetings].[MemberSubscriptions] (\n    [Id]             UNIQUEIDENTIFIER NOT NULL,\n    [ExpirationDate] DATETIME         NOT NULL,\n    CONSTRAINT [PK_meetings_MemberSubscriptions_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingAttendees]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingAttendees] (\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [AttendeeId]            UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate]          DATETIME2 (7)    NOT NULL,\n    [RoleCode]              VARCHAR (50)     NULL,\n    [GuestsNumber]          INT              NULL,\n    [DecisionChanged]       BIT              NOT NULL,\n    [DecisionChangeDate]    DATETIME2 (7)    NULL,\n    [IsRemoved]             BIT              NOT NULL,\n    [RemovingMemberId]      UNIQUEIDENTIFIER NULL,\n    [RemovingReason]        NVARCHAR (500)   NULL,\n    [RemovedDate]           DATETIME2 (7)    NULL,\n    [BecameNotAttendeeDate] DATETIME2 (7)    NULL,\n    [FeeValue]              DECIMAL (5)      NULL,\n    [FeeCurrency]           VARCHAR (3)      NULL,\n    [IsFeePaid]             BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingAttendees_Id] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [AttendeeId] ASC, [DecisionDate] ASC)\n);\n\nGO\nPRINT N'Creating [meetings].[MeetingComments]...';\n\n\nGO\nCREATE TABLE meetings.MeetingComments\n(\n    [Id]                    UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [AuthorId]              UNIQUEIDENTIFIER NOT NULL,\n    [InReplyToCommentId]    UNIQUEIDENTIFIER NULL,\n    [Comment]               VARCHAR(300)     NULL,\n    [IsRemoved]             BIT              NOT NULL,\n    [RemovedByReason]       VARCHAR(300)     NULL,\n    [CreateDate]            DATETIME         NOT NULL,\n    [EditDate]              DATE             NULL,\n    CONSTRAINT [PK_meetings_MeetingComments_Id] PRIMARY KEY ([Id] ASC)\n)\n\nGO\nPRINT N'Creating [payments].[Payers]...';\n\n\nGO\nCREATE TABLE [payments].[Payers] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_payments_Payers_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [payments].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_payments_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\n\nPRINT N'Creating [payments].[MeetingFees]...';\n\n\nGO\nCREATE TABLE [payments].[MeetingFees] (\n    [MeetingFeeId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId]      UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]    UNIQUEIDENTIFIER NOT NULL,\n    [FeeValue]     DECIMAL (18, 2)  NOT NULL,\n    [FeeCurrency]  VARCHAR (50)     NOT NULL,\n    [Status]       VARCHAR (50)     NOT NULL,\n    CONSTRAINT [PK_payments_MeetingFees_MeetingFeeId] PRIMARY KEY CLUSTERED ([MeetingFeeId] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[PriceListItems]...';\n\n\nGO\nCREATE TABLE [payments].[PriceListItems] (\n    [Id]                     UNIQUEIDENTIFIER NOT NULL,\n    [SubscriptionPeriodCode] VARCHAR (50)     NOT NULL,\n    [CategoryCode]           VARCHAR (50)     NOT NULL,\n    [CountryCode]            VARCHAR (50)     NOT NULL,\n    [MoneyValue]             DECIMAL (18, 2)  NOT NULL,\n    [MoneyCurrency]          VARCHAR (50)     NOT NULL,\n    [IsActive]               BIT              NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionPayments]...';\n\n\nGO\nCREATE TABLE [payments].[SubscriptionPayments] (\n    [PaymentId]      UNIQUEIDENTIFIER NOT NULL,\n    [PayerId]        UNIQUEIDENTIFIER NOT NULL,\n    [Type]           VARCHAR (50)     NOT NULL,\n    [Status]         VARCHAR (50)     NOT NULL,\n    [Period]         VARCHAR (50)     NOT NULL,\n    [Date]           DATETIME         NOT NULL,\n    [SubscriptionId] UNIQUEIDENTIFIER NULL,\n    [MoneyValue]     DECIMAL (18, 2)  NOT NULL,\n    [MoneyCurrency]  VARCHAR (50)     NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionCheckpoints]...';\n\n\nGO\nCREATE TABLE [payments].[SubscriptionCheckpoints] (\n    [Code]     VARCHAR (50) NOT NULL,\n    [Position] BIGINT       NOT NULL\n);\n\n\nGO\nPRINT N'Creating [payments].[SubscriptionDetails]...';\nGO\nCREATE TABLE [payments].[SubscriptionDetails] (\n    [Id]             UNIQUEIDENTIFIER NOT NULL,\n    [Period]         VARCHAR (50)     NOT NULL,\n    [Status]         VARCHAR (50)     NOT NULL,\n    [CountryCode]    VARCHAR (50)     NOT NULL,\n    [ExpirationDate] DATETIME         NOT NULL,\n    CONSTRAINT [PK_payments_SubscriptionDetails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\nGO\nPRINT N'Creating [payments].[Streams]...';\nGO\nCREATE TABLE [payments].[Streams] (\n        Id                  CHAR(42)                                NOT NULL,\n        IdOriginal          NVARCHAR(1000)                          NOT NULL,\n        IdInternal          INT                 IDENTITY(1,1)       NOT NULL,\n        [Version]           INT                 NOT NULL,\n        Position            BIGINT              NOT NULL,\n        MaxAge              INT                 DEFAULT(NULL),\n        MaxCount            INT                 DEFAULT(NULL),\n        IdOriginalReversed  AS REVERSE(IdOriginal)\n        CONSTRAINT PK_Streams PRIMARY KEY CLUSTERED (IdInternal)\n);\n\nGO\nPRINT N'Creating [payments].[DF_payments_Streams_Version]...';\n\nGO\nALTER TABLE [payments].[Streams]\n    ADD CONSTRAINT [DF_payments_Streams_Version] DEFAULT (-1) FOR [Version];\n\nGO\nPRINT N'Creating [payments].[DF_payments_Streams_Position]...';\n\nGO\nALTER TABLE [payments].[Streams]\n    ADD CONSTRAINT [DF_payments_Streams_Position] DEFAULT (-1) FOR [Position];\nGO\n\nPRINT N'Creating [payments].[Streams].[IX_Streams_Id]...';\nGO\nCREATE UNIQUE NONCLUSTERED INDEX [IX_Streams_Id]\n    ON [payments].[Streams]([Id] ASC);\n\nCREATE NONCLUSTERED INDEX IX_Streams_IdOriginal\n        ON [payments].Streams (IdOriginal);\n\nCREATE NONCLUSTERED INDEX IX_Streams_IdOriginalReversed\n        ON [payments].Streams (IdOriginalReversed);\nGO\nPRINT N'Creating [payments].[Messages]...';\n\n\nGO\nCREATE TABLE [payments].[Messages] (\n    [StreamIdInternal] INT              NOT NULL,\n    [StreamVersion]    INT              NOT NULL,\n    [Position]         BIGINT           IDENTITY (0, 1) NOT NULL,\n    [Id]               UNIQUEIDENTIFIER NOT NULL,\n    [Created]          DATETIME         NOT NULL,\n    [Type]             NVARCHAR (128)   NOT NULL,\n    [JsonData]         NVARCHAR (MAX)   NOT NULL,\n    [JsonMetadata]     NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_Events] PRIMARY KEY NONCLUSTERED ([Position] ASC),\n    CONSTRAINT FK_Events_Streams FOREIGN KEY (StreamIdInternal) REFERENCES payments.Streams(IdInternal)\n);\n\n\nGO\nPRINT N'Creating [payments].[Messages] Index...';\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Id' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Id ON payments.Messages (StreamIdInternal, Id);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Revision' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Revision ON payments.Messages (StreamIdInternal, StreamVersion);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Created' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Created ON payments.Messages (StreamIdInternal, Created);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.table_types tt JOIN sys.schemas s ON tt.schema_id = s.schema_id\n    WHERE s.name + '.' + tt.name='payments.NewStreamMessages')\nBEGIN\n    CREATE TYPE payments.NewStreamMessages AS TABLE (\n        StreamVersion       INT IDENTITY(0,1)                       NOT NULL,\n        Id                  UNIQUEIDENTIFIER                        NOT NULL,\n        Created             DATETIME          DEFAULT(GETUTCDATE()) NOT NULL,\n        [Type]              NVARCHAR(128)                           NOT NULL,\n        JsonData            NVARCHAR(max)                           NULL,\n        JsonMetadata        NVARCHAR(max)                           NULL\n    );\nEND\n\nBEGIN\n    IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('payments.Streams') AND [name] = N'version' AND [minor_id] = 0)\n    EXEC sys.sp_addextendedproperty   \n    @name = N'version',\n    @value = N'3',\n    @level0type = N'SCHEMA', @level0name = 'payments',\n    @level1type = N'TABLE',  @level1name = 'Streams';\nEND\n\nGO\nPRINT N'Creating [users].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[UserRoles]...';\n\n\nGO\nCREATE TABLE [users].[UserRoles] (\n    [UserId]   UNIQUEIDENTIFIER NOT NULL,\n    [RoleCode] NVARCHAR (50)    NULL\n);\n\n\nGO\nPRINT N'Creating [registrations].[UserRegistrations]...';\n\n\nGO\nCREATE TABLE [registrations].[UserRegistrations] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [Login]         NVARCHAR (100)   NOT NULL,\n    [Email]         NVARCHAR (255)   NOT NULL,\n    [Password]      NVARCHAR (255)   NOT NULL,\n    [FirstName]     NVARCHAR (50)    NOT NULL,\n    [LastName]      NVARCHAR (50)    NOT NULL,\n    [Name]          NVARCHAR (255)   NOT NULL,\n    [StatusCode]    VARCHAR (50)     NOT NULL,\n    [RegisterDate]  DATETIME         NOT NULL,\n    [ConfirmedDate] DATETIME         NULL,\n    CONSTRAINT [PK_registrations_UserRegistrations_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Users]...';\n\n\nGO\nCREATE TABLE [users].[Users] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [Password]  NVARCHAR (255)   NOT NULL,\n    [IsActive]  BIT              NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_users_Users_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[RolesToPermissions]...';\n\n\nGO\nCREATE TABLE [users].[RolesToPermissions] (\n    [RoleCode]       VARCHAR (50) NOT NULL,\n    [PermissionCode] VARCHAR (50) NOT NULL,\n    CONSTRAINT [PK_RolesToPermissions_RoleCode_PermissionCode] PRIMARY KEY CLUSTERED ([RoleCode] ASC, [PermissionCode] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Permissions]...';\n\n\nGO\nCREATE TABLE [users].[Permissions] (\n    [Code]        VARCHAR (50)  NOT NULL,\n    [Name]        VARCHAR (100) NOT NULL,\n    [Description] VARCHAR (255) NULL,\n    CONSTRAINT [PK_users_Permissions_Code] PRIMARY KEY CLUSTERED ([Code] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [users].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error]         NVARCHAR (MAX)   NULL,\n    CONSTRAINT [PK_users_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\n\nPRINT N'Creating [administration].[v_MeetingGroupProposals]...';\n\n\nGO\nCREATE VIEW [administration].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode],\n    [MeetingGroupProposal].[DecisionDate],\n    [MeetingGroupProposal].[DecisionUserId],\n    [MeetingGroupProposal].[DecisionCode],\n    [MeetingGroupProposal].[DecisionRejectReason]\nFROM [administration].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\nPRINT N'Creating [administration].[v_Members]...';\n\n\nGO\nCREATE VIEW [administration].[v_Members]\nAS\nSELECT\n    [Member].[Id],\n    [Member].[Login],\n    [Member].[Email],\n    [Member].[FirstName],\n    [Member].[LastName],\n    [Member].[Name]\nFROM [administration].[Members] AS [Member]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroups]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_MeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity]\nFROM meetings.MeetingGroups AS [MeetingGroup]\nGO\nPRINT N'Creating [meetings].[v_Meetings]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_Meetings]\nAS\nSELECT\n\tMeeting.[Id],\n    Meeting.[Title],\n    Meeting.[Description],\n    Meeting.LocationAddress,\n    Meeting.LocationCity,\n    Meeting.LocationPostalCode,\n    Meeting.TermStartDate,\n    Meeting.TermEndDate\nFROM meetings.Meetings AS [Meeting]\nGO\nPRINT N'Creating [meetings].[v_Members]...';\n\n\nGO\nCREATE VIEW [meetings].[v_Members]\nAS\nSELECT\n    [Member].Id,\n    [Member].[Name],\n    [Member].[Login],\n    [Member].[Email]\nFROM meetings.Members AS [Member]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroupMembers]...';\n\n\nGO\nCREATE VIEW [meetings].[v_MeetingGroupMembers]\nAS\nSELECT\n    [MeetingGroupMember].MeetingGroupId,\n    [MeetingGroupMember].MemberId,\n    [MeetingGroupMember].RoleCode\nFROM meetings.MeetingGroupMembers AS [MeetingGroupMember]\nGO\nPRINT N'Creating [meetings].[v_MeetingGroupProposals]...';\n\n\nGO\nCREATE VIEW [meetings].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode]\nFROM [meetings].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\nPRINT N'Creating [users].[v_UserRoles]...';\n\n\nGO\nCREATE VIEW [users].[v_UserRoles]\nAS\nSELECT\n    [UserRole].[UserId],\n    [UserRole].[RoleCode]\nFROM [users].[UserRoles] AS [UserRole]\nGO\nPRINT N'Creating [users].[v_Users]...';\n\n\nGO\nCREATE VIEW [users].[v_Users]\nAS\nSELECT\n    [User].[Id],\n    [User].[IsActive],\n    [User].[Login],\n    [User].[Password],\n    [User].[Email],\n    [User].[Name]\nFROM [users].[Users] AS [User]\nGO\nPRINT N'Creating [registrations].[v_UserRegistrations]...';\n\n\nGO\nCREATE VIEW [users].[v_UserRegistrations]\nAS\nSELECT\n    [UserRegistration].[Id],\n    [UserRegistration].[Login],\n    [UserRegistration].[Email],\n    [UserRegistration].[FirstName],\n    [UserRegistration].[LastName],\n    [UserRegistration].[Name],\n    [UserRegistration].[StatusCode]\nFROM [registrations].[UserRegistrations] AS [UserRegistration]\nGO\nPRINT N'Creating [users].[v_UserPermissions]...';\n\n\nGO\nCREATE VIEW [users].[v_UserPermissions]\nAS\nSELECT \n\tDISTINCT\n\t[UserRole].UserId,\n\t[RolesToPermission].PermissionCode\nFROM [users].UserRoles AS [UserRole]\n\tINNER JOIN [users].RolesToPermissions AS [RolesToPermission]\n\t\tON [UserRole].RoleCode = [RolesToPermission].RoleCode\nGO\nPRINT N'Checking existing data against newly created constraints';\n\n\nGO\n\nALTER TABLE [payments].[Messages] WITH CHECK CHECK CONSTRAINT [FK_Events_Streams];\n\n\nGO\nPRINT N'Update complete.';\n\n\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0002_change_meeting_comments_edit_date_type_and_add_meeting_comments_view.sql",
    "content": "﻿ALTER TABLE [meetings].[MeetingComments] \nALTER COLUMN [EditDate] DATETIME \nGO\n\nCREATE VIEW [meetings].[v_MeetingComments]\nAS\nSELECT\n    [MeetingComments].Id,\n    [MeetingComments].MeetingId,\n    [MeetingComments].AuthorId,\n    [MeetingComments].InReplyToCommentId,\n    [MeetingComments].Comment,\n    [MeetingComments].CreateDate,\n    [MeetingComments].EditDate\nFROM [meetings].[MeetingComments] AS [MeetingComments]\nWHERE [MeetingComments].IsRemoved = 0\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0003_add_meetings_countries_table.sql",
    "content": "﻿CREATE TABLE [meetings].[Countries]\n(\n\t[Code] CHAR(2) NOT NULL,\n\t[Name] NVARCHAR(50) NOT NULL\n\tCONSTRAINT [PK_meetings_Countries_Code] PRIMARY KEY ([Code] ASC)\n)\nGO\n\nCREATE VIEW [meetings].[v_Countries]\nAS\nSELECT\n    [Country].[Code],\n    [Country].[Name]\nFROM meetings.Countries AS [Country]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0004_add_meeting_commenting_configurations_table.sql",
    "content": "﻿CREATE TABLE meetings.MeetingCommentingConfigurations\n(\n    [Id]                    UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [IsCommentingEnabled]   BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingCommentingConfigurations_Id] PRIMARY KEY ([Id] ASC),\n    CONSTRAINT [FK_meetings_MeetingCommentingConfigurations_Meetings] FOREIGN KEY ([MeetingId]) REFERENCES meetings.Meetings ([Id])\n);\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0005_add_payer_id_to_subcription_details_view.sql",
    "content": "﻿DELETE FROM payments.SubscriptionDetails\nGO\n\nALTER TABLE payments.SubscriptionDetails ADD [PayerId] UNIQUEIDENTIFIER NOT NULL\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0006_add_member_meeting_groups_view.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MemberMeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity],\n\n    [MeetingGroupMember].[MemberId],\n    [MeetingGroupMember].[RoleCode],\n    [MeetingGroupMember].[IsActive],\n    [MeetingGroupMember].[JoinedDate]\nFROM meetings.MeetingGroups AS [MeetingGroup]\n    INNER JOIN [meetings].[MeetingGroupMembers] AS [MeetingGroupMember]\n        ON [MeetingGroup].[Id] = [MeetingGroupMember].[MeetingGroupId]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0007_add_meeting_attendees_view.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingAttendees]\nAS\nSELECT\n    [MeetingAttendee].[MeetingId],\n    [MeetingAttendee].[AttendeeId],\n    [MeetingAttendee].[DecisionDate],\n    [MeetingAttendee].[RoleCode],\n    [MeetingAttendee].[GuestsNumber],\n\n    [Member].[FirstName],\n    [Member].[LastName]\nFROM [meetings].[MeetingAttendees] AS [MeetingAttendee]\n    INNER JOIN [meetings].[Members] AS [Member]\n        ON [MeetingAttendee].[AttendeeId] = [Member].[Id]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0008_add_meeting_details_view.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingDetails]\nAS\nSELECT\n    [Meeting].[Id],\n    [Meeting].[MeetingGroupId],\n    [Meeting].[Title],\n    [Meeting].[TermStartDate],\n    [Meeting].[TermEndDate],\n    [Meeting].[Description],\n    [Meeting].[LocationName],\n    [Meeting].[LocationAddress],\n    [Meeting].[LocationPostalCode],\n    [Meeting].[LocationCity],\n    [Meeting].[AttendeesLimit],\n    [Meeting].[GuestsLimit],\n    [Meeting].[RSVPTermStartDate],\n    [Meeting].[RSVPTermEndDate],\n    [Meeting].[EventFeeValue],\n    [Meeting].[EventFeeCurrency]\nFROM [meetings].[Meetings] AS [Meeting]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0009_add_mock_emails_table.sql",
    "content": "﻿CREATE TABLE [app].[Emails]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[From] NVARCHAR(255) NOT NULL,\n\t[To] NVARCHAR(255) NOT NULL,\n\t[Subject] NVARCHAR(255) NOT NULL,\n\t[Content] NVARCHAR(MAX) NOT NULL,\n\t[Date] DATETIME NOT NULL,\n\tCONSTRAINT [PK_app_Emails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n)\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0010_add_member_meetings_view.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MemberMeetings]\nAS\nSELECT\n\t[Meeting].[Id],\n    [Meeting].[Title],\n    [Meeting].[Description],\n    [Meeting].[LocationAddress],\n    [Meeting].[LocationCity],\n    [Meeting].[LocationPostalCode],\n    [Meeting].[TermStartDate],\n    [Meeting].[TermEndDate],\n\n    [MeetingAttendee].[AttendeeId],\n    [MeetingAttendee].[IsRemoved],\n    [MeetingAttendee].[RoleCode]\nFROM [meetings].[Meetings] AS [Meeting]\n    INNER JOIN [meetings].[MeetingAttendees] AS [MeetingAttendee]\n        ON [Meeting].[Id] = [MeetingAttendee].[MeetingId]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0011_add_likes_count_to_meeting_comments_table.sql",
    "content": "﻿ALTER TABLE [meetings].[MeetingComments] ADD [LikesCount] INT DEFAULT 0\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0012_add_likes_count_to_meeting_comments_view.sql",
    "content": "﻿ALTER VIEW [meetings].[v_MeetingComments]\nAS\nSELECT\n    [MeetingComments].Id,\n    [MeetingComments].MeetingId,\n    [MeetingComments].AuthorId,\n    [MeetingComments].InReplyToCommentId,\n    [MeetingComments].Comment,\n    [MeetingComments].CreateDate,\n    [MeetingComments].EditDate,\n    [MeetingComments].LikesCount\nFROM [meetings].[MeetingComments] AS [MeetingComments]\nWHERE [MeetingComments].IsRemoved = 0\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0013_add_meeting_member_comment_likes_table.sql",
    "content": "﻿CREATE TABLE [meetings].[MeetingMemberCommentLikes]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]  UNIQUEIDENTIFIER NOT NULL,\n    [MeetingCommentId] UNIQUEIDENTIFIER NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingMemberCommentLikes_Id] PRIMARY KEY ([Id] ASC),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_Members] FOREIGN KEY ([MemberId]) REFERENCES meetings.Members ([Id]),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_MeetingComments] FOREIGN KEY ([MeetingCommentId]) REFERENCES meetings.MeetingComments ([Id])\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Migrations/1_0_0_0/0014_add_missing_tables_for_registrations.sql",
    "content": "﻿CREATE TABLE [registrations].[OutboxMessages]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_registrations_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO\n\nCREATE TABLE [registrations].[InternalCommands]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_registrations_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO\n\nCREATE TABLE [registrations].[InboxMessages]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_registrations_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/SeedDatabase.sql",
    "content": "﻿-- Add Test Member\nINSERT INTO registrations.UserRegistrations VALUES \n(\n\t'2EBFECFC-ED13-43B8-B516-6AC89D51C510',\n\t'testMember@mail.com',\n\t'testMember@mail.com',\n\t'AHKrg4VuA82NvKXNoaPx0odIMnw1eRQV9IqmCHJ1jemv4sWFD3jsw6dabc1xerzgLQ==', -- testMemberPass\n\t'John',\n\t'Doe',\n\t'John Doe',\n\t'Confirmed',\n\tGETDATE(),\n\tGETDATE()\n)\n\nINSERT INTO users.Users VALUES\n(\n\t'2EBFECFC-ED13-43B8-B516-6AC89D51C510',\n\t'testMember@mail.com',\n\t'testMember@mail.com',\n\t'AHKrg4VuA82NvKXNoaPx0odIMnw1eRQV9IqmCHJ1jemv4sWFD3jsw6dabc1xerzgLQ==', -- testMemberPass\n\t1,\n\t'John',\n\t'Doe',\n\t'John Doe'\n)\n\nINSERT INTO meetings.Members VALUES\n(\n\t'2EBFECFC-ED13-43B8-B516-6AC89D51C510',\n\t'testMember@mail.com',\n\t'testMember@mail.com',\n\t'John',\n\t'Doe',\n\t'John Doe'\n)\n\nINSERT INTO payments.Payers VALUES\n(\n\t'2EBFECFC-ED13-43B8-B516-6AC89D51C510',\n\t'testMember@mail.com',\n\t'testMember@mail.com',\n\t'John',\n\t'Doe',\n\t'John Doe'\n)\n\nINSERT INTO users.UserRoles VALUES\n('2EBFECFC-ED13-43B8-B516-6AC89D51C510', 'Member')\n\n-- Add Test Administrator\nINSERT INTO registrations.UserRegistrations VALUES \n(\n\t'4065630E-4A4C-4F01-9142-0BACF6B8C64D',\n\t'testAdmin@mail.com',\n\t'testAdmin@mail.com',\n\t'AK0qplH5peUHwnCVuzW9zy0JGZTTG6/Ji88twX+nw9JdTUwqa3Wol1K4m5aCG9pE2A==', -- testAdminPass\n\t'Jane',\n\t'Doe',\n\t'Jane Doe',\n\t'Confirmed',\n\tGETDATE(),\n\tGETDATE()\n)\n\nINSERT INTO users.Users VALUES\n(\n\t'4065630E-4A4C-4F01-9142-0BACF6B8C64D',\n\t'testAdmin@mail.com',\n\t'testAdmin@mail.com',\n\t'AJtxxwNDtxRI7lq268ienCfsBwvo9y3RmKkP4JMpRinWqdgbnFgzjLX9LqEt2YcUgA==', -- testAdminPass\n\t1,\n\t'Jane',\n\t'Doe',\n\t'Jane Doe'\n)\n\nINSERT INTO users.UserRoles VALUES\n('4065630E-4A4C-4F01-9142-0BACF6B8C64D', 'Administrator')\n\n-- Roles to Permissions\n\nINSERT INTO users.[Permissions] ([Code], [Name]) VALUES\n\t-- Meetings\n\t('GetMeetingGroupProposals', 'GetMeetingGroupProposals'),\n\t('ProposeMeetingGroup', 'ProposeMeetingGroup'),\n\t('CreateNewMeeting','CreateNewMeeting'),\n\t('EditMeeting','EditMeeting'),\n\t('AddMeetingAttendee','AddMeetingAttendee'),\n\t('RemoveMeetingAttendee','RemoveMeetingAttendee'),\n\t('AddNotAttendee','AddNotAttendee'),\n\t('ChangeNotAttendeeDecision','ChangeNotAttendeeDecision'),\n\t('SignUpMemberToWaitlist','SignUpMemberToWaitlist'),\n\t('SignOffMemberFromWaitlist','SignOffMemberFromWaitlist'),\n\t('SetMeetingHostRole','SetMeetingHostRole'),\n\t('SetMeetingAttendeeRole','SetMeetingAttendeeRole'),\n\t('CancelMeeting','CancelMeeting'),\n\t('GetAllMeetingGroups','GetAllMeetingGroups'),\n\t('EditMeetingGroupGeneralAttributes','EditMeetingGroupGeneralAttributes'),\n\t('JoinToGroup','JoinToGroup'),\n\t('LeaveMeetingGroup','LeaveMeetingGroup'),\n\t('AddMeetingComment','AddMeetingComment'),\n\t('EditMeetingComment','EditMeetingComment'),\n\t('RemoveMeetingComment','RemoveMeetingComment'),\n\t('AddMeetingCommentReply','AddMeetingCommentReply'),\n\t('LikeMeetingComment','LikeMeetingComment'),\n\t('UnlikeMeetingComment','UnlikeMeetingComment'),\n\t('EnableMeetingCommenting','EnableMeetingCommenting'),\n\t('DisableMeetingCommenting','DisableMeetingCommenting'),\n\t('MyMeetingGroupsView','MyMeetingGroupsView'),\n\t('AllMeetingGroupsView','AllMeetingGroupsView'),\n\t('SubscriptionView','SubscriptionView'),\n\t('EmailsView','EmailsView'),\n\t('MyMeetingsView','MyMeetingsView'),\n\t('GetAuthenticatedMemberMeetings','GetAuthenticatedMemberMeetings'),\n\n\t-- Administration\n\t('AcceptMeetingGroupProposal','AcceptMeetingGroupProposal'),\n\t('AdministrationsView','AdministrationsView'),\n\n\t-- Payments\n\t('RegisterPayment','RegisterPayment'),\n\t('BuySubscription','BuySubscription'),\n\t('RenewSubscription','RenewSubscription'),\n\t('CreatePriceListItem','CreatePriceListItem'),\n\t('ActivatePriceListItem','ActivatePriceListItem'),\n\t('DeactivatePriceListItem','DeactivatePriceListItem'),\n\t('ChangePriceListItemAttributes','ChangePriceListItemAttributes'),\n\t('GetAuthenticatedPayerSubscription','GetAuthenticatedPayerSubscription'),\n\t('GetPriceListItem','GetPriceListItem')\n\n-- Meetings\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingGroupProposals')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'ProposeMeetingGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'CreateNewMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RemoveMeetingAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddNotAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'ChangeNotAttendeeDecision')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SignUpMemberToWaitlist')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SignOffMemberFromWaitlist')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SetMeetingHostRole')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SetMeetingAttendeeRole')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'CancelMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAllMeetingGroups')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeetingGroupGeneralAttributes')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'JoinToGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'LeaveMeetingGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RemoveMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingCommentReply')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'LikeMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'UnlikeMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedMemberMeetingGroups')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingGroupDetails')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingDetails')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingAttendees')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'MyMeetingsGroupsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SubscriptionView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EmailsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AllMeetingGroupsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'MyMeetingsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedMemberMeetings')\n\n-- Administration\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'AcceptMeetingGroupProposal')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'AdministrationsView')\n\n-- Payments\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RegisterPayment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'BuySubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RenewSubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedPayerSubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetPriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'CreatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'ActivatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'DeactivatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'ChangePriceListItemAttributes')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'GetPriceListItem')"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Scripts/Seeds/0001_SeedCountries.sql",
    "content": "﻿INSERT INTO [meetings].[Countries] VALUES ('AD', 'Andorra')\nINSERT INTO [meetings].[Countries] VALUES ('AE', 'United Arab Emirates')\nINSERT INTO [meetings].[Countries] VALUES ('AF', 'Afghanistan')\nINSERT INTO [meetings].[Countries] VALUES ('AG', 'Antigua and Barbuda')\nINSERT INTO [meetings].[Countries] VALUES ('AI', 'Anguilla')\nINSERT INTO [meetings].[Countries] VALUES ('AL', 'Albania')\nINSERT INTO [meetings].[Countries] VALUES ('AM', 'Armenia')\nINSERT INTO [meetings].[Countries] VALUES ('AN', 'Netherlands Antilles')\nINSERT INTO [meetings].[Countries] VALUES ('AO', 'Angola')\nINSERT INTO [meetings].[Countries] VALUES ('AQ', 'Antarctica')\nINSERT INTO [meetings].[Countries] VALUES ('AR', 'Argentina')\nINSERT INTO [meetings].[Countries] VALUES ('AS', 'American Samoa')\nINSERT INTO [meetings].[Countries] VALUES ('AT', 'Austria')\nINSERT INTO [meetings].[Countries] VALUES ('AU', 'Australia')\nINSERT INTO [meetings].[Countries] VALUES ('AW', 'Aruba')\nINSERT INTO [meetings].[Countries] VALUES ('AX', 'Aland Islands')\nINSERT INTO [meetings].[Countries] VALUES ('AZ', 'Azerbaijan')\nINSERT INTO [meetings].[Countries] VALUES ('BA', 'Bosnia and Herzegovina')\nINSERT INTO [meetings].[Countries] VALUES ('BB', 'Barbados')\nINSERT INTO [meetings].[Countries] VALUES ('BD', 'Bangladesh')\nINSERT INTO [meetings].[Countries] VALUES ('BE', 'Belgium')\nINSERT INTO [meetings].[Countries] VALUES ('BF', 'Burkina Faso')\nINSERT INTO [meetings].[Countries] VALUES ('BG', 'Bulgaria')\nINSERT INTO [meetings].[Countries] VALUES ('BH', 'Bahrain')\nINSERT INTO [meetings].[Countries] VALUES ('BI', 'Burundi')\nINSERT INTO [meetings].[Countries] VALUES ('BJ', 'Benin')\nINSERT INTO [meetings].[Countries] VALUES ('BM', 'Bermuda')\nINSERT INTO [meetings].[Countries] VALUES ('BN', 'Brunei Darussalam')\nINSERT INTO [meetings].[Countries] VALUES ('BO', 'Bolivia')\nINSERT INTO [meetings].[Countries] VALUES ('BR', 'Brazil')\nINSERT INTO [meetings].[Countries] VALUES ('BS', 'Bahamas')\nINSERT INTO [meetings].[Countries] VALUES ('BT', 'Bhutan')\nINSERT INTO [meetings].[Countries] VALUES ('BV', 'Bouvet Island')\nINSERT INTO [meetings].[Countries] VALUES ('BW', 'Botswana')\nINSERT INTO [meetings].[Countries] VALUES ('BY', 'Belarus')\nINSERT INTO [meetings].[Countries] VALUES ('BZ', 'Belize')\nINSERT INTO [meetings].[Countries] VALUES ('CA', 'Canada')\nINSERT INTO [meetings].[Countries] VALUES ('CC', 'Cocos (Keeling) Islands')\nINSERT INTO [meetings].[Countries] VALUES ('CD', 'Congo, The Democratic Republic of the')\nINSERT INTO [meetings].[Countries] VALUES ('CF', 'Central African Republic')\nINSERT INTO [meetings].[Countries] VALUES ('CG', 'Congo')\nINSERT INTO [meetings].[Countries] VALUES ('CH', 'Switzerland')\nINSERT INTO [meetings].[Countries] VALUES ('CI', 'Cote DIvoire')\nINSERT INTO [meetings].[Countries] VALUES ('CK', 'Cook Islands')\nINSERT INTO [meetings].[Countries] VALUES ('CL', 'Chile')\nINSERT INTO [meetings].[Countries] VALUES ('CM', 'Cameroon')\nINSERT INTO [meetings].[Countries] VALUES ('CN', 'China')\nINSERT INTO [meetings].[Countries] VALUES ('CO', 'Colombia')\nINSERT INTO [meetings].[Countries] VALUES ('CR', 'Costa Rica')\nINSERT INTO [meetings].[Countries] VALUES ('CU', 'Cuba')\nINSERT INTO [meetings].[Countries] VALUES ('CV', 'Cape Verde')\nINSERT INTO [meetings].[Countries] VALUES ('CX', 'Christmas Island')\nINSERT INTO [meetings].[Countries] VALUES ('CY', 'Cyprus')\nINSERT INTO [meetings].[Countries] VALUES ('CZ', 'Czech Republic')\nINSERT INTO [meetings].[Countries] VALUES ('DE', 'Germany')\nINSERT INTO [meetings].[Countries] VALUES ('DJ', 'Djibouti')\nINSERT INTO [meetings].[Countries] VALUES ('DK', 'Denmark')\nINSERT INTO [meetings].[Countries] VALUES ('DM', 'Dominica')\nINSERT INTO [meetings].[Countries] VALUES ('DO', 'Dominican Republic')\nINSERT INTO [meetings].[Countries] VALUES ('DZ', 'Algeria')\nINSERT INTO [meetings].[Countries] VALUES ('EC', 'Ecuador')\nINSERT INTO [meetings].[Countries] VALUES ('EE', 'Estonia')\nINSERT INTO [meetings].[Countries] VALUES ('EG', 'Egypt')\nINSERT INTO [meetings].[Countries] VALUES ('EH', 'Western Sahara')\nINSERT INTO [meetings].[Countries] VALUES ('ER', 'Eritrea')\nINSERT INTO [meetings].[Countries] VALUES ('ES', 'Spain')\nINSERT INTO [meetings].[Countries] VALUES ('ET', 'Ethiopia')\nINSERT INTO [meetings].[Countries] VALUES ('FI', 'Finland')\nINSERT INTO [meetings].[Countries] VALUES ('FJ', 'Fiji')\nINSERT INTO [meetings].[Countries] VALUES ('FK', 'Falkland Islands (Malvinas)')\nINSERT INTO [meetings].[Countries] VALUES ('FM', 'Micronesia, Federated States of')\nINSERT INTO [meetings].[Countries] VALUES ('FO', 'Faroe Islands')\nINSERT INTO [meetings].[Countries] VALUES ('FR', 'France')\nINSERT INTO [meetings].[Countries] VALUES ('GA', 'Gabon')\nINSERT INTO [meetings].[Countries] VALUES ('GB', 'United Kingdom')\nINSERT INTO [meetings].[Countries] VALUES ('GD', 'Grenada')\nINSERT INTO [meetings].[Countries] VALUES ('GE', 'Georgia')\nINSERT INTO [meetings].[Countries] VALUES ('GF', 'French Guiana')\nINSERT INTO [meetings].[Countries] VALUES ('GG', 'Guernsey')\nINSERT INTO [meetings].[Countries] VALUES ('GH', 'Ghana')\nINSERT INTO [meetings].[Countries] VALUES ('GI', 'Gibraltar')\nINSERT INTO [meetings].[Countries] VALUES ('GL', 'Greenland')\nINSERT INTO [meetings].[Countries] VALUES ('GM', 'Gambia')\nINSERT INTO [meetings].[Countries] VALUES ('GN', 'Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('GP', 'Guadeloupe')\nINSERT INTO [meetings].[Countries] VALUES ('GQ', 'Equatorial Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('GR', 'Greece')\nINSERT INTO [meetings].[Countries] VALUES ('GS', 'South Georgia and the South Sandwich Islands')\nINSERT INTO [meetings].[Countries] VALUES ('GT', 'Guatemala')\nINSERT INTO [meetings].[Countries] VALUES ('GU', 'Guam')\nINSERT INTO [meetings].[Countries] VALUES ('GW', 'Guinea-Bissau')\nINSERT INTO [meetings].[Countries] VALUES ('GY', 'Guyana')\nINSERT INTO [meetings].[Countries] VALUES ('HK', 'Hong Kong')\nINSERT INTO [meetings].[Countries] VALUES ('HM', 'Heard Island and Mcdonald Islands')\nINSERT INTO [meetings].[Countries] VALUES ('HN', 'Honduras')\nINSERT INTO [meetings].[Countries] VALUES ('HR', 'Croatia')\nINSERT INTO [meetings].[Countries] VALUES ('HT', 'Haiti')\nINSERT INTO [meetings].[Countries] VALUES ('HU', 'Hungary')\nINSERT INTO [meetings].[Countries] VALUES ('ID', 'Indonesia')\nINSERT INTO [meetings].[Countries] VALUES ('IE', 'Ireland')\nINSERT INTO [meetings].[Countries] VALUES ('IL', 'Israel')\nINSERT INTO [meetings].[Countries] VALUES ('IM', 'Isle of Man')\nINSERT INTO [meetings].[Countries] VALUES ('IN', 'India')\nINSERT INTO [meetings].[Countries] VALUES ('IO', 'British Indian Ocean Territory')\nINSERT INTO [meetings].[Countries] VALUES ('IQ', 'Iraq')\nINSERT INTO [meetings].[Countries] VALUES ('IR', 'Iran, Islamic Republic Of')\nINSERT INTO [meetings].[Countries] VALUES ('IS', 'Iceland')\nINSERT INTO [meetings].[Countries] VALUES ('IT', 'Italy')\nINSERT INTO [meetings].[Countries] VALUES ('JE', 'Jersey')\nINSERT INTO [meetings].[Countries] VALUES ('JM', 'Jamaica')\nINSERT INTO [meetings].[Countries] VALUES ('JO', 'Jordan')\nINSERT INTO [meetings].[Countries] VALUES ('JP', 'Japan')\nINSERT INTO [meetings].[Countries] VALUES ('KE', 'Kenya')\nINSERT INTO [meetings].[Countries] VALUES ('KG', 'Kyrgyzstan')\nINSERT INTO [meetings].[Countries] VALUES ('KH', 'Cambodia')\nINSERT INTO [meetings].[Countries] VALUES ('KI', 'Kiribati')\nINSERT INTO [meetings].[Countries] VALUES ('KM', 'Comoros')\nINSERT INTO [meetings].[Countries] VALUES ('KN', 'Saint Kitts and Nevis')\nINSERT INTO [meetings].[Countries] VALUES ('KP', 'Korea, Democratic PeopleS Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('KR', 'Korea, Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('KW', 'Kuwait')\nINSERT INTO [meetings].[Countries] VALUES ('KY', 'Cayman Islands')\nINSERT INTO [meetings].[Countries] VALUES ('KZ', 'Kazakhstan')\nINSERT INTO [meetings].[Countries] VALUES ('LA', 'Lao PeopleS Democratic Republic')\nINSERT INTO [meetings].[Countries] VALUES ('LB', 'Lebanon')\nINSERT INTO [meetings].[Countries] VALUES ('LC', 'Saint Lucia')\nINSERT INTO [meetings].[Countries] VALUES ('LI', 'Liechtenstein')\nINSERT INTO [meetings].[Countries] VALUES ('LK', 'Sri Lanka')\nINSERT INTO [meetings].[Countries] VALUES ('LR', 'Liberia')\nINSERT INTO [meetings].[Countries] VALUES ('LS', 'Lesotho')\nINSERT INTO [meetings].[Countries] VALUES ('LT', 'Lithuania')\nINSERT INTO [meetings].[Countries] VALUES ('LU', 'Luxembourg')\nINSERT INTO [meetings].[Countries] VALUES ('LV', 'Latvia')\nINSERT INTO [meetings].[Countries] VALUES ('LY', 'Libyan Arab Jamahiriya')\nINSERT INTO [meetings].[Countries] VALUES ('MA', 'Morocco')\nINSERT INTO [meetings].[Countries] VALUES ('MC', 'Monaco')\nINSERT INTO [meetings].[Countries] VALUES ('MD', 'Moldova, Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('ME', 'Montenegro')\nINSERT INTO [meetings].[Countries] VALUES ('MG', 'Madagascar')\nINSERT INTO [meetings].[Countries] VALUES ('MH', 'Marshall Islands')\nINSERT INTO [meetings].[Countries] VALUES ('MK', 'Macedonia, The Former Yugoslav Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('ML', 'Mali')\nINSERT INTO [meetings].[Countries] VALUES ('MM', 'Myanmar')\nINSERT INTO [meetings].[Countries] VALUES ('MN', 'Mongolia')\nINSERT INTO [meetings].[Countries] VALUES ('MO', 'Macao')\nINSERT INTO [meetings].[Countries] VALUES ('MP', 'Northern Mariana Islands')\nINSERT INTO [meetings].[Countries] VALUES ('MQ', 'Martinique')\nINSERT INTO [meetings].[Countries] VALUES ('MR', 'Mauritania')\nINSERT INTO [meetings].[Countries] VALUES ('MS', 'Montserrat')\nINSERT INTO [meetings].[Countries] VALUES ('MT', 'Malta')\nINSERT INTO [meetings].[Countries] VALUES ('MU', 'Mauritius')\nINSERT INTO [meetings].[Countries] VALUES ('MV', 'Maldives')\nINSERT INTO [meetings].[Countries] VALUES ('MW', 'Malawi')\nINSERT INTO [meetings].[Countries] VALUES ('MX', 'Mexico')\nINSERT INTO [meetings].[Countries] VALUES ('MY', 'Malaysia')\nINSERT INTO [meetings].[Countries] VALUES ('MZ', 'Mozambique')\nINSERT INTO [meetings].[Countries] VALUES ('NA', 'Namibia')\nINSERT INTO [meetings].[Countries] VALUES ('NC', 'New Caledonia')\nINSERT INTO [meetings].[Countries] VALUES ('NE', 'Niger')\nINSERT INTO [meetings].[Countries] VALUES ('NF', 'Norfolk Island')\nINSERT INTO [meetings].[Countries] VALUES ('NG', 'Nigeria')\nINSERT INTO [meetings].[Countries] VALUES ('NI', 'Nicaragua')\nINSERT INTO [meetings].[Countries] VALUES ('NL', 'Netherlands')\nINSERT INTO [meetings].[Countries] VALUES ('NO', 'Norway')\nINSERT INTO [meetings].[Countries] VALUES ('NP', 'Nepal')\nINSERT INTO [meetings].[Countries] VALUES ('NR', 'Nauru')\nINSERT INTO [meetings].[Countries] VALUES ('NU', 'Niue')\nINSERT INTO [meetings].[Countries] VALUES ('NZ', 'New Zealand')\nINSERT INTO [meetings].[Countries] VALUES ('OM', 'Oman')\nINSERT INTO [meetings].[Countries] VALUES ('PA', 'Panama')\nINSERT INTO [meetings].[Countries] VALUES ('PE', 'Peru')\nINSERT INTO [meetings].[Countries] VALUES ('PF', 'French Polynesia')\nINSERT INTO [meetings].[Countries] VALUES ('PG', 'Papua New Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('PH', 'Philippines')\nINSERT INTO [meetings].[Countries] VALUES ('PK', 'Pakistan')\nINSERT INTO [meetings].[Countries] VALUES ('PL', 'Poland')\nINSERT INTO [meetings].[Countries] VALUES ('PM', 'Saint Pierre and Miquelon')\nINSERT INTO [meetings].[Countries] VALUES ('PN', 'Pitcairn')\nINSERT INTO [meetings].[Countries] VALUES ('PR', 'Puerto Rico')\nINSERT INTO [meetings].[Countries] VALUES ('PS', 'Palestinian Territory, Occupied')\nINSERT INTO [meetings].[Countries] VALUES ('PT', 'Portugal')\nINSERT INTO [meetings].[Countries] VALUES ('PW', 'Palau')\nINSERT INTO [meetings].[Countries] VALUES ('PY', 'Paraguay')\nINSERT INTO [meetings].[Countries] VALUES ('QA', 'Qatar')\nINSERT INTO [meetings].[Countries] VALUES ('RE', 'Reunion')\nINSERT INTO [meetings].[Countries] VALUES ('RO', 'Romania')\nINSERT INTO [meetings].[Countries] VALUES ('RS', 'Serbia')\nINSERT INTO [meetings].[Countries] VALUES ('RU', 'Russian Federation')\nINSERT INTO [meetings].[Countries] VALUES ('RW', 'RWANDA')\nINSERT INTO [meetings].[Countries] VALUES ('SA', 'Saudi Arabia')\nINSERT INTO [meetings].[Countries] VALUES ('SB', 'Solomon Islands')\nINSERT INTO [meetings].[Countries] VALUES ('SC', 'Seychelles')\nINSERT INTO [meetings].[Countries] VALUES ('SD', 'Sudan')\nINSERT INTO [meetings].[Countries] VALUES ('SE', 'Sweden')\nINSERT INTO [meetings].[Countries] VALUES ('SG', 'Singapore')\nINSERT INTO [meetings].[Countries] VALUES ('SH', 'Saint Helena')\nINSERT INTO [meetings].[Countries] VALUES ('SI', 'Slovenia')\nINSERT INTO [meetings].[Countries] VALUES ('SJ', 'Svalbard and Jan Mayen')\nINSERT INTO [meetings].[Countries] VALUES ('SK', 'Slovakia')\nINSERT INTO [meetings].[Countries] VALUES ('SL', 'Sierra Leone')\nINSERT INTO [meetings].[Countries] VALUES ('SM', 'San Marino')\nINSERT INTO [meetings].[Countries] VALUES ('SN', 'Senegal')\nINSERT INTO [meetings].[Countries] VALUES ('SO', 'Somalia')\nINSERT INTO [meetings].[Countries] VALUES ('SR', 'Suriname')\nINSERT INTO [meetings].[Countries] VALUES ('ST', 'Sao Tome and Principe')\nINSERT INTO [meetings].[Countries] VALUES ('SV', 'El Salvador')\nINSERT INTO [meetings].[Countries] VALUES ('SY', 'Syrian Arab Republic')\nINSERT INTO [meetings].[Countries] VALUES ('SZ', 'Swaziland')\nINSERT INTO [meetings].[Countries] VALUES ('TC', 'Turks and Caicos Islands')\nINSERT INTO [meetings].[Countries] VALUES ('TD', 'Chad')\nINSERT INTO [meetings].[Countries] VALUES ('TF', 'French Southern Territories')\nINSERT INTO [meetings].[Countries] VALUES ('TG', 'Togo')\nINSERT INTO [meetings].[Countries] VALUES ('TH', 'Thailand')\nINSERT INTO [meetings].[Countries] VALUES ('TJ', 'Tajikistan')\nINSERT INTO [meetings].[Countries] VALUES ('TK', 'Tokelau')\nINSERT INTO [meetings].[Countries] VALUES ('TL', 'Timor-Leste')\nINSERT INTO [meetings].[Countries] VALUES ('TM', 'Turkmenistan')\nINSERT INTO [meetings].[Countries] VALUES ('TN', 'Tunisia')\nINSERT INTO [meetings].[Countries] VALUES ('TO', 'Tonga')\nINSERT INTO [meetings].[Countries] VALUES ('TR', 'Turkey')\nINSERT INTO [meetings].[Countries] VALUES ('TT', 'Trinidad and Tobago')\nINSERT INTO [meetings].[Countries] VALUES ('TV', 'Tuvalu')\nINSERT INTO [meetings].[Countries] VALUES ('TW', 'Taiwan, Province of China')\nINSERT INTO [meetings].[Countries] VALUES ('TZ', 'Tanzania, United Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('UA', 'Ukraine')\nINSERT INTO [meetings].[Countries] VALUES ('UG', 'Uganda')\nINSERT INTO [meetings].[Countries] VALUES ('UM', 'United States Minor Outlying Islands')\nINSERT INTO [meetings].[Countries] VALUES ('US', 'United States')\nINSERT INTO [meetings].[Countries] VALUES ('UY', 'Uruguay')\nINSERT INTO [meetings].[Countries] VALUES ('UZ', 'Uzbekistan')\nINSERT INTO [meetings].[Countries] VALUES ('VA', 'Holy See (Vatican City State)')\nINSERT INTO [meetings].[Countries] VALUES ('VC', 'Saint Vincent and the Grenadines')\nINSERT INTO [meetings].[Countries] VALUES ('VE', 'Venezuela')\nINSERT INTO [meetings].[Countries] VALUES ('VG', 'Virgin Islands, British')\nINSERT INTO [meetings].[Countries] VALUES ('VI', 'Virgin Islands, U.S.')\nINSERT INTO [meetings].[Countries] VALUES ('VN', 'Viet Nam')\nINSERT INTO [meetings].[Countries] VALUES ('VU', 'Vanuatu')\nINSERT INTO [meetings].[Countries] VALUES ('WF', 'Wallis and Futuna')\nINSERT INTO [meetings].[Countries] VALUES ('WS', 'Samoa')\nINSERT INTO [meetings].[Countries] VALUES ('YE', 'Yemen')\nINSERT INTO [meetings].[Countries] VALUES ('YT', 'Mayotte')\nINSERT INTO [meetings].[Countries] VALUES ('ZA', 'South Africa')\nINSERT INTO [meetings].[Countries] VALUES ('ZM', 'Zambia')\nINSERT INTO [meetings].[Countries] VALUES ('ZW', 'Zimbabwe')\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/Security/Schemas.sql",
    "content": "﻿CREATE SCHEMA app AUTHORIZATION dbo\nGO\n\nCREATE SCHEMA administration AUTHORIZATION dbo\nGO\n\nCREATE SCHEMA meetings AUTHORIZATION dbo\nGO\n\nCREATE SCHEMA users AUTHORIZATION dbo\nGO\n\nCREATE SCHEMA registrations AUTHORIZATION dbo\nGO\n\nCREATE SCHEMA payments AUTHORIZATION dbo\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Tables/InboxMessages.sql",
    "content": "﻿CREATE TABLE [administration].InboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_administration_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Tables/InternalCommands.sql",
    "content": "﻿CREATE TABLE [administration].InternalCommands\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_administration_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Tables/MeetingGroupProposals.sql",
    "content": "﻿CREATE TABLE [administration].[MeetingGroupProposals]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[Name] NVARCHAR(255) NOT NULL,\n\t[Description] VARCHAR(200) NULL,\n    [LocationCity] NVARCHAR(50) NOT NULL,\n    [LocationCountryCode] NVARCHAR(3) NOT NULL,\n    [ProposalUserId] UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate] DATETIME NOT NULL,\n    [StatusCode] NVARCHAR(50) NOT NULL,\n    [DecisionDate] DATETIME NULL,\n    [DecisionUserId] UNIQUEIDENTIFIER NULL,\n    [DecisionCode] NVARCHAR(50) NULL,\n    [DecisionRejectReason] NVARCHAR(250) NULL,\n\tCONSTRAINT [PK_administration_MeetingGroupProposals_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Tables/Members.sql",
    "content": "﻿CREATE TABLE [administration].[Members]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Login] NVARCHAR(100) NOT NULL,\n    [Email] NVARCHAR (255) NOT NULL,\n    [FirstName] NVARCHAR(50) NOT NULL,\n    [LastName] NVARCHAR(50) NOT NULL,\n    [Name] NVARCHAR (255) NOT NULL,\n    CONSTRAINT [PK_administration_Members_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Tables/OutboxMessages.sql",
    "content": "﻿CREATE TABLE [administration].OutboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_administration_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Views/v_MeetingGroupProposals.sql",
    "content": "﻿CREATE VIEW [administration].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode],\n    [MeetingGroupProposal].[DecisionDate],\n    [MeetingGroupProposal].[DecisionUserId],\n    [MeetingGroupProposal].[DecisionCode],\n    [MeetingGroupProposal].[DecisionRejectReason]\nFROM [administration].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/administration/Views/v_Members.sql",
    "content": "﻿CREATE VIEW [administration].[v_Members]\nAS\nSELECT\n    [Member].[Id],\n    [Member].[Login],\n    [Member].[Email],\n    [Member].[FirstName],\n    [Member].[LastName],\n    [Member].[Name]\nFROM [administration].[Members] AS [Member]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/app/Tables/Emails.sql",
    "content": "﻿CREATE TABLE [app].[Emails]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[From] NVARCHAR(255) NOT NULL,\n\t[To] NVARCHAR(255) NOT NULL,\n\t[Subject] NVARCHAR(255) NOT NULL,\n\t[Content] NVARCHAR(MAX) NOT NULL,\n\t[Date] DATETIME NOT NULL,\n\tCONSTRAINT [PK_app_Emails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n)\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/app/Tables/MigrationsJournal.sql",
    "content": "﻿CREATE TABLE [app].[MigrationsJournal](\n\t[Id] [int] IDENTITY(1, 1) NOT NULL,\n\t[ScriptName] NVARCHAR(255) NOT NULL,\n\t[Applied] DATETIME NOT NULL,\n CONSTRAINT [PK_app_MigrationsJournal_Id] PRIMARY KEY CLUSTERED \n(\n\t[Id] ASC\n))"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/Countries.sql",
    "content": "﻿CREATE TABLE [meetings].[Countries]\n(\n\t[Code] CHAR(2) NOT NULL,\n\t[Name] NVARCHAR(50) NOT NULL\n\tCONSTRAINT [PK_meetings_Countries_Code] PRIMARY KEY ([Code] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/InboxMessages.sql",
    "content": "﻿CREATE TABLE [meetings].InboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_meetings_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/InternalCommands.sql",
    "content": "﻿CREATE TABLE [meetings].InternalCommands\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_meetings_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingAttendees.sql",
    "content": "﻿CREATE TABLE meetings.MeetingAttendees\n(\n\t[MeetingId] UNIQUEIDENTIFIER NOT NULL,\n\t[AttendeeId] UNIQUEIDENTIFIER NOT NULL,\n\t[DecisionDate] DATETIME2 NOT NULL,\n\t[RoleCode] VARCHAR(50) NULL,   \n    [GuestsNumber] INT NULL,\n    [DecisionChanged] BIT NOT NULL,\n    [DecisionChangeDate] DATETIME2 NULL,\n\t[IsRemoved] BIT NOT NULL,\n\t[RemovingMemberId] UNIQUEIDENTIFIER NULL,\n\t[RemovingReason] NVARCHAR(500) NULL,\n\t[RemovedDate] DATETIME2 NULL,\n\t[BecameNotAttendeeDate] DATETIME2 NULL,\n\t[FeeValue] DECIMAL(5, 0) NULL,\n\t[FeeCurrency] VARCHAR(3) NULL,\n\t[IsFeePaid] BIT NOT NULL,\n\tCONSTRAINT [PK_meetings_MeetingAttendees_Id] PRIMARY KEY ([MeetingId] ASC, [AttendeeId] ASC, [DecisionDate] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingCommentingConfigurations.sql",
    "content": "﻿CREATE TABLE meetings.MeetingCommentingConfigurations\n(\n    [Id]                    UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [IsCommentingEnabled]   BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingCommentingConfigurations_Id] PRIMARY KEY ([Id] ASC),\n    CONSTRAINT [FK_meetings_MeetingCommentingConfigurations_Meetings] FOREIGN KEY ([MeetingId]) REFERENCES meetings.Meetings ([Id])\n);\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingComments.sql",
    "content": "﻿CREATE TABLE meetings.MeetingComments\n(\n    [Id]                    UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId]             UNIQUEIDENTIFIER NOT NULL,\n    [AuthorId]              UNIQUEIDENTIFIER NOT NULL,\n    [InReplyToCommentId]    UNIQUEIDENTIFIER NULL,\n    [Comment]               VARCHAR(300)     NULL,\n    [IsRemoved]             BIT              NOT NULL,\n    [RemovedByReason]       VARCHAR(300)     NULL,\n    [CreateDate]            DATETIME         NOT NULL,\n    [EditDate]              DATETIME         NULL,\n    [LikesCount]            INT              NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingComments_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingGroupMembers.sql",
    "content": "﻿CREATE TABLE meetings.MeetingGroupMembers\n(\n\t[MeetingGroupId] UNIQUEIDENTIFIER NOT NULL,\n\t[MemberId] UNIQUEIDENTIFIER NOT NULL,\n\t[JoinedDate] DATETIME2 NOT NULL,\n\t[RoleCode] VARCHAR(50) NOT NULL,   \n    [IsActive] BIT NOT NULL,\n    [LeaveDate] DATETIME NULL,\n\tCONSTRAINT [PK_meetings_MeetingGroupMembers_MeetingGroupId_MemberId_JoinedDate] PRIMARY KEY ([MeetingGroupId] ASC, [MemberId] ASC, [JoinedDate] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingGroupProposals.sql",
    "content": "﻿CREATE TABLE [meetings].[MeetingGroupProposals]\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[Name] NVARCHAR(255) NOT NULL,\n\t[Description] VARCHAR(200) NULL,\n    [LocationCity] NVARCHAR(50) NOT NULL,\n    [LocationCountryCode] NVARCHAR(3) NOT NULL,\n    [ProposalUserId] UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate] DATETIME NOT NULL,\n    [StatusCode] NVARCHAR(50) NOT NULL\n\tCONSTRAINT [PK_meetings_MeetingGroupProposals_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingGroups.sql",
    "content": "﻿CREATE TABLE meetings.MeetingGroups\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[Name] NVARCHAR(255) NOT NULL,\n\t[Description] VARCHAR(200) NULL,\n    [LocationCity] NVARCHAR(50) NOT NULL,\n    [LocationCountryCode] NVARCHAR(3) NOT NULL,\n    [CreatorId] UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate] DATETIME NOT NULL,\n\t[PaymentDateTo] DATE NULL,\n\tCONSTRAINT [PK_meetings_MeetingGroups_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingMemberCommentLikes.sql",
    "content": "﻿CREATE TABLE [meetings].[MeetingMemberCommentLikes]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]  UNIQUEIDENTIFIER NOT NULL,\n    [MeetingCommentId] UNIQUEIDENTIFIER NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingMemberCommentLikes_Id] PRIMARY KEY ([Id] ASC),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_Members] FOREIGN KEY ([MemberId]) REFERENCES meetings.Members ([Id]),\n    CONSTRAINT [FK_meetings_MeetingMemberCommentLikes_MeetingComments] FOREIGN KEY ([MeetingCommentId]) REFERENCES meetings.MeetingComments ([Id])\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingNotAttendees.sql",
    "content": "﻿CREATE TABLE meetings.MeetingNotAttendees\n(\n\t[MeetingId] UNIQUEIDENTIFIER NOT NULL,\n\t[MemberId] UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate] DATETIME2 NOT NULL,\n    [DecisionChanged] BIT NOT NULL,\n    [DecisionChangeDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_meetings_MeetingNotAttendees_Id] PRIMARY KEY ([MeetingId] ASC, [MemberId] ASC, [DecisionDate] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MeetingWaitlistMembers.sql",
    "content": "﻿CREATE TABLE meetings.MeetingWaitlistMembers\n(\n\t[MeetingId] UNIQUEIDENTIFIER NOT NULL,\n\t[MemberId] UNIQUEIDENTIFIER NOT NULL,\n    [SignUpDate] DATETIME2 NOT NULL,\n    [IsSignedOff] BIT NOT NULL,\n    [SignOffDate] DATETIME2 NULL,\n    [IsMovedToAttendees] BIT NOT NULL,\n    [MovedToAttendeesDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_meetings_MeetingWaitlistMembers_MeetingId_MemberId_SignUpDate] PRIMARY KEY ([MeetingId] ASC, [MemberId] ASC, [SignUpDate] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/Meetings.sql",
    "content": "﻿CREATE TABLE meetings.Meetings\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [MeetingGroupId] UNIQUEIDENTIFIER NOT NULL,\n    [CreatorId] UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate] DATETIME2 NOT NULL,\n    [Title] NVARCHAR(200) NOT NULL,\n    [Description] NVARCHAR(4000) NOT NULL,\n    [TermStartDate] DATETIME NOT NULL,\n    [TermEndDate] DATETIME NOT NULL,\n    [LocationName] NVARCHAR(200) NOT NULL,\n    [LocationAddress] NVARCHAR(200) NOT NULL,\n    [LocationPostalCode] NVARCHAR(200) NULL,\n    [LocationCity] NVARCHAR(50) NOT NULL,\n    [AttendeesLimit] INT NULL,\n    [GuestsLimit] INT NOT NULL,\n    [RSVPTermStartDate] DATETIME NULL,\n    [RSVPTermEndDate] DATETIME NULL,\n    [EventFeeValue] DECIMAL(5, 0) NULL,\n    [EventFeeCurrency] VARCHAR(3) NULL,\n\t[ChangeDate] DATETIME2 NULL,\n\t[ChangeMemberId] UNIQUEIDENTIFIER NULL,\n\t[CancelDate] DATETIME NULL,\n\t[CancelMemberId] UNIQUEIDENTIFIER NULL,\n\t[IsCanceled] BIT NOT NULL,\n\tCONSTRAINT [PK_meetings_Meetings_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/MemberSubscriptions.sql",
    "content": "﻿CREATE TABLE [meetings].[MemberSubscriptions]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [ExpirationDate] DATETIME NOT NULL,\n    CONSTRAINT [PK_meetings_MemberSubscriptions_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/Members.sql",
    "content": "﻿CREATE TABLE [meetings].[Members]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Login] NVARCHAR(100) NOT NULL,\n    [Email] NVARCHAR (255) NOT NULL,\n    [FirstName] NVARCHAR(50) NOT NULL,\n    [LastName] NVARCHAR(50) NOT NULL,\n    [Name] NVARCHAR (255) NOT NULL,\n    CONSTRAINT [PK_meetings_Members_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Tables/OutboxMessages.sql",
    "content": "﻿CREATE TABLE [meetings].OutboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_meetings_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_Countries.sql",
    "content": "﻿CREATE VIEW [meetings].[v_Countriess]\nAS\nSELECT\n    [Country].[Code],\n    [Country].[Name]\nFROM meetings.Countries AS [Country]\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingAttendees.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingAttendees]\nAS\nSELECT\n    [MeetingAttendee].[MeetingId],\n    [MeetingAttendee].[AttendeeId],\n    [MeetingAttendee].[DecisionDate],\n    [MeetingAttendee].[RoleCode],\n    [MeetingAttendee].[GuestsNumber],\n\n    [Member].[FirstName],\n    [Member].[LastName]\nFROM [meetings].[MeetingAttendees] AS [MeetingAttendee]\n    INNER JOIN [meetings].[Members] AS [Member]\n        ON [MeetingAttendee].[AttendeeId] = [Member].[Id]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingComments.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingComments]\nAS\nSELECT\n    [MeetingComments].Id,\n    [MeetingComments].MeetingId,\n    [MeetingComments].AuthorId,\n    [MeetingComments].InReplyToCommentId,\n    [MeetingComments].Comment,\n    [MeetingComments].CreateDate,\n    [MeetingComments].EditDate\nFROM [meetings].[MeetingComments] AS [MeetingComments]\nWHERE [MeetingComments].IsRemoved = 0\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingDetails.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingDetails]\nAS\nSELECT\n    [Meeting].[Id],\n    [Meeting].[MeetingGroupId],\n    [Meeting].[Title],\n    [Meeting].[TermStartDate],\n    [Meeting].[TermEndDate],\n    [Meeting].[Description],\n    [Meeting].[LocationName],\n    [Meeting].[LocationAddress],\n    [Meeting].[LocationPostalCode],\n    [Meeting].[LocationCity],\n    [Meeting].[AttendeesLimit],\n    [Meeting].[GuestsLimit],\n    [Meeting].[RSVPTermStartDate],\n    [Meeting].[RSVPTermEndDate],\n    [Meeting].[EventFeeValue],\n    [Meeting].[EventFeeCurrency]\nFROM [meetings].[Meetings] AS [Meeting]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingGroupMembers.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingGroupMembers]\nAS\nSELECT\n    [MeetingGroupMember].MeetingGroupId,\n    [MeetingGroupMember].MemberId,\n    [MeetingGroupMember].RoleCode\nFROM meetings.MeetingGroupMembers AS [MeetingGroupMember]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingGroupProposals.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode]\nFROM [meetings].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MeetingGroups.sql",
    "content": "﻿\nCREATE VIEW [meetings].[v_MeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity]\nFROM meetings.MeetingGroups AS [MeetingGroup]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_Meetings.sql",
    "content": "﻿\nCREATE VIEW [meetings].[v_Meetings]\nAS\nSELECT\n\tMeeting.[Id],\n    Meeting.[Title],\n    Meeting.[Description],\n    Meeting.LocationAddress,\n    Meeting.LocationCity,\n    Meeting.LocationPostalCode,\n    Meeting.TermStartDate,\n    Meeting.TermEndDate\nFROM meetings.Meetings AS [Meeting]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MemberMeetingGroups.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MemberMeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity],\n\n    [MeetingGroupMember].[MemberId],\n    [MeetingGroupMember].[RoleCode],\n    [MeetingGroupMember].[IsActive],\n    [MeetingGroupMember].[JoinedDate]\nFROM meetings.MeetingGroups AS [MeetingGroup]\n    INNER JOIN [meetings].[MeetingGroupMembers] AS [MeetingGroupMember]\n        ON [MeetingGroup].[Id] = [MeetingGroupMember].[MeetingGroupId]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_MemberMeetings.sql",
    "content": "﻿CREATE VIEW [meetings].[v_MemberMeetings]\nAS\nSELECT\n\t[Meeting].[Id],\n    [Meeting].[Title],\n    [Meeting].[Description],\n    [Meeting].[LocationAddress],\n    [Meeting].[LocationCity],\n    [Meeting].[LocationPostalCode],\n    [Meeting].[TermStartDate],\n    [Meeting].[TermEndDate],\n\n    [MeetingAttendee].[AttendeeId],\n    [MeetingAttendee].[IsRemoved],\n    [MeetingAttendee].[RoleCode]\nFROM [meetings].[Meetings] AS [Meeting]\n    INNER JOIN [meetings].[MeetingAttendees] AS [MeetingAttendee]\n        ON [Meeting].[Id] = [MeetingAttendee].[MeetingId]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/meetings/Views/v_Members.sql",
    "content": "﻿CREATE VIEW [meetings].[v_Members]\nAS\nSELECT\n    [Member].Id,\n    [Member].[Name],\n    [Member].[Login],\n    [Member].[Email]\nFROM meetings.Members AS [Member]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/InboxMessages.sql",
    "content": "﻿CREATE TABLE [payments].InboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_payments_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/InternalCommands.sql",
    "content": "﻿CREATE TABLE [payments].InternalCommands\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_payments_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/MeetingFees.sql",
    "content": "﻿CREATE TABLE [payments].[MeetingFees]\n(\n    [MeetingFeeId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId] UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId] UNIQUEIDENTIFIER NOT NULL,\n    [FeeValue] DECIMAL(18, 2) NOT NULL,\n    [FeeCurrency] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    CONSTRAINT [PK_payments_MeetingFees_MeetingFeeId] PRIMARY KEY ([MeetingFeeId] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/Messages.sql",
    "content": "﻿CREATE TABLE payments.[Messages]\n(\n    StreamIdInternal    INT                                     NOT NULL,\n    StreamVersion       INT                                     NOT NULL,\n    Position            BIGINT                 IDENTITY(0,1)    NOT NULL,\n    Id                  UNIQUEIDENTIFIER                        NOT NULL,\n    Created             DATETIME                                NOT NULL,\n    [Type]              NVARCHAR(128)                           NOT NULL,\n    JsonData            NVARCHAR(max)                           NOT NULL,\n    JsonMetadata        NVARCHAR(max)                                   ,\n    CONSTRAINT PK_Events PRIMARY KEY NONCLUSTERED (Position),\n    CONSTRAINT FK_Events_Streams FOREIGN KEY (StreamIdInternal) REFERENCES payments.Streams(IdInternal)\n);\nGO\n\nCREATE UNIQUE NONCLUSTERED INDEX IX_Messages_Position ON payments.Messages (Position);\nGO\n\nCREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Id ON payments.Messages (StreamIdInternal, Id);\nGO\n\nCREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Revision ON payments.Messages (StreamIdInternal, StreamVersion);\nGO\n\nCREATE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Created ON payments.Messages (StreamIdInternal, Created);\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/OutboxMessages.sql",
    "content": "﻿CREATE TABLE [payments].OutboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_payments_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/Payers.sql",
    "content": "﻿CREATE TABLE [payments].[Payers]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Login] NVARCHAR(100) NOT NULL,\n    [Email] NVARCHAR (255) NOT NULL,\n    [FirstName] NVARCHAR(50) NOT NULL,\n    [LastName] NVARCHAR(50) NOT NULL,\n    [Name] NVARCHAR (255) NOT NULL,\n    CONSTRAINT [PK_payments_Payers_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/PriceListItems.sql",
    "content": "﻿CREATE TABLE payments.PriceListItems\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [SubscriptionPeriodCode] VARCHAR(50) NOT NULL,\n    [CategoryCode] VARCHAR(50) NOT NULL,\n    [CountryCode] VARCHAR(50) NOT NULL,\n    [MoneyValue] DECIMAL(18, 2) NOT NULL,\n    [MoneyCurrency] VARCHAR(50) NOT NULL,\n    [IsActive] BIT NOT NULL\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/Streams.sql",
    "content": "﻿CREATE TABLE payments.Streams\n(\n    Id                  CHAR(42)                                NOT NULL,\n    IdOriginal          NVARCHAR(1000)                          NOT NULL,\n    IdInternal          INT                 IDENTITY(1,1)       NOT NULL,\n    [Version]           INT   CONSTRAINT DF_payments_Streams_Version DEFAULT(-1) NOT NULL,\n    Position            BIGINT CONSTRAINT DF_payments_Streams_Position DEFAULT(-1) NOT NULL,\n    CONSTRAINT PK_Streams PRIMARY KEY CLUSTERED (IdInternal)\n);\nGO\n\nCREATE UNIQUE NONCLUSTERED INDEX IX_Streams_Id ON payments.Streams (Id);\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/SubscriptionCheckpoints.sql",
    "content": "﻿CREATE TABLE payments.SubscriptionCheckpoints\n(\n    [Code] VARCHAR(50) NOT NULL,\n    [Position] BIGINT NOT NULL\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/SubscriptionDetails.sql",
    "content": "﻿CREATE TABLE payments.SubscriptionDetails\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId] UNIQUEIDENTIFIER NOT NULL,\n    [Period] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    [CountryCode] VARCHAR(50) NOT NULL,\n    [ExpirationDate] DATETIME NOT NULL,\n    CONSTRAINT [PK_payments_SubscriptionDetails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Tables/SubscriptionPayments.sql",
    "content": "﻿CREATE TABLE payments.SubscriptionPayments\n(\n    [PaymentId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId] UNIQUEIDENTIFIER NOT NULL,\n    [Type] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    [Period] VARCHAR(50) NOT NULL,\n    [Date] DATETIME NOT NULL,\n    [SubscriptionId] UNIQUEIDENTIFIER NULL,\n    [MoneyValue] DECIMAL(18, 2) NOT NULL,\n    [MoneyCurrency] VARCHAR(50) NOT NULL\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/payments/Types/NewStreamMessages.sql",
    "content": "﻿CREATE TYPE payments.NewStreamMessages AS TABLE (\n    StreamVersion       INT IDENTITY(0,1)                       NOT NULL,\n    Id                  UNIQUEIDENTIFIER                        NOT NULL,\n    Created             DATETIME          DEFAULT(GETUTCDATE()) NOT NULL,\n    [Type]              NVARCHAR(128)                           NOT NULL,\n    JsonData            NVARCHAR(max)                           NULL,\n    JsonMetadata        NVARCHAR(max)                           NULL\n);\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/registrations/Tables/InboxMessages.sql",
    "content": "﻿CREATE TABLE [registrations].InboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_registrations_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/registrations/Tables/InternalCommands.sql",
    "content": "﻿CREATE TABLE [registrations].InternalCommands\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_registrations_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/registrations/Tables/OutboxMessages.sql",
    "content": "﻿CREATE TABLE [registrations].OutboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_registrations_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO\n"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/registrations/Tables/UserRegistrations.sql",
    "content": "﻿CREATE TABLE [registrations].[UserRegistrations]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Login] NVARCHAR(100) NOT NULL,\n    [Email] NVARCHAR (255) NOT NULL,\n    [Password] NVARCHAR(255) NOT NULL,\n    [FirstName] NVARCHAR(50) NOT NULL,\n    [LastName] NVARCHAR(50) NOT NULL,\n    [Name] NVARCHAR (255) NOT NULL,\n\t[StatusCode] VARCHAR(50) NOT NULL,\n\t[RegisterDate] DATETIME NOT NULL,\n\t[ConfirmedDate] DATETIME NULL,\n    CONSTRAINT [PK_registrations_UserRegistrations_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/registrations/Views/v_UserRegistrations.sql",
    "content": "﻿CREATE VIEW [registrations].[v_UserRegistrations]\nAS\nSELECT\n    [UserRegistration].[Id],\n    [UserRegistration].[Login],\n    [UserRegistration].[Email],\n    [UserRegistration].[FirstName],\n    [UserRegistration].[LastName],\n    [UserRegistration].[Name],\n    [UserRegistration].[StatusCode],\n    [UserRegistration].[Password]\nFROM [registrations].[UserRegistrations] AS [UserRegistration]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/InboxMessages.sql",
    "content": "﻿CREATE TABLE [users].InboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_users_InboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/InternalCommands.sql",
    "content": "﻿CREATE TABLE [users].InternalCommands\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[EnqueueDate] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\t[Error] NVARCHAR(MAX) NULL,\n\tCONSTRAINT [PK_users_InternalCommands_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/OutboxMessages.sql",
    "content": "﻿CREATE TABLE [users].OutboxMessages\n(\n\t[Id] UNIQUEIDENTIFIER NOT NULL,\n\t[OccurredOn] DATETIME2 NOT NULL,\n\t[Type] VARCHAR(255) NOT NULL,\n\t[Data] VARCHAR(MAX) NOT NULL,\n\t[ProcessedDate] DATETIME2 NULL,\n\tCONSTRAINT [PK_users_OutboxMessages_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/Permissions.sql",
    "content": "﻿CREATE TABLE [users].[Permissions]\n(\n\t[Code] VARCHAR(50) NOT NULL,\n\t[Name] VARCHAR(100) NOT NULL,\n\t[Description] [varchar](255) NULL,\n\tCONSTRAINT [PK_users_Permissions_Code] PRIMARY KEY ([Code] ASC)\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/RolesToPermissions.sql",
    "content": "﻿CREATE TABLE [users].[RolesToPermissions]\n(\n\t[RoleCode] VARCHAR(50) NOT NULL,\n\t[PermissionCode] VARCHAR(50) NOT NULL,\n\tCONSTRAINT [PK_RolesToPermissions_RoleCode_PermissionCode] PRIMARY KEY (RoleCode ASC, PermissionCode ASC)\n)"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/UserRoles.sql",
    "content": "﻿CREATE TABLE [users].[UserRoles]\n(\n    [UserId] UNIQUEIDENTIFIER NOT NULL,\n    [RoleCode] NVARCHAR(50)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Tables/Users.sql",
    "content": "﻿CREATE TABLE [users].[Users]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Login] NVARCHAR(100) NOT NULL,\n    [Email] NVARCHAR (255) NOT NULL,\n    [Password] NVARCHAR(255) NOT NULL,\n    [IsActive] BIT NOT NULL,\n    [FirstName] NVARCHAR(50) NOT NULL,\n    [LastName] NVARCHAR(50) NOT NULL,\n    [Name] NVARCHAR (255) NOT NULL,\n    CONSTRAINT [PK_users_Users_Id] PRIMARY KEY ([Id] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Views/v_UserPermissions.sql",
    "content": "﻿CREATE VIEW [users].[v_UserPermissions]\nAS\nSELECT \n\tDISTINCT\n\t[UserRole].UserId,\n\t[RolesToPermission].PermissionCode\nFROM [users].UserRoles AS [UserRole]\n\tINNER JOIN [users].RolesToPermissions AS [RolesToPermission]\n\t\tON [UserRole].RoleCode = [RolesToPermission].RoleCode\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Views/v_UserRoles.sql",
    "content": "﻿CREATE VIEW [users].[v_UserRoles]\nAS\nSELECT\n    [UserRole].[UserId],\n    [UserRole].[RoleCode]\nFROM [users].[UserRoles] AS [UserRole]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database/Structure/users/Views/v_Users.sql",
    "content": "﻿CREATE VIEW [users].[v_Users]\nAS\nSELECT\n    [User].[Id],\n    [User].[IsActive],\n    [User].[Login],\n    [User].[Password],\n    [User].[Email],\n    [User].[Name]\nFROM [users].[Users] AS [User]\nGO"
  },
  {
    "path": "src/Database/CompanyName.MyMeetings.Database.Build/CompanyName.MyMeetings.Database.Build.csproj",
    "content": "<Project Sdk=\"MSBuild.Sdk.SqlProj/2.6.1\">\n  <PropertyGroup>\n    <SqlServerVersion>Sql130</SqlServerVersion>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n  </PropertyGroup>\n  <ItemGroup>\n    <Content Include=\"..\\CompanyName.MyMeetings.Database\\Structure\\**\\*.sql\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Database/DatabaseMigrator/.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"
  },
  {
    "path": "src/Database/DatabaseMigrator/DatabaseMigrator.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/Database/DatabaseMigrator/Program.cs",
    "content": "﻿using DbUp;\nusing DbUp.ScriptProviders;\nusing Serilog;\nusing Serilog.Formatting.Compact;\n\nnamespace DatabaseMigrator\n{\n    public class Program\n    {\n        public static int Main(string[] args)\n        {\n            var logsPath = \"logs\\\\migration-logs\";\n\n            ILogger logger = new LoggerConfiguration()\n                .WriteTo.Console()\n                .WriteTo.File(new CompactJsonFormatter(), logsPath)\n                .CreateLogger();\n\n            logger.Information(\"Logger configured. Starting migration...\");\n\n            if (args.Length != 2)\n            {\n                logger.Error(\"Invalid arguments. Execution: DatabaseMigrator [connectionString] [pathToScripts].\");\n\n                logger.Information(\"Migration stopped\");\n\n                return -1;\n            }\n\n            var connectionString = args[0];\n\n            var scriptsPath = args[1];\n\n            if (!Directory.Exists(scriptsPath))\n            {\n                logger.Information($\"Directory {scriptsPath} does not exist\");\n\n                return -1;\n            }\n\n            var serilogUpgradeLog = new SerilogUpgradeLog(logger);\n\n            var upgrader =\n                DeployChanges.To\n                    .SqlDatabase(connectionString)\n                    .WithScriptsFromFileSystem(scriptsPath, new FileSystemScriptOptions\n                    {\n                        IncludeSubDirectories = true\n                    })\n                    .LogTo(serilogUpgradeLog)\n                    .JournalToSqlTable(\"app\", \"MigrationsJournal\")\n                    .Build();\n\n            var result = upgrader.PerformUpgrade();\n\n            if (!result.Successful)\n            {\n                logger.Information(\"Migration failed\");\n\n                return -1;\n            }\n\n            logger.Information(\"Migration successful\");\n\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Database/DatabaseMigrator/SerilogUpgradeLog.cs",
    "content": "﻿using DbUp.Engine.Output;\nusing Serilog;\n\nnamespace DatabaseMigrator\n{\n    internal class SerilogUpgradeLog : IUpgradeLog\n    {\n        private readonly ILogger _logger;\n\n        public SerilogUpgradeLog(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public void WriteInformation(string format, params object[] args)\n        {\n            _logger.Information(format, args);\n        }\n\n        public void WriteError(string format, params object[] args)\n        {\n            _logger.Error(format, args);\n        }\n\n        public void WriteWarning(string format, params object[] args)\n        {\n            _logger.Warning(format, args);\n        }\n    }\n}"
  },
  {
    "path": "src/Database/Dockerfile",
    "content": "FROM mcr.microsoft.com/mssql/server:2022-latest\n\nCOPY ./CompanyName.MyMeetings.Database/Scripts/CreateDatabase_Linux.sql /scripts/\n\nENV ACCEPT_EULA=Y\nENV SA_PASSWORD=Test@12345\nENV MSSQL_PID=Express\nENV MSSQL_TCP_PORT=1433\n\nADD entrypoint.sh /\nENTRYPOINT [\"/bin/bash\", \"/entrypoint.sh\"]"
  },
  {
    "path": "src/Database/Dockerfile_DatabaseMigrator",
    "content": "FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base\nWORKDIR /app\n\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build\nWORKDIR /src\n\nCOPY [\"./Database/DatabaseMigrator/DatabaseMigrator.csproj\", \"DatabaseMigrator.csproj\"]\nCOPY [\"Directory.Packages.props\", \"Directory.Packages.props\"]\nCOPY [\"Directory.Build.targets\", \"Directory.Build.targets\"]\nCOPY [\"Directory.Build.props\", \"Directory.Build.props\"]\nCOPY [\"stylecop.json\", \"stylecop.json\"]\nCOPY [\".editorconfig\", \".editorconfig\"]\n\nRUN dotnet restore \"DatabaseMigrator.csproj\"\n\nCOPY ./Database/ .\n\nWORKDIR \"/src\"\nRUN dotnet build \"DatabaseMigrator.csproj\" -c Release -o /app/build\n\nFROM build AS publish\nRUN dotnet publish \"DatabaseMigrator.csproj\" -c Release -o /app/publish\n\nFROM base AS final\nWORKDIR /app\nCOPY --from=publish /app/publish .\n\nADD ./Database/entrypoint_DatabaseMigrator.sh /\nADD ./Database/CompanyName.MyMeetings.Database/Scripts/Migrations /migrations/\n\n# Copy wait-for-it.sh into our image\nCOPY ./Database/wait-for-it.sh wait-for-it.sh\n# Make it executable, in Linux\nRUN chmod +x wait-for-it.sh\n\n#ENTRYPOINT [\"/bin/bash\", \"/entrypoint_DatabaseMigrator.sh\"]\n"
  },
  {
    "path": "src/Database/InitializeDatabase.sql",
    "content": "﻿\nGO\nPRINT N'Creating [administration]...';\n\n\nGO\nCREATE SCHEMA [administration]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [meetings]...';\n\n\nGO\nCREATE SCHEMA [meetings]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [payments]...';\n\n\nGO\nCREATE SCHEMA [payments]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [users]...';\n\n\nGO\nCREATE SCHEMA [users]\n    AUTHORIZATION [dbo];\n\n\nGO\nPRINT N'Creating [administration].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [administration].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error] NVARCHAR(MAX) NULL,\n    CONSTRAINT [PK_administration_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [administration].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_administration_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [administration].[MeetingGroupProposals] (\n    [Id]                   UNIQUEIDENTIFIER NOT NULL,\n    [Name]                 NVARCHAR (255)   NOT NULL,\n    [Description]          VARCHAR (200)    NULL,\n    [LocationCity]         NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode]  NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]       UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]         DATETIME         NOT NULL,\n    [StatusCode]           NVARCHAR (50)    NOT NULL,\n    [DecisionDate]         DATETIME         NULL,\n    [DecisionUserId]       UNIQUEIDENTIFIER NULL,\n    [DecisionCode]         NVARCHAR (50)    NULL,\n    [DecisionRejectReason] NVARCHAR (250)   NULL,\n    CONSTRAINT [PK_administration_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [administration].[Members]...';\n\n\nGO\nCREATE TABLE [administration].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_administration_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingWaitlistMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingWaitlistMembers] (\n    [MeetingId]            UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]             UNIQUEIDENTIFIER NOT NULL,\n    [SignUpDate]           DATETIME2 (7)    NOT NULL,\n    [IsSignedOff]          BIT              NOT NULL,\n    [SignOffDate]          DATETIME2 (7)    NULL,\n    [IsMovedToAttendees]   BIT              NOT NULL,\n    [MovedToAttendeesDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingWaitlistMembers_MeetingId_MemberId_SignUpDate] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [SignUpDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingNotAttendees]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingNotAttendees] (\n    [MeetingId]          UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]           UNIQUEIDENTIFIER NOT NULL,\n    [DecisionDate]       DATETIME2 (7)    NOT NULL,\n    [DecisionChanged]    BIT              NOT NULL,\n    [DecisionChangeDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_MeetingNotAttendees_Id] PRIMARY KEY CLUSTERED ([MeetingId] ASC, [MemberId] ASC, [DecisionDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingAttendees]...';\n\n\nGO\nCREATE TABLE meetings.MeetingAttendees\n(\n\t[MeetingId] UNIQUEIDENTIFIER NOT NULL,\n\t[AttendeeId] UNIQUEIDENTIFIER NOT NULL,\n\t[DecisionDate] DATETIME2 NOT NULL,\n\t[RoleCode] VARCHAR(50) NULL,   \n    [GuestsNumber] INT NULL,\n    [DecisionChanged] BIT NOT NULL,\n    [DecisionChangeDate] DATETIME2 NULL,\n\t[IsRemoved] BIT NOT NULL,\n\t[RemovingMemberId] UNIQUEIDENTIFIER NULL,\n\t[RemovingReason] NVARCHAR(500) NULL,\n\t[RemovedDate] DATETIME2 NULL,\n\t[BecameNotAttendeeDate] DATETIME2 NULL,\n\t[FeeValue] DECIMAL(5, 0) NULL,\n    [FeeCurrency] VARCHAR(3) NULL,\n\t[IsFeePaid] BIT NOT NULL,\n\tCONSTRAINT [PK_meetings_MeetingAttendees_Id] PRIMARY KEY ([MeetingId] ASC, [AttendeeId] ASC, [DecisionDate] ASC)\n)\nGO\n\n\nGO\nPRINT N'Creating [meetings].[Meetings]...';\n\n\nGO\nCREATE TABLE [meetings].[Meetings] (\n    [Id]                 UNIQUEIDENTIFIER NOT NULL,\n    [MeetingGroupId]     UNIQUEIDENTIFIER NOT NULL,\n    [CreatorId]          UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]         DATETIME2 (7)    NOT NULL,\n    [Title]              NVARCHAR (200)   NOT NULL,\n    [Description]        NVARCHAR (4000)  NOT NULL,\n    [TermStartDate]      DATETIME         NOT NULL,\n    [TermEndDate]        DATETIME         NOT NULL,\n    [LocationName]       NVARCHAR (200)   NOT NULL,\n    [LocationAddress]    NVARCHAR (200)   NOT NULL,\n    [LocationPostalCode] NVARCHAR (200)   NULL,\n    [LocationCity]       NVARCHAR (50)    NOT NULL,\n    [AttendeesLimit]     INT              NULL,\n    [GuestsLimit]        INT              NOT NULL,\n    [RSVPTermStartDate]  DATETIME         NULL,\n    [RSVPTermEndDate]    DATETIME         NULL,\n    [EventFeeValue]      DECIMAL (5)      NULL,\n    [EventFeeCurrency]   VARCHAR (3)      NULL,\n    [ChangeDate]         DATETIME2 (7)    NULL,\n    [ChangeMemberId]     UNIQUEIDENTIFIER NULL,\n    [CancelDate]         DATETIME         NULL,\n    [CancelMemberId]     UNIQUEIDENTIFIER NULL,\n    [IsCanceled]         BIT              NOT NULL,\n    CONSTRAINT [PK_meetings_Meetings_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupMembers]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupMembers] (\n    [MeetingGroupId] UNIQUEIDENTIFIER NOT NULL,\n    [MemberId]       UNIQUEIDENTIFIER NOT NULL,\n    [JoinedDate]     DATETIME2 (7)    NOT NULL,\n    [RoleCode]       VARCHAR (50)     NOT NULL,\n    [IsActive]       BIT              NOT NULL,\n    [LeaveDate]      DATETIME         NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupMembers_MeetingGroupId_MemberId_JoinedDate] PRIMARY KEY CLUSTERED ([MeetingGroupId] ASC, [MemberId] ASC, [JoinedDate] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroups]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroups] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [CreatorId]           UNIQUEIDENTIFIER NOT NULL,\n    [CreateDate]          DATETIME         NOT NULL,\n    [PaymentDateTo]       DATE             NULL,\n    CONSTRAINT [PK_meetings_MeetingGroups_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[Members]...';\n\n\nGO\nCREATE TABLE [meetings].[Members] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_meetings_Members_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[MeetingGroupProposals]...';\n\n\nGO\nCREATE TABLE [meetings].[MeetingGroupProposals] (\n    [Id]                  UNIQUEIDENTIFIER NOT NULL,\n    [Name]                NVARCHAR (255)   NOT NULL,\n    [Description]         VARCHAR (200)    NULL,\n    [LocationCity]        NVARCHAR (50)    NOT NULL,\n    [LocationCountryCode] NVARCHAR (3)     NOT NULL,\n    [ProposalUserId]      UNIQUEIDENTIFIER NOT NULL,\n    [ProposalDate]        DATETIME         NOT NULL,\n    [StatusCode]          NVARCHAR (50)    NOT NULL,\n    CONSTRAINT [PK_meetings_MeetingGroupProposals_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [meetings].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error] NVARCHAR(MAX) NULL,\n    CONSTRAINT [PK_meetings_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [meetings].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_meetings_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\n\nPRINT N'Creating [payments].[Payers]...';\n\n\nGO\nCREATE TABLE [payments].[Payers] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_payments_Payers_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\nGO\n\n\nPRINT N'Creating [payments].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [payments].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error] NVARCHAR(MAX) NULL,\n    CONSTRAINT [PK_payments_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [payments].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [payments].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_payments_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[InboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[InboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_InboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[UserRoles]...';\n\n\nGO\nCREATE TABLE [users].[UserRoles] (\n    [UserId]   UNIQUEIDENTIFIER NOT NULL,\n    [RoleCode] NVARCHAR (50)    NULL\n);\n\n\nGO\nPRINT N'Creating [users].[UserRegistrations]...';\n\n\nGO\nCREATE TABLE [users].[UserRegistrations] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [Login]         NVARCHAR (100)   NOT NULL,\n    [Email]         NVARCHAR (255)   NOT NULL,\n    [Password]      NVARCHAR (255)   NOT NULL,\n    [FirstName]     NVARCHAR (50)    NOT NULL,\n    [LastName]      NVARCHAR (50)    NOT NULL,\n    [Name]          NVARCHAR (255)   NOT NULL,\n    [StatusCode]    VARCHAR (50)     NOT NULL,\n    [RegisterDate]  DATETIME         NOT NULL,\n    [ConfirmedDate] DATETIME         NULL,\n    CONSTRAINT [PK_users_UserRegistrations_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Users]...';\n\n\nGO\nCREATE TABLE [users].[Users] (\n    [Id]        UNIQUEIDENTIFIER NOT NULL,\n    [Login]     NVARCHAR (100)   NOT NULL,\n    [Email]     NVARCHAR (255)   NOT NULL,\n    [Password]  NVARCHAR (255)   NOT NULL,\n    [IsActive]  BIT              NOT NULL,\n    [FirstName] NVARCHAR (50)    NOT NULL,\n    [LastName]  NVARCHAR (50)    NOT NULL,\n    [Name]      NVARCHAR (255)   NOT NULL,\n    CONSTRAINT [PK_users_Users_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[RolesToPermissions]...';\n\n\nGO\nCREATE TABLE [users].[RolesToPermissions] (\n    [RoleCode]       VARCHAR (50) NOT NULL,\n    [PermissionCode] VARCHAR (50) NOT NULL,\n    CONSTRAINT [PK_RolesToPermissions_RoleCode_PermissionCode] PRIMARY KEY CLUSTERED ([RoleCode] ASC, [PermissionCode] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[Permissions]...';\n\n\nGO\nCREATE TABLE [users].[Permissions] (\n    [Code]        VARCHAR (50)  NOT NULL,\n    [Name]        VARCHAR (100) NOT NULL,\n    [Description] VARCHAR (255) NULL,\n    CONSTRAINT [PK_users_Permissions_Code] PRIMARY KEY CLUSTERED ([Code] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[InternalCommands]...';\n\n\nGO\nCREATE TABLE [users].[InternalCommands] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [EnqueueDate]   DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    [Error] NVARCHAR(MAX) NULL,\n    CONSTRAINT [PK_users_InternalCommands_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [users].[OutboxMessages]...';\n\n\nGO\nCREATE TABLE [users].[OutboxMessages] (\n    [Id]            UNIQUEIDENTIFIER NOT NULL,\n    [OccurredOn]    DATETIME2 (7)    NOT NULL,\n    [Type]          VARCHAR (255)    NOT NULL,\n    [Data]          VARCHAR (MAX)    NOT NULL,\n    [ProcessedDate] DATETIME2 (7)    NULL,\n    CONSTRAINT [PK_users_OutboxMessages_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n);\n\n\nGO\nPRINT N'Creating [meetings].[v_MeetingGroups]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_MeetingGroups]\nAS\nSELECT\n    [MeetingGroup].Id,\n    [MeetingGroup].[Name],\n    [MeetingGroup].[Description],\n    [MeetingGroup].[LocationCountryCode],\n    [MeetingGroup].[LocationCity]\nFROM meetings.MeetingGroups AS [MeetingGroup]\nGO\nPRINT N'Creating [meetings].[v_Meetings]...';\n\n\nGO\n\nCREATE VIEW [meetings].[v_Meetings]\nAS\nSELECT\n\tMeeting.[Id],\n    Meeting.[Title],\n    Meeting.[Description],\n    Meeting.LocationAddress,\n    Meeting.LocationCity,\n    Meeting.LocationPostalCode,\n    Meeting.TermStartDate,\n    Meeting.TermEndDate\nFROM meetings.Meetings AS [Meeting]\nGO\nPRINT N'Creating [meetings].[v_Members]...';\n\n\nGO\nCREATE VIEW [meetings].[v_Members]\nAS\nSELECT\n    [Member].Id,\n    [Member].[Name],\n    [Member].[Login],\n    [Member].[Email]\nFROM meetings.Members AS [Member]\nGO\nPRINT N'Creating [users].[v_UserRoles]...';\n\n\nGO\nCREATE VIEW [users].[v_UserRoles]\nAS\nSELECT\n    [UserRole].[UserId],\n    [UserRole].[RoleCode]\nFROM [users].[UserRoles] AS [UserRole]\nGO\nPRINT N'Creating [users].[v_Users]...';\n\n\nGO\nCREATE VIEW [users].[v_Users]\nAS\nSELECT\n    [User].[Id],\n    [User].[IsActive],\n    [User].[Login],\n    [User].[Password],\n    [User].[Email],\n    [User].[Name]\nFROM [users].[Users] AS [User]\nGO\nPRINT N'Creating [users].[v_UserPermissions]...';\n\n\nGO\nCREATE VIEW [users].[v_UserPermissions]\nAS\nSELECT \n\tDISTINCT\n\t[UserRole].UserId,\n\t[RolesToPermission].PermissionCode\nFROM [users].UserRoles AS [UserRole]\n\tINNER JOIN [users].RolesToPermissions AS [RolesToPermission]\n\t\tON [UserRole].RoleCode = [RolesToPermission].RoleCode\nGO\nPRINT N'Update complete.';\n\n\nGO\n\nCREATE VIEW [users].[v_UserRegistrations]\nAS\nSELECT\n    [UserRegistration].[Id],\n    [UserRegistration].[Login],\n    [UserRegistration].[Email],\n    [UserRegistration].[FirstName],\n    [UserRegistration].[LastName],\n    [UserRegistration].[Name],\n    [UserRegistration].[StatusCode]\nFROM [users].[UserRegistrations] AS [UserRegistration]\nGO\n\nCREATE VIEW [administration].[v_Members]\nAS\nSELECT\n    [Member].[Id],\n    [Member].[Login],\n    [Member].[Email],\n    [Member].[FirstName],\n    [Member].[LastName],\n    [Member].[Name]\nFROM [administration].[Members] AS [Member]\nGO\n\nCREATE VIEW [administration].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode],\n    [MeetingGroupProposal].[DecisionDate],\n    [MeetingGroupProposal].[DecisionUserId],\n    [MeetingGroupProposal].[DecisionCode],\n    [MeetingGroupProposal].[DecisionRejectReason]\nFROM [administration].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\n\nCREATE VIEW [meetings].[v_MeetingGroupProposals]\nAS\nSELECT\n    [MeetingGroupProposal].[Id],\n    [MeetingGroupProposal].[Name],\n    [MeetingGroupProposal].[Description],\n    [MeetingGroupProposal].[LocationCity],\n    [MeetingGroupProposal].[LocationCountryCode],\n    [MeetingGroupProposal].[ProposalUserId],\n    [MeetingGroupProposal].[ProposalDate],\n    [MeetingGroupProposal].[StatusCode]\nFROM [meetings].[MeetingGroupProposals] AS [MeetingGroupProposal]\nGO\n\n-- Initialize some data\n\n\n/* SQL Server 2012+*/\n\nDECLARE @DBName sysname;\nSET @DBName = (SELECT db_name());\nDECLARE @SQL varchar(1000);\nSET @SQL = 'ALTER DATABASE ['+@DBName+'] SET ALLOW_SNAPSHOT_ISOLATION ON; ALTER DATABASE ['+@DBName+'] SET READ_COMMITTED_SNAPSHOT ON;'; \nexec(@sql)\n\nIF OBJECT_ID('payments.Streams', 'U') IS NULL\nBEGIN\n    CREATE TABLE payments.Streams(\n        Id                  CHAR(42)                                NOT NULL,\n        IdOriginal          NVARCHAR(1000)                          NOT NULL,\n        IdInternal          INT                 IDENTITY(1,1)       NOT NULL,\n        [Version]           INT                 DEFAULT(-1)         NOT NULL,\n        Position            BIGINT              DEFAULT(-1)         NOT NULL,\n        CONSTRAINT PK_Streams PRIMARY KEY CLUSTERED (IdInternal)\n    );\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Streams_Id' AND object_id = OBJECT_ID('payments.Streams', 'U'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Streams_Id ON payments.Streams (Id);\nEND\n \nIF object_id('payments.Messages', 'U') IS NULL\nBEGIN\n    CREATE TABLE payments.Messages(\n        StreamIdInternal    INT                                     NOT NULL,\n        StreamVersion       INT                                     NOT NULL,\n        Position            BIGINT                 IDENTITY(0,1)    NOT NULL,\n        Id                  UNIQUEIDENTIFIER                        NOT NULL,\n        Created             DATETIME                                NOT NULL,\n        [Type]              NVARCHAR(128)                           NOT NULL,\n        JsonData            NVARCHAR(max)                           NOT NULL,\n        JsonMetadata        NVARCHAR(max)                                   ,\n        CONSTRAINT PK_Events PRIMARY KEY NONCLUSTERED (Position),\n        CONSTRAINT FK_Events_Streams FOREIGN KEY (StreamIdInternal) REFERENCES payments.Streams(IdInternal)\n    );\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_Position' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Messages_Position ON payments.Messages (Position);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Id' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Id ON payments.Messages (StreamIdInternal, Id);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Revision' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE UNIQUE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Revision ON payments.Messages (StreamIdInternal, StreamVersion);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.indexes\n    WHERE name='IX_Messages_StreamIdInternal_Created' AND object_id = OBJECT_ID('payments.Messages'))\nBEGIN\n    CREATE NONCLUSTERED INDEX IX_Messages_StreamIdInternal_Created ON payments.Messages (StreamIdInternal, Created);\nEND\n\nIF NOT EXISTS(\n    SELECT * \n    FROM sys.table_types tt JOIN sys.schemas s ON tt.schema_id = s.schema_id\n    WHERE s.name + '.' + tt.name='payments.NewStreamMessages')\nBEGIN\n    CREATE TYPE payments.NewStreamMessages AS TABLE (\n        StreamVersion       INT IDENTITY(0,1)                       NOT NULL,\n        Id                  UNIQUEIDENTIFIER                        NOT NULL,\n        Created             DATETIME          DEFAULT(GETUTCDATE()) NOT NULL,\n        [Type]              NVARCHAR(128)                           NOT NULL,\n        JsonData            NVARCHAR(max)                           NULL,\n        JsonMetadata        NVARCHAR(max)                           NULL\n    );\nEND\n\nBEGIN\n    IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('payments.Streams') AND [name] = N'version' AND [minor_id] = 0)\n    EXEC sys.sp_addextendedproperty   \n    @name = N'version',\n    @value = N'2',\n    @level0type = N'SCHEMA', @level0name = 'payments',\n    @level1type = N'TABLE',  @level1name = 'Streams';\nEND\n\nCREATE TABLE payments.SubscriptionDetails\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [Period] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    [CountryCode] VARCHAR(50) NOT NULL,\n    [ExpirationDate] DATETIME NOT NULL,\n    CONSTRAINT [PK_payments_SubscriptionDetails_Id] PRIMARY KEY CLUSTERED ([Id] ASC)\n)\n\nCREATE TABLE payments.SubscriptionCheckpoints\n(\n    [Code] VARCHAR(50) NOT NULL,\n    [Position] BIGINT NOT NULL\n)\n\nCREATE TABLE payments.PriceListItems\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [SubscriptionPeriodCode] VARCHAR(50) NOT NULL,\n    [CategoryCode] VARCHAR(50) NOT NULL,\n    [CountryCode] VARCHAR(50) NOT NULL,\n    [MoneyValue] DECIMAL(18, 2) NOT NULL,\n    [MoneyCurrency] VARCHAR(50) NOT NULL,\n    [IsActive] BIT NOT NULL\n)\n\nCREATE TABLE payments.SubscriptionPayments\n(\n    [PaymentId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId] UNIQUEIDENTIFIER NOT NULL,\n    [Type] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    [Period] VARCHAR(50) NOT NULL,\n    [Date] DATETIME NOT NULL,\n    [SubscriptionId] UNIQUEIDENTIFIER NULL,\n    [MoneyValue] DECIMAL(18, 2) NOT NULL,\n    [MoneyCurrency] VARCHAR(50) NOT NULL\n)\n\nCREATE TABLE [meetings].[MemberSubscriptions]\n(\n    [Id] UNIQUEIDENTIFIER NOT NULL,\n    [ExpirationDate] DATETIME NOT NULL,\n    CONSTRAINT [PK_meetings_MemberSubscriptions_Id] PRIMARY KEY ([Id] ASC)\n)\nGO\n\nINSERT INTO payments.PriceListItems\nVALUES ('d58f0876-efe3-4b4c-b196-a4c3d5fadd24', 'Month', 'New', 'PL', 60, 'PLN', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('d48e9951-2ae8-467e-a257-a1f492dbd36d', 'HalfYear', 'New', 'PL', 320, 'PLN', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('b7bbe846-c151-48b5-85ef-a5737108640c', 'Month', 'New', 'US', 15, 'USD', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('92666bf7-7e86-4784-9c69-e6f3b8bb0ea6', 'HalfYear', 'New', 'US', 80, 'USD', 1)\nGO\n\nINSERT INTO payments.PriceListItems\nVALUES ('d58f0876-efe3-4b4c-b196-a4c3d5fadd24', 'Month', 'Renewal', 'PL', 60, 'PLN', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('d48e9951-2ae8-467e-a257-a1f492dbd36d', 'HalfYear', 'Renewal', 'PL', 320, 'PLN', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('b7bbe846-c151-48b5-85ef-a5737108640c', 'Month', 'Renewal', 'US', 15, 'USD', 1)\n\nINSERT INTO payments.PriceListItems\nVALUES ('92666bf7-7e86-4784-9c69-e6f3b8bb0ea6', 'HalfYear', 'Renewal', 'US', 80, 'USD', 1)\nGO\n\nCREATE VIEW [meetings].[v_MeetingGroupMembers]\nAS\nSELECT\n    [MeetingGroupMember].MeetingGroupId,\n    [MeetingGroupMember].MemberId,\n    [MeetingGroupMember].RoleCode\nFROM meetings.MeetingGroupMembers AS [MeetingGroupMember]\nGO\n\nCREATE TABLE [payments].[MeetingFees]\n(\n    [MeetingFeeId] UNIQUEIDENTIFIER NOT NULL,\n    [PayerId] UNIQUEIDENTIFIER NOT NULL,\n    [MeetingId] UNIQUEIDENTIFIER NOT NULL,\n    [FeeValue] DECIMAL(18, 2) NOT NULL,\n    [FeeCurrency] VARCHAR(50) NOT NULL,\n    [Status] VARCHAR(50) NOT NULL,\n    CONSTRAINT [PK_payments_MeetingFees_MeetingFeeId] PRIMARY KEY ([MeetingFeeId] ASC)\n)\nGO"
  },
  {
    "path": "src/Database/entrypoint.sh",
    "content": "#!/bin/bash\n\necho 'Starting sql server..' ;\n\n# Start SQL Server\n/opt/mssql/bin/sqlservr &\n\necho 'SQL server started.';\n\nsleep 30 ;\n\necho 'Create database..' ;\n\n# Create database\n/opt/mssql-tools/bin/sqlcmd -d master -i /scripts/CreateDatabase_Linux.sql -U sa -P Test@12345 ;\n\necho 'Database created' ;\n\ntail -f /dev/null"
  },
  {
    "path": "src/Database/entrypoint_DatabaseMigrator.sh",
    "content": "# Wait 30 seconds after SQL Server is running for database creation.\nsleep 30;\n\necho $ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\n\ndotnet DatabaseMigrator.dll $ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString \"/migrations\""
  },
  {
    "path": "src/Database/wait-for-it.sh",
    "content": "#!/usr/bin/env bash\n# Use this script to test if a given TCP host/port are available\n\nWAITFORIT_cmdname=${0##*/}\n\nechoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo \"$@\" 1>&2; fi }\n\nusage()\n{\n    cat << USAGE >&2\nUsage:\n    $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]\n    -h HOST | --host=HOST       Host or IP under test\n    -p PORT | --port=PORT       TCP port under test\n                                Alternatively, you specify the host and port as host:port\n    -s | --strict               Only execute subcommand if the test succeeds\n    -q | --quiet                Don't output any status messages\n    -t TIMEOUT | --timeout=TIMEOUT\n                                Timeout in seconds, zero for no timeout\n    -- COMMAND ARGS             Execute command with args after the test finishes\nUSAGE\n    exit 1\n}\n\nwait_for()\n{\n    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then\n        echoerr \"$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT\"\n    else\n        echoerr \"$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout\"\n    fi\n    WAITFORIT_start_ts=$(date +%s)\n    while :\n    do\n        if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then\n            nc -z $WAITFORIT_HOST $WAITFORIT_PORT\n            WAITFORIT_result=$?\n        else\n            (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1\n            WAITFORIT_result=$?\n        fi\n        if [[ $WAITFORIT_result -eq 0 ]]; then\n            WAITFORIT_end_ts=$(date +%s)\n            echoerr \"$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds\"\n            break\n        fi\n        sleep 1\n    done\n    return $WAITFORIT_result\n}\n\nwait_for_wrapper()\n{\n    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692\n    if [[ $WAITFORIT_QUIET -eq 1 ]]; then\n        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &\n    else\n        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &\n    fi\n    WAITFORIT_PID=$!\n    trap \"kill -INT -$WAITFORIT_PID\" INT\n    wait $WAITFORIT_PID\n    WAITFORIT_RESULT=$?\n    if [[ $WAITFORIT_RESULT -ne 0 ]]; then\n        echoerr \"$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT\"\n    fi\n    return $WAITFORIT_RESULT\n}\n\n# process arguments\nwhile [[ $# -gt 0 ]]\ndo\n    case \"$1\" in\n        *:* )\n        WAITFORIT_hostport=(${1//:/ })\n        WAITFORIT_HOST=${WAITFORIT_hostport[0]}\n        WAITFORIT_PORT=${WAITFORIT_hostport[1]}\n        shift 1\n        ;;\n        --child)\n        WAITFORIT_CHILD=1\n        shift 1\n        ;;\n        -q | --quiet)\n        WAITFORIT_QUIET=1\n        shift 1\n        ;;\n        -s | --strict)\n        WAITFORIT_STRICT=1\n        shift 1\n        ;;\n        -h)\n        WAITFORIT_HOST=\"$2\"\n        if [[ $WAITFORIT_HOST == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --host=*)\n        WAITFORIT_HOST=\"${1#*=}\"\n        shift 1\n        ;;\n        -p)\n        WAITFORIT_PORT=\"$2\"\n        if [[ $WAITFORIT_PORT == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --port=*)\n        WAITFORIT_PORT=\"${1#*=}\"\n        shift 1\n        ;;\n        -t)\n        WAITFORIT_TIMEOUT=\"$2\"\n        if [[ $WAITFORIT_TIMEOUT == \"\" ]]; then break; fi\n        shift 2\n        ;;\n        --timeout=*)\n        WAITFORIT_TIMEOUT=\"${1#*=}\"\n        shift 1\n        ;;\n        --)\n        shift\n        WAITFORIT_CLI=(\"$@\")\n        break\n        ;;\n        --help)\n        usage\n        ;;\n        *)\n        echoerr \"Unknown argument: $1\"\n        usage\n        ;;\n    esac\ndone\n\nif [[ \"$WAITFORIT_HOST\" == \"\" || \"$WAITFORIT_PORT\" == \"\" ]]; then\n    echoerr \"Error: you need to provide a host and port to test.\"\n    usage\nfi\n\nWAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}\nWAITFORIT_STRICT=${WAITFORIT_STRICT:-0}\nWAITFORIT_CHILD=${WAITFORIT_CHILD:-0}\nWAITFORIT_QUIET=${WAITFORIT_QUIET:-0}\n\n# Check to see if timeout is from busybox?\nWAITFORIT_TIMEOUT_PATH=$(type -p timeout)\nWAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)\n\nWAITFORIT_BUSYTIMEFLAG=\"\"\nif [[ $WAITFORIT_TIMEOUT_PATH =~ \"busybox\" ]]; then\n    WAITFORIT_ISBUSY=1\n    # Check if busybox timeout uses -t flag\n    # (recent Alpine versions don't support -t anymore)\n    if timeout &>/dev/stdout | grep -q -e '-t '; then\n        WAITFORIT_BUSYTIMEFLAG=\"-t\"\n    fi\nelse\n    WAITFORIT_ISBUSY=0\nfi\n\nif [[ $WAITFORIT_CHILD -gt 0 ]]; then\n    wait_for\n    WAITFORIT_RESULT=$?\n    exit $WAITFORIT_RESULT\nelse\n    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then\n        wait_for_wrapper\n        WAITFORIT_RESULT=$?\n    else\n        wait_for\n        WAITFORIT_RESULT=$?\n    fi\nfi\n\nif [[ $WAITFORIT_CLI != \"\" ]]; then\n    if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then\n        echoerr \"$WAITFORIT_cmdname: strict mode, refusing to execute subprocess\"\n        exit $WAITFORIT_RESULT\n    fi\n    exec \"${WAITFORIT_CLI[@]}\"\nelse\n    exit $WAITFORIT_RESULT\nfi\n"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"NuspecSettings\">\n    <Company>Kamil Grzybek</Company>\n    <Authors>$(Company)</Authors>\n    <Copyright>Copyright © $(Company) $([System.DateTime]::Now.Year)</Copyright>\n    <Trademark>$(Company)™</Trademark>\n    <Product>$(Company) Projects</Product>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Configurations>Debug;Release;Production</Configurations>\n    <NoWarn>1591;1701;1702;8032;NU1701;AD0001;NU5128;NU1603</NoWarn>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <Deterministic>true</Deterministic>\n    <RestoreIgnoreFailedSource>true</RestoreIgnoreFailedSource>\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\n    <EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>\n    <RunAnalyzersDuringLiveAnalysis>True</RunAnalyzersDuringLiveAnalysis>\n    <RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>\n    <EnableNETAnalyzers>True</EnableNETAnalyzers>\n    <Optimize>True</Optimize>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"ConfigFiles\">\n    <StyleCopFile Condition=\" '$(StyleCopFile)' == '' \">$([MSBuild]::GetPathOfFileAbove('stylecop.json',\n      $(MSBuildProjectDirectory)))</StyleCopFile>\n    <EditorConfigFile Condition=\" '$(EditorConfigFile)' == '' \">$([MSBuild]::GetPathOfFileAbove('.editorconfig',\n      $(MSBuildProjectDirectory)))</EditorConfigFile>\n  </PropertyGroup>\n\n  <ItemGroup Label=\"ConfigFiles\">\n    <AdditionalFiles Condition=\"Exists('$(StyleCopFile)')\" Include=\"$(StyleCopFile)\" Visible=\"false\" />\n    <None Condition=\"Exists('$(EditorConfigFile)')\" Include=\"$(EditorConfigFile)\" Visible=\"false\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Directory.Build.targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <None Include=\"**\\*.sql\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Remove=\"bin\\**\" />\n    <None Remove=\"obj\\**\" />\n  </ItemGroup>\n\n  <PropertyGroup Condition=\"'$(TestProject)' == 'true' or '$(OutputType)' == 'Exe'\">\n    <IsPackable>False</IsPackable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <BBDomainPath>$(MSBuildThisFileDirectory)\\BuildingBlocks\\Domain\\*.csproj</BBDomainPath>\n    <BBApplicationPath>$(MSBuildThisFileDirectory)\\BuildingBlocks\\Application\\*.csproj</BBApplicationPath>\n    <BBInfrastructurePath>$(MSBuildThisFileDirectory)\\BuildingBlocks\\Infrastructure\\*.csproj</BBInfrastructurePath>\n    <BBIntegrationTestsPath>$(MSBuildThisFileDirectory)\\BuildingBlocks\\Tests\\IntegrationTests\\*.csproj</BBIntegrationTestsPath>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('API'))\">\n    <ProjectReference Include=\"..\\..\\Modules\\**\\Infrastructure\\*.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('BuildingBlocks')) and $(MSBuildProjectName.EndsWith('Application'))\">\n    <ProjectReference Include=\"$(BBDomainPath)\" />\n  </ItemGroup>\t\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('BuildingBlocks')) and ($(MSBuildProjectName.EndsWith('UnitTests')) or $(MSBuildProjectName.EndsWith('Infrastructure')))\">\n    <ProjectReference Include=\"$(BBApplicationPath)\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('src$([System.IO.Path]::DirectorySeparatorChar)Tests'))\">\n    <ProjectReference Include=\"..\\..\\API\\**\\*.csproj\" />\n    <ProjectReference Include=\"$(BBIntegrationTestsPath)\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Modules')) and $(MSBuildProjectName.EndsWith('Domain'))\">\n    <ProjectReference Include=\"$(BBDomainPath)\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Modules')) and $(MSBuildProjectName.EndsWith('IntegrationEvents'))\">\n    <ProjectReference Include=\"$(BBInfrastructurePath)\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Modules')) and $(MSBuildProjectName.EndsWith('Application'))\">\n    <ProjectReference Include=\"..\\Domain\\*.csproj\" />\n    <ProjectReference Include=\"..\\IntegrationEvents\\*.csproj\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Modules')) and $(MSBuildProjectName.EndsWith('Infrastructure'))\">\n    <ProjectReference Include=\"..\\Application\\*.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Modules')) and $(MSBuildProjectName.EndsWith('Tests'))\">\n    <ProjectReference Include=\"..\\..\\Infrastructure\\*.csproj\" />\n    <ProjectReference Include=\"$(BBIntegrationTestsPath)\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Directory.Packages.props",
    "content": "﻿<Project>\n  <ItemGroup>\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.556\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('API'))\">\n    <PackageReference Include=\"Hellang.Middleware.ProblemDetails\" Version=\"6.5.1\" />\n    <PackageReference Include=\"Microsoft.VisualStudio.Azure.Containers.Tools.Targets\" Version=\"1.19.5\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.5.0\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('Migrator'))\">\n    <PackageReference Include=\"dbup-sqlserver\" Version=\"5.0.37\" />\n    <PackageReference Include=\"Serilog.AspNetCore\" Version=\"8.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('BuildingBlocks.Domain'))\">\n    <PackageReference Include=\"MediatR\" Version=\"12.2.0\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('BuildingBlocks.Application'))\">\n    <PackageReference Include=\"Dapper\" Version=\"2.1.24\" />\n    <PackageReference Include=\"FluentValidation\" Version=\"11.8.1\" />\n\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.3\" />\n    <PackageReference Include=\"Quartz\" Version=\"3.8.0\" />\n    <PackageReference Include=\"Serilog.AspNetCore\" Version=\"8.0.0\" />\n  </ItemGroup>\n  <ItemGroup Condition=\"$(MSBuildProjectName.EndsWith('BuildingBlocks.Infrastructure'))\">\n    <PackageReference Include=\"Autofac\" Version=\"7.1.0\" />\n    <PackageReference Include=\"Autofac.Extensions.DependencyInjection\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.SqlServer\" Version=\"8.0.0\" />\n    <PackageReference Include=\"System.Data.SqlClient\" Version=\"4.8.6\" />\n    <PackageReference Include=\"Polly\" Version=\"8.2.0\" />\n    <PackageReference Include=\"SqlStreamStore.MsSql\" Version=\"1.1.3\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"$(MSBuildProjectFullPath.Contains('Tests'))\">\n    <PackageReference Include=\"NetArchTest.Rules\" Version=\"1.3.2\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"nunit\" Version=\"4.0.1\" />\n    <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.5.0\" />\n    <PackageReference Include=\"FluentAssertions\" Version=\"6.12.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Dockerfile",
    "content": "#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.\n\nFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base\nWORKDIR /app\nEXPOSE 80\nEXPOSE 443\n\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build\nWORKDIR /src\nCOPY [\"API/CompanyName.MyMeetings.API/CompanyName.MyMeetings.API.csproj\", \"API/CompanyName.MyMeetings.API/\"]\nCOPY [\"Modules/UserAccess/Application/CompanyName.MyMeetings.Modules.UserAccess.Application.csproj\", \"Modules/UserAccess/Application/\"]\nCOPY [\"Modules/UserAccess/IntegrationEvents/CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj\", \"Modules/UserAccess/IntegrationEvents/\"]\nCOPY [\"BuildingBlocks/Infrastructure/CompanyName.MyMeetings.BuildingBlocks.Infrastructure.csproj\", \"BuildingBlocks/Infrastructure/\"]\nCOPY [\"BuildingBlocks/Domain/CompanyName.MyMeetings.BuildingBlocks.Domain.csproj\", \"BuildingBlocks/Domain/\"]\nCOPY [\"BuildingBlocks/Application/CompanyName.MyMeetings.BuildingBlocks.Application.csproj\", \"BuildingBlocks/Application/\"]\nCOPY [\"Modules/UserAccess/Domain/CompanyName.MyMeetings.Modules.UserAccess.Domain.csproj\", \"Modules/UserAccess/Domain/\"]\nCOPY [\"Modules/Meetings/IntegrationEvents/CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj\", \"Modules/Meetings/IntegrationEvents/\"]\nCOPY [\"Modules/Meetings/Application/CompanyName.MyMeetings.Modules.Meetings.Application.csproj\", \"Modules/Meetings/Application/\"]\nCOPY [\"Modules/Meetings/Domain/CompanyName.MyMeetings.Modules.Meetings.Domain.csproj\", \"Modules/Meetings/Domain/\"]\nCOPY [\"Modules/Administration/IntegrationEvents/CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.csproj\", \"Modules/Administration/IntegrationEvents/\"]\nCOPY [\"Modules/Payments/IntegrationEvents/CompanyName.MyMeetings.Modules.Payments.IntegrationEvents.csproj\", \"Modules/Payments/IntegrationEvents/\"]\nCOPY [\"Modules/UserAccess/Infrastructure/CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.csproj\", \"Modules/UserAccess/Infrastructure/\"]\nCOPY [\"Modules/Payments/Application/CompanyName.MyMeetings.Modules.Payments.Application.csproj\", \"Modules/Payments/Application/\"]\nCOPY [\"Modules/Payments/Domain/CompanyName.MyMeetings.Modules.Payments.Domain.csproj\", \"Modules/Payments/Domain/\"]\nCOPY [\"Modules/Meetings/Infrastructure/CompanyName.MyMeetings.Modules.Meetings.Infrastructure.csproj\", \"Modules/Meetings/Infrastructure/\"]\nCOPY [\"Modules/Payments/Infrastructure/CompanyName.MyMeetings.Modules.Payments.Infrastructure.csproj\", \"Modules/Payments/Infrastructure/\"]\nCOPY [\"Modules/Administration/Application/CompanyName.MyMeetings.Modules.Administration.Application.csproj\", \"Modules/Administration/Application/\"]\nCOPY [\"Modules/Administration/Domain/CompanyName.MyMeetings.Modules.Administration.Domain.csproj\", \"Modules/Administration/Domain/\"]\nCOPY [\"Modules/Administration/Infrastructure/CompanyName.MyMeetings.Modules.Administration.Infrastructure.csproj\", \"Modules/Administration/Infrastructure/\"]\nCOPY [\"Directory.Packages.props\", \"Directory.Packages.props\"]\nCOPY [\"Directory.Build.props\", \"Directory.Build.props\"]\nCOPY [\"Directory.Build.targets\", \"Directory.Build.targets\"]\nRUN dotnet restore \"API/CompanyName.MyMeetings.API/CompanyName.MyMeetings.API.csproj\"\nCOPY . .\nWORKDIR \"/src/API/CompanyName.MyMeetings.API\"\nRUN dotnet build \"CompanyName.MyMeetings.API.csproj\" -c Release -o /app/build\n\nFROM build AS publish\nRUN dotnet publish \"CompanyName.MyMeetings.API.csproj\" -c Release -o /app/publish\n\nFROM base AS final\nWORKDIR /app\nCOPY --from=publish /app/publish .\n\nADD entrypoint.sh /\n\nENTRYPOINT [\"/bin/bash\", \"/entrypoint.sh\"]"
  },
  {
    "path": "src/Modules/Administration/Application/CompanyName.MyMeetings.Modules.Administration.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Meetings\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\Registrations\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\UserAccess\\IntegrationEvents\\CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/Administration/Application/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Configuration/Queries/IQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries\n{\n    public interface IQueryHandler<in TQuery, TResult> :\n        IRequestHandler<TQuery, TResult>\n        where TQuery : IQuery<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/CommandBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public abstract class CommandBase : ICommand\n    {\n        public Guid Id { get; }\n\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n\n    public abstract class CommandBase<TResult> : ICommand<TResult>\n    {\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/IAdministrationModule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public interface IAdministrationModule\n    {\n        Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n        Task ExecuteCommandAsync(ICommand command);\n\n        Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/ICommand.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public interface ICommand<out TResult> : IRequest<TResult>\n    {\n        Guid Id { get; }\n    }\n\n    public interface ICommand : IRequest\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/IQuery.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public interface IQuery<out TResult> : IRequest<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Contracts/QueryBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.Contracts\n{\n    public abstract class QueryBase<TResult> : IQuery<TResult>\n    {\n        public Guid Id { get; }\n\n        protected QueryBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected QueryBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/AcceptMeetingGroupProposalCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    public class AcceptMeetingGroupProposalCommand : CommandBase\n    {\n        public AcceptMeetingGroupProposalCommand(Guid meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        internal Guid MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/AcceptMeetingGroupProposalCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\r\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\r\n{\r\n    internal class AcceptMeetingGroupProposalCommandHandler : ICommandHandler<AcceptMeetingGroupProposalCommand>\r\n    {\r\n        private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\r\n        private readonly IUserContext _userContext;\r\n\r\n        internal AcceptMeetingGroupProposalCommandHandler(IMeetingGroupProposalRepository meetingGroupProposalRepository, IUserContext userContext)\r\n        {\r\n            _meetingGroupProposalRepository = meetingGroupProposalRepository;\r\n            _userContext = userContext;\r\n        }\r\n\r\n        public async Task Handle(AcceptMeetingGroupProposalCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroupProposal = await _meetingGroupProposalRepository.GetByIdAsync(new MeetingGroupProposalId(request.MeetingGroupProposalId));\r\n\r\n            meetingGroupProposal.Accept(_userContext.UserId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/MeetingGroupProposalAcceptedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    public class MeetingGroupProposalAcceptedNotification : DomainNotificationBase<MeetingGroupProposalAcceptedDomainEvent>\n    {\n        [JsonConstructor]\n        public MeetingGroupProposalAcceptedNotification(MeetingGroupProposalAcceptedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/MeetingGroupProposalAcceptedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.MeetingGroupProposals;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    public class MeetingGroupProposalAcceptedNotificationHandler : INotificationHandler<MeetingGroupProposalAcceptedNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public MeetingGroupProposalAcceptedNotificationHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(MeetingGroupProposalAcceptedNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new MeetingGroupProposalAcceptedIntegrationEvent(\n                notification.Id,\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.MeetingGroupProposalId.Value));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/GetMeetingGroupProposal/GetMeetingGroupProposalQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    public class GetMeetingGroupProposalQuery : QueryBase<MeetingGroupProposalDto>\n    {\n        public GetMeetingGroupProposalQuery(Guid meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        public Guid MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/GetMeetingGroupProposal/GetMeetingGroupProposalQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    internal class GetMeetingGroupProposalQueryHandler : IQueryHandler<GetMeetingGroupProposalQuery, MeetingGroupProposalDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingGroupProposalQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MeetingGroupProposalDto> Handle(GetMeetingGroupProposalQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                         SELECT \n                             [MeetingGroupProposal].[Id] AS [{nameof(MeetingGroupProposalDto.Id)}], \n                             [MeetingGroupProposal].[Name] AS [{nameof(MeetingGroupProposalDto.Name)}], \n                             [MeetingGroupProposal].[ProposalUserId] AS [{nameof(MeetingGroupProposalDto.ProposalUserId)}], \n                             [MeetingGroupProposal].[LocationCity] AS [{nameof(MeetingGroupProposalDto.LocationCity)}], \n                             [MeetingGroupProposal].[LocationCountryCode] AS [{nameof(MeetingGroupProposalDto.LocationCountryCode)}], \n                             [MeetingGroupProposal].[Description] AS [{nameof(MeetingGroupProposalDto.Description)}], \n                             [MeetingGroupProposal].[ProposalDate] AS [{nameof(MeetingGroupProposalDto.ProposalDate)}], \n                             [MeetingGroupProposal].[StatusCode] AS [{nameof(MeetingGroupProposalDto.StatusCode)}], \n                             [MeetingGroupProposal].[DecisionDate] AS [{nameof(MeetingGroupProposalDto.DecisionDate)}], \n                             [MeetingGroupProposal].[DecisionUserId] AS [{nameof(MeetingGroupProposalDto.DecisionUserId)}], \n                             [MeetingGroupProposal].[DecisionCode] AS [{nameof(MeetingGroupProposalDto.DecisionCode)}], \n                             [MeetingGroupProposal].[DecisionRejectReason] AS [{nameof(MeetingGroupProposalDto.DecisionRejectReason)}] \n                         FROM [administration].[v_MeetingGroupProposals] AS [MeetingGroupProposal]\n                         WHERE [MeetingGroupProposal].[Id] = @MeetingGroupProposalId\n                         \"\"\";\n\n            return await connection.QuerySingleAsync<MeetingGroupProposalDto>(sql, new { query.MeetingGroupProposalId });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/GetMeetingGroupProposal/MeetingGroupProposalDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    public class MeetingGroupProposalDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationCountryCode { get; set; }\n\n        public Guid ProposalUserId { get; set; }\n\n        public DateTime ProposalDate { get; set; }\n\n        public string StatusCode { get; set; }\n\n        public DateTime? DecisionDate { get; set; }\n\n        public Guid? DecisionUserId { get; set; }\n\n        public string DecisionCode { get; set; }\n\n        public string DecisionRejectReason { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/GetMeetingGroupProposals/GetMeetingGroupProposalsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposals\n{\n    public class GetMeetingGroupProposalsQuery : QueryBase<List<MeetingGroupProposalDto>>\n    {\n        public GetMeetingGroupProposalsQuery()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/GetMeetingGroupProposals/GetMeetingGroupProposalsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposals\n{\n    internal class GetMeetingGroupProposalsQueryHandler : IQueryHandler<GetMeetingGroupProposalsQuery, List<MeetingGroupProposalDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingGroupProposalsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingGroupProposalDto>> Handle(GetMeetingGroupProposalsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT\n                                    [MeetingGroupProposal].[Id] AS [{nameof(MeetingGroupProposalDto.Id)}],\n                                    [MeetingGroupProposal].[Name] AS [{nameof(MeetingGroupProposalDto.Name)}],\n                                    [MeetingGroupProposal].[ProposalUserId] AS [{nameof(MeetingGroupProposalDto.ProposalUserId)}],\n                                    [MeetingGroupProposal].[LocationCity] AS [{nameof(MeetingGroupProposalDto.LocationCity)}],\n                                    [MeetingGroupProposal].[LocationCountryCode] AS [{nameof(MeetingGroupProposalDto.LocationCountryCode)}],\n                                    [MeetingGroupProposal].[Description] AS [{nameof(MeetingGroupProposalDto.Description)}],\n                                    [MeetingGroupProposal].[ProposalDate] AS [{nameof(MeetingGroupProposalDto.ProposalDate)}],\n                                    [MeetingGroupProposal].[StatusCode] AS [{nameof(MeetingGroupProposalDto.StatusCode)}],\n                                    [MeetingGroupProposal].[DecisionDate] AS [{nameof(MeetingGroupProposalDto.DecisionDate)}],\n                                    [MeetingGroupProposal].[DecisionUserId] AS [{nameof(MeetingGroupProposalDto.DecisionUserId)}],\n                                    [MeetingGroupProposal].[DecisionCode] AS [{nameof(MeetingGroupProposalDto.DecisionCode)}],\n                                    [MeetingGroupProposal].[DecisionRejectReason] AS [{nameof(MeetingGroupProposalDto.DecisionRejectReason)}]\n                                FROM [administration].[v_MeetingGroupProposals] AS [MeetingGroupProposal]\n                                \"\"\";\n\n            return (await connection.QueryAsync<MeetingGroupProposalDto>(sql)).AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/MeetingGroupProposedIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.RequestMeetingGroupProposalVerification;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals\n{\n    internal class MeetingGroupProposedIntegrationEventHandler : INotificationHandler<MeetingGroupProposedIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal MeetingGroupProposedIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingGroupProposedIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new RequestMeetingGroupProposalVerificationCommand(\n            Guid.NewGuid(),\n            notification.MeetingGroupProposalId,\n            notification.Name,\n            notification.Description,\n            notification.LocationCity,\n            notification.LocationCountryCode,\n            notification.ProposalUserId,\n            notification.ProposalDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/RequestMeetingGroupProposalVerification/RequestMeetingGroupProposalVerificationCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.RequestMeetingGroupProposalVerification\n{\n    public class RequestMeetingGroupProposalVerificationCommand : InternalCommandBase<Guid>\n    {\n        [JsonConstructor]\n        public RequestMeetingGroupProposalVerificationCommand(\n            Guid id,\n            Guid meetingGroupProposalId,\n            string name,\n            string description,\n            string locationCity,\n            string locationCountryCode,\n            Guid proposalUserId,\n            DateTime proposalDate)\n            : base(id)\n        {\n            this.MeetingGroupProposalId = meetingGroupProposalId;\n            this.Name = name;\n            this.Description = description;\n            this.LocationCity = locationCity;\n            this.LocationCountryCode = locationCountryCode;\n            this.ProposalUserId = proposalUserId;\n            this.ProposalDate = proposalDate;\n        }\n\n        public Guid MeetingGroupProposalId { get; }\n\n        public string Name { get; }\n\n        public string Description { get; }\n\n        public string LocationCity { get; }\n\n        public string LocationCountryCode { get; }\n\n        public Guid ProposalUserId { get; }\n\n        public DateTime ProposalDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/MeetingGroupProposals/RequestMeetingGroupProposalVerification/RequestMeetingGroupProposalVerificationCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.RequestMeetingGroupProposalVerification\n{\n    internal class RequestMeetingGroupProposalVerificationCommandHandler :\n        ICommandHandler<RequestMeetingGroupProposalVerificationCommand, Guid>\n    {\n        private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\n\n        public RequestMeetingGroupProposalVerificationCommandHandler(IMeetingGroupProposalRepository meetingGroupProposalRepository)\n        {\n            _meetingGroupProposalRepository = meetingGroupProposalRepository;\n        }\n\n        public async Task<Guid> Handle(RequestMeetingGroupProposalVerificationCommand request, CancellationToken cancellationToken)\n        {\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                request.MeetingGroupProposalId,\n                request.Name,\n                request.Description,\n                MeetingGroupLocation.Create(request.LocationCity, request.LocationCountryCode),\n                new UserId(request.ProposalUserId),\n                request.ProposalDate);\n\n            await _meetingGroupProposalRepository.AddAsync(meetingGroupProposal);\n\n            return meetingGroupProposal.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/CreateMember/CreateMemberCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember\n{\n    public class CreateMemberCommand : InternalCommandBase<Guid>\n    {\n        [JsonConstructor]\n        public CreateMemberCommand(\n            Guid id,\n            Guid memberId,\n            string login,\n            string email,\n            string firstName,\n            string lastName,\n            string name)\n            : base(id)\n        {\n            Login = login;\n            MemberId = memberId;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n        }\n\n        internal Guid MemberId { get; }\n\n        internal string Login { get; }\n\n        internal string Email { get; }\n\n        internal string FirstName { get; }\n\n        internal string LastName { get; }\n\n        internal string Name { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/CreateMember/CreateMemberCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember\n{\n    internal class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand, Guid>\n    {\n        private readonly IMemberRepository _memberRepository;\n\n        public CreateMemberCommandHandler(IMemberRepository memberRepository)\n        {\n            _memberRepository = memberRepository;\n        }\n\n        public async Task<Guid> Handle(CreateMemberCommand request, CancellationToken cancellationToken)\n        {\n            var member = Member.Create(\n                request.MemberId,\n                request.Login,\n                request.Email,\n                request.FirstName,\n                request.LastName,\n                request.Name);\n\n            await _memberRepository.AddAsync(member);\n\n            return member.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/GetMember/GetMemberQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Members.GetMember\n{\n    public class GetMemberQuery : QueryBase<MemberDto>\n    {\n        public GetMemberQuery(Guid memberId)\n        {\n            MemberId = memberId;\n        }\n\n        public Guid MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/GetMember/GetMemberQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Members.GetMember\n{\n    internal class GetMemberQueryHandler : IQueryHandler<GetMemberQuery, MemberDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMemberQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MemberDto> Handle(GetMemberQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n            const string sql = $\"\"\"\n                               SELECT\n                                  [Member].[Id] AS [{nameof(MemberDto.Id)}],\n                                  [Member].[Login] AS [{nameof(MemberDto.Login)}],\n                                  [Member].[Email] AS [{nameof(MemberDto.Email)}],\n                                  [Member].[FirstName] AS [{nameof(MemberDto.FirstName)}],\n                                  [Member].[LastName] AS [{nameof(MemberDto.LastName)}],\n                                  [Member].[Name] AS [{nameof(MemberDto.Name)}]\n                               FROM [administration].[v_Members] AS [Member]\n                               WHERE [Member].[Id] = @MemberId   \n                              \"\"\";\n\n            return await connection.QuerySingleAsync<MemberDto>(sql, new { query.MemberId });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/GetMember/MemberDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Application.Members.GetMember\n{\n    public class MemberDto\n    {\n        public Guid Id { get; set; }\n\n        public string Login { get; set; }\n\n        public string Email { get; set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Application/Members/NewUserRegisteredIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Application.Members\n{\n    internal class NewUserRegisteredIntegrationEventHandler : INotificationHandler<NewUserRegisteredIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal NewUserRegisteredIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(NewUserRegisteredIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new\n                CreateMemberCommand(\n                    Guid.NewGuid(),\n                    notification.UserId,\n                    notification.Login,\n                    notification.Email,\n                    notification.FirstName,\n                    notification.LastName,\n                    notification.Name));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/CompanyName.MyMeetings.Modules.Administration.Domain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/Events/MeetingGroupProposalAcceptedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events\n{\n    public class MeetingGroupProposalAcceptedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupProposalAcceptedDomainEvent(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/Events/MeetingGroupProposalRejectedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events\n{\n    internal class MeetingGroupProposalRejectedDomainEvent : DomainEventBase\n    {\n        internal MeetingGroupProposalRejectedDomainEvent(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        internal MeetingGroupProposalId MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/Events/MeetingGroupProposalVerificationRequestedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events\n{\n    public class MeetingGroupProposalVerificationRequestedDomainEvent : DomainEventBase\n    {\n        internal MeetingGroupProposalVerificationRequestedDomainEvent(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/IMeetingGroupProposalRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public interface IMeetingGroupProposalRepository\n    {\n        Task AddAsync(MeetingGroupProposal meetingGroupProposal);\n\n        Task<MeetingGroupProposal> GetByIdAsync(MeetingGroupProposalId meetingGroupProposalId);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/MeetingGroupLocation.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupLocation : ValueObject\n    {\n        private MeetingGroupLocation(string city, string countryCode)\n        {\n            City = city;\n            CountryCode = countryCode;\n        }\n\n        public string City { get; }\n\n        public string CountryCode { get; }\n\n        public static MeetingGroupLocation Create(string city, string countryCode)\n        {\n            return new MeetingGroupLocation(city, countryCode);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/MeetingGroupProposal.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Rules;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposal : Entity, IAggregateRoot\n    {\n        private string _name;\n\n        private string _description;\n\n        private MeetingGroupLocation _location;\n\n        private DateTime _proposalDate;\n\n        private UserId _proposalUserId;\n\n        private MeetingGroupProposalStatus _status;\n\n        private MeetingGroupProposalDecision _decision;\n\n        private MeetingGroupProposal(\n            MeetingGroupProposalId id,\n            string name,\n            string description,\n            MeetingGroupLocation location,\n            UserId proposalUserId,\n            DateTime proposalDate)\n        {\n            Id = id;\n            _name = name;\n            _description = description;\n            _location = location;\n            _proposalUserId = proposalUserId;\n            _proposalDate = proposalDate;\n\n            _status = MeetingGroupProposalStatus.ToVerify;\n            _decision = MeetingGroupProposalDecision.NoDecision;\n\n            this.AddDomainEvent(new MeetingGroupProposalVerificationRequestedDomainEvent(this.Id));\n        }\n\n        private MeetingGroupProposal()\n        {\n            _decision = MeetingGroupProposalDecision.NoDecision;\n        }\n\n        public MeetingGroupProposalId Id { get; private set; }\n\n        public void Accept(UserId userId)\n        {\n            this.CheckRule(new MeetingGroupProposalCanBeVerifiedOnceRule(_decision));\n\n            _decision = MeetingGroupProposalDecision.AcceptDecision(DateTime.UtcNow, userId);\n\n            _status = _decision.GetStatusForDecision();\n\n            this.AddDomainEvent(new MeetingGroupProposalAcceptedDomainEvent(this.Id));\n        }\n\n        public void Reject(UserId userId, string rejectReason)\n        {\n            this.CheckRule(new MeetingGroupProposalCanBeVerifiedOnceRule(_decision));\n            this.CheckRule(new MeetingGroupProposalRejectionMustHaveAReasonRule(rejectReason));\n\n            _decision = MeetingGroupProposalDecision.RejectDecision(DateTime.UtcNow, userId, rejectReason);\n\n            _status = _decision.GetStatusForDecision();\n\n            this.AddDomainEvent(new MeetingGroupProposalRejectedDomainEvent(this.Id));\n        }\n\n        public static MeetingGroupProposal CreateToVerify(\n            Guid meetingGroupProposalId,\n            string name,\n            string description,\n            MeetingGroupLocation location,\n            UserId proposalUserId,\n            DateTime proposalDate)\n        {\n            var meetingGroupProposal = new MeetingGroupProposal(\n                new MeetingGroupProposalId(meetingGroupProposalId),\n                name,\n                description,\n                location,\n                proposalUserId,\n                proposalDate);\n\n            return meetingGroupProposal;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/MeetingGroupProposalDecision.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposalDecision : ValueObject\n    {\n        private MeetingGroupProposalDecision(DateTime? date, UserId userId, string code, string rejectReason)\n        {\n            this.Date = date;\n            this.UserId = userId;\n            this.Code = code;\n            this.RejectReason = rejectReason;\n        }\n\n        public DateTime? Date { get; }\n\n        public UserId UserId { get; }\n\n        public string Code { get; }\n\n        public string RejectReason { get; }\n\n        internal static MeetingGroupProposalDecision NoDecision =>\n            new MeetingGroupProposalDecision(null, null, null, null);\n\n        private bool IsAccepted => this.Code == \"Accept\";\n\n        private bool IsRejected => this.Code == \"Reject\";\n\n        internal static MeetingGroupProposalDecision AcceptDecision(DateTime date, UserId userId)\n        {\n            return new MeetingGroupProposalDecision(date, userId, \"Accept\", null);\n        }\n\n        internal static MeetingGroupProposalDecision RejectDecision(DateTime date, UserId userId, string rejectReason)\n        {\n            return new MeetingGroupProposalDecision(date, userId, \"Reject\", rejectReason);\n        }\n\n        internal MeetingGroupProposalStatus GetStatusForDecision()\n        {\n            if (this.IsAccepted)\n            {\n                return MeetingGroupProposalStatus.Verified;\n            }\n\n            if (this.IsRejected)\n            {\n                return MeetingGroupProposalStatus.Create(\"Rejected\");\n            }\n\n            return MeetingGroupProposalStatus.ToVerify;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/MeetingGroupProposalId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposalId : TypedIdValueBase\n    {\n        public MeetingGroupProposalId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/MeetingGroupProposalStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposalStatus : ValueObject\n    {\n        private MeetingGroupProposalStatus(string value)\n        {\n            Value = value;\n        }\n\n        public static MeetingGroupProposalStatus ToVerify => new MeetingGroupProposalStatus(\"ToVerify\");\n\n        public static MeetingGroupProposalStatus Verified => new MeetingGroupProposalStatus(\"Verified\");\n\n        public string Value { get; }\n\n        internal static MeetingGroupProposalStatus Create(string value)\n        {\n            return new MeetingGroupProposalStatus(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/Rules/MeetingGroupProposalCanBeVerifiedOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Rules\n{\n    public class MeetingGroupProposalCanBeVerifiedOnceRule : IBusinessRule\n    {\n        private readonly MeetingGroupProposalDecision _actualDecision;\n\n        internal MeetingGroupProposalCanBeVerifiedOnceRule(MeetingGroupProposalDecision actualDecision)\n        {\n            _actualDecision = actualDecision;\n        }\n\n        public string Message => \"Meeting group proposal can be verified only once\";\n\n        public bool IsBroken() => _actualDecision != MeetingGroupProposalDecision.NoDecision;\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/MeetingGroupProposals/Rules/MeetingGroupProposalRejectionMustHaveAReasonRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Rules\n{\n    public class MeetingGroupProposalRejectionMustHaveAReasonRule : IBusinessRule\n    {\n        private readonly string _reason;\n\n        internal MeetingGroupProposalRejectionMustHaveAReasonRule(string reason)\n        {\n            _reason = reason;\n        }\n\n        public string Message => \"Meeting group proposal rejection must have a reason\";\n\n        public bool IsBroken() => string.IsNullOrEmpty(_reason);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Members/Events/MemberCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.Members.Events\n{\n    public class MemberCreatedDomainEvent : DomainEventBase\n    {\n        public MemberCreatedDomainEvent(MemberId memberId)\n        {\n            MemberId = memberId;\n        }\n\n        public MemberId MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Members/IMemberRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Domain.Members\n{\n    public interface IMemberRepository\n    {\n        Task AddAsync(Member member);\n\n        Task<Member> GetByIdAsync(MemberId memberId);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Members/Member.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Members.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.Members\n{\n    public class Member : Entity, IAggregateRoot\n    {\n        public MemberId Id { get; private set; }\n\n        private string _login;\n\n        private string _email;\n\n        private string _firstName;\n\n        private string _lastName;\n\n        private string _name;\n\n        private DateTime _createDate;\n\n        private Member()\n        {\n            // Only for EF.\n        }\n\n        private Member(Guid id, string login, string email, string firstName, string lastName, string name)\n        {\n            this.Id = new MemberId(id);\n            _login = login;\n            _email = email;\n            _firstName = firstName;\n            _lastName = lastName;\n            _name = name;\n            _createDate = DateTime.UtcNow;\n\n            this.AddDomainEvent(new MemberCreatedDomainEvent(this.Id));\n        }\n\n        public static Member Create(Guid id, string login, string email, string firstName, string lastName, string name)\n        {\n            return new Member(id, login, email, firstName, lastName, name);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Members/MemberId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.Members\n{\n    public class MemberId : TypedIdValueBase\n    {\n        public MemberId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Users/IUserContext.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Domain.Users\n{\n    public interface IUserContext\n    {\n        UserId UserId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Domain/Users/UserId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.Users\n{\n    public class UserId : TypedIdValueBase\n    {\n        public UserId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/AdministrationContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure\n{\n    public class AdministrationContext : DbContext\n    {\n        private readonly ILoggerFactory _loggerFactory;\n\n        public DbSet<InternalCommand> InternalCommands { get; set; }\n\n        internal DbSet<MeetingGroupProposal> MeetingGroupProposals { get; set; }\n\n        internal DbSet<OutboxMessage> OutboxMessages { get; set; }\n\n        internal DbSet<Member> Members { get; set; }\n\n        public AdministrationContext(DbContextOptions options, ILoggerFactory loggerFactory)\n            : base(options)\n        {\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.ApplyConfiguration(new MeetingGroupProposalEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new OutboxMessageEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new InternalCommandEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new MemberEntityTypeConfiguration());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/AdministrationModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure\n{\n    public class AdministrationModule : IAdministrationModule\n    {\n        public async Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command)\n        {\n            return await CommandsExecutor.Execute(command);\n        }\n\n        public async Task ExecuteCommandAsync(ICommand command)\n        {\n            await CommandsExecutor.Execute(command);\n        }\n\n        public async Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)\n        {\n            using (var scope = AdministrationCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n\n                return await mediator.Send(query);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/CompanyName.MyMeetings.Modules.Administration.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/AdministrationCompositionRoot.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration\n{\n    internal static class AdministrationCompositionRoot\n    {\n        private static IContainer _container;\n\n        public static void SetContainer(IContainer container)\n        {\n            _container = container;\n        }\n\n        public static ILifetimeScope BeginLifetimeScope()\n        {\n            return _container.BeginLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/AdministrationStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.RequestMeetingGroupProposalVerification;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Authentication;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.DataAccess;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.EventsBus;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Logging;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Mediation;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Quartz;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration\n{\n    public class AdministrationStartup\n    {\n        private static IContainer _container;\n\n        public static void Initialize(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            IEventsBus eventsBus,\n            long? internalProcessingPoolingInterval = null)\n        {\n            var moduleLogger = logger.ForContext(\"Module\", \"Administration\");\n\n            ConfigureContainer(connectionString, executionContextAccessor, moduleLogger, eventsBus);\n\n            QuartzStartup.Initialize(moduleLogger, internalProcessingPoolingInterval);\n\n            EventsBusStartup.Initialize(moduleLogger);\n        }\n\n        public static void Stop()\n        {\n            QuartzStartup.StopQuartz();\n        }\n\n        private static void ConfigureContainer(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            IEventsBus eventsBus)\n        {\n            var containerBuilder = new ContainerBuilder();\n\n            containerBuilder.RegisterModule(new LoggingModule(logger));\n\n            var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(logger);\n            containerBuilder.RegisterModule(new DataAccessModule(connectionString, loggerFactory));\n\n            containerBuilder.RegisterModule(new ProcessingModule());\n            containerBuilder.RegisterModule(new EventsBusModule(eventsBus));\n            containerBuilder.RegisterModule(new MediatorModule());\n            containerBuilder.RegisterModule(new AuthenticationModule());\n\n            var domainNotificationsMap = new BiDictionary<string, Type>();\n            domainNotificationsMap.Add(\"MeetingGroupProposalAcceptedNotification\", typeof(MeetingGroupProposalAcceptedNotification));\n            containerBuilder.RegisterModule(new OutboxModule(domainNotificationsMap));\n\n            BiDictionary<string, Type> internalCommandsMap = new BiDictionary<string, Type>();\n            internalCommandsMap.Add(\"CreateMember\", typeof(CreateMemberCommand));\n            internalCommandsMap.Add(\"RequestMeetingGroupProposalVerification\", typeof(RequestMeetingGroupProposalVerificationCommand));\n            containerBuilder.RegisterModule(new InternalCommandsModule(internalCommandsMap));\n\n            containerBuilder.RegisterModule(new QuartzModule());\n\n            containerBuilder.RegisterInstance(executionContextAccessor);\n\n            _container = containerBuilder.Build();\n\n            AdministrationCompositionRoot.SetContainer(_container);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/AllConstructorFinder.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing Autofac.Core.Activators.Reflection;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration\n{\n    internal class AllConstructorFinder : IConstructorFinder\n    {\n        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =\n            new ConcurrentDictionary<Type, ConstructorInfo[]>();\n\n        public ConstructorInfo[] FindConstructors(Type targetType)\n        {\n            var result = Cache.GetOrAdd(\n                targetType,\n                t => t.GetTypeInfo().DeclaredConstructors.ToArray());\n\n            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType, this);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Assemblies.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration\n{\n    internal static class Assemblies\n    {\n        public static readonly Assembly Application = typeof(IAdministrationModule).Assembly;\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Authentication/AuthenticationModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Authentication\n{\n    internal class AuthenticationModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<UserContext>()\n                .As<IUserContext>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/DataAccess/DataAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.DataAccess\n{\n    internal class DataAccessModule : Autofac.Module\n    {\n        private readonly string _databaseConnectionString;\n        private readonly ILoggerFactory _loggerFactory;\n\n        internal DataAccessModule(string databaseConnectionString, ILoggerFactory loggerFactory)\n        {\n            _databaseConnectionString = databaseConnectionString;\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlConnectionFactory>()\n                .As<ISqlConnectionFactory>()\n                .WithParameter(\"connectionString\", _databaseConnectionString)\n                .InstancePerLifetimeScope();\n\n            builder\n                .Register(c =>\n                {\n                    var dbContextOptionsBuilder = new DbContextOptionsBuilder<AdministrationContext>();\n                    dbContextOptionsBuilder.UseSqlServer(_databaseConnectionString);\n\n                    dbContextOptionsBuilder\n                        .ReplaceService<IValueConverterSelector, StronglyTypedIdValueConverterSelector>();\n\n                    return new AdministrationContext(dbContextOptionsBuilder.Options, _loggerFactory);\n                })\n                .AsSelf()\n                .As<DbContext>()\n                .InstancePerLifetimeScope();\n\n            var infrastructureAssembly = typeof(AdministrationContext).Assembly;\n\n            builder.RegisterAssemblyTypes(infrastructureAssembly)\n                .Where(type => type.Name.EndsWith(\"Repository\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/EventsBus/EventsBusModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.EventsBus\n{\n    internal class EventsBusModule : Autofac.Module\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public EventsBusModule(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_eventsBus != null)\n            {\n                builder.RegisterInstance(_eventsBus).SingleInstance();\n            }\n            else\n            {\n                builder.RegisterType<InMemoryEventBusClient>()\n                    .As<IEventsBus>()\n                    .SingleInstance();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/EventsBus/EventsBusStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.EventsBus\n{\n    internal static class EventsBusStartup\n    {\n        internal static void Initialize(\n            ILogger logger)\n        {\n            SubscribeToIntegrationEvents(logger);\n        }\n\n        private static void SubscribeToIntegrationEvents(ILogger logger)\n        {\n            var eventBus = AdministrationCompositionRoot.BeginLifetimeScope().Resolve<IEventsBus>();\n\n            SubscribeToIntegrationEvent<MeetingGroupProposedIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<NewUserRegisteredIntegrationEvent>(eventBus, logger);\n        }\n\n        private static void SubscribeToIntegrationEvent<T>(IEventsBus eventBus, ILogger logger)\n            where T : IntegrationEvent\n        {\n            logger.Information(\"Subscribe to {@IntegrationEvent}\", typeof(T).FullName);\n            eventBus.Subscribe(\n                new IntegrationEventGenericHandler<T>());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/EventsBus/IntegrationEventGenericHandler.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.EventsBus\n{\n    internal class IntegrationEventGenericHandler<T> : IIntegrationEventHandler<T>\n        where T : IntegrationEvent\n    {\n        public async Task Handle(T @event)\n        {\n            using var scope = AdministrationCompositionRoot.BeginLifetimeScope();\n            using var connection = scope.Resolve<ISqlConnectionFactory>().GetOpenConnection();\n\n            string type = @event.GetType().FullName;\n            var data = JsonConvert.SerializeObject(@event, new JsonSerializerSettings\n            {\n                ContractResolver = new AllPropertiesContractResolver()\n            });\n\n            var sql = \"INSERT INTO [administration].[InboxMessages] (Id, OccurredOn, Type, Data) \" +\n                      \"VALUES (@Id, @OccurredOn, @Type, @Data)\";\n\n            await connection.ExecuteScalarAsync(sql, new\n            {\n                @event.Id,\n                @event.OccurredOn,\n                type,\n                data\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Logging/LoggingModule.cs",
    "content": "﻿using Autofac;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Logging\n{\n    internal class LoggingModule : Autofac.Module\n    {\n        private readonly ILogger _logger;\n\n        internal LoggingModule(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterInstance(_logger)\n                .As<ILogger>()\n                .SingleInstance();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Mediation/MediatorModule.cs",
    "content": "﻿using System.Reflection;\nusing Autofac;\nusing Autofac.Core;\nusing Autofac.Features.Variance;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries;\nusing FluentValidation;\nusing MediatR;\nusing MediatR.Pipeline;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Mediation\n{\n    public class MediatorModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<ServiceProviderWrapper>()\n            .As<IServiceProvider>()\n            .InstancePerDependency()\n            .IfNotRegistered(typeof(IServiceProvider));\n\n            builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope();\n\n            var mediatorOpenTypes = new[]\n            {\n                typeof(ICommandHandler<>),\n                typeof(ICommandHandler<,>),\n                typeof(IQueryHandler<,>),\n                typeof(INotificationHandler<>),\n                typeof(IValidator<>),\n                typeof(IRequestPreProcessor<>),\n                typeof(IStreamRequestHandler<,>),\n                typeof(IRequestPostProcessor<,>),\n                typeof(IRequestExceptionHandler<,,>),\n                typeof(IRequestExceptionAction<,>),\n            };\n            builder.RegisterSource(new ScopedContravariantRegistrationSource(\n                mediatorOpenTypes));\n            foreach (var mediatorOpenType in mediatorOpenTypes)\n            {\n                builder\n                    .RegisterAssemblyTypes(Assemblies.Application, ThisAssembly)\n                    .AsClosedTypesOf(mediatorOpenType)\n                    .AsImplementedInterfaces()\n                    .FindConstructorsWith(new AllConstructorFinder());\n            }\n\n            builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n            builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n        }\n\n        private class ScopedContravariantRegistrationSource : IRegistrationSource\n        {\n            private readonly ContravariantRegistrationSource _source = new();\n            private readonly List<Type> _types = new();\n\n            public ScopedContravariantRegistrationSource(params Type[] types)\n            {\n                ArgumentNullException.ThrowIfNull(types);\n\n                if (!types.All(x => x.IsGenericTypeDefinition))\n                {\n                    throw new ArgumentException(\"Supplied types should be generic type definitions\");\n                }\n\n                _types.AddRange(types);\n            }\n\n            public IEnumerable<IComponentRegistration> RegistrationsFor(\n                Service service,\n                Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)\n            {\n                var components = _source.RegistrationsFor(service, registrationAccessor);\n                foreach (var c in components)\n                {\n                    var defs = c.Target.Services\n                        .OfType<TypedService>()\n                        .Select(x => x.ServiceType.GetGenericTypeDefinition());\n\n                    if (defs.Any(_types.Contains))\n                    {\n                        yield return c;\n                    }\n                }\n            }\n\n            public bool IsAdapterForIndividualComponents => _source.IsAdapterForIndividualComponents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/CommandsExecutor.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal static class CommandsExecutor\n    {\n        internal static async Task Execute(ICommand command)\n        {\n            using (var scope = AdministrationCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                await mediator.Send(command);\n            }\n        }\n\n        internal static async Task<TResult> Execute<TResult>(ICommand<TResult> command)\n        {\n            using (var scope = AdministrationCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                return await mediator.Send(command);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Inbox/InboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Inbox\n{\n    public class InboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Inbox\n{\n    public class ProcessInboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Inbox\r\n{\r\n    internal class ProcessInboxCommandHandler : ICommandHandler<ProcessInboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInboxCommandHandler(IMediator mediator, ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                               SELECT \r\n                                   [InboxMessage].[Id] AS [{nameof(InboxMessageDto.Id)}], \r\n                                   [InboxMessage].[Type] AS [{nameof(InboxMessageDto.Type)}], \r\n                                   [InboxMessage].[Data] AS [{nameof(InboxMessageDto.Data)}] \r\n                               FROM [administration].[InboxMessages] AS [InboxMessage] \r\n                               WHERE [InboxMessage].[ProcessedDate] IS NULL \r\n                               ORDER BY [InboxMessage].[OccurredOn]\r\n                               \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<InboxMessageDto>(sql);\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [administration].[InboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n\r\n            foreach (var message in messages)\r\n            {\r\n                var messageAssembly = AppDomain.CurrentDomain.GetAssemblies()\r\n                    .SingleOrDefault(assembly => message.Type.Contains(assembly.GetName().Name));\r\n\r\n                Type type = messageAssembly.GetType(message.Type);\r\n                var request = JsonConvert.DeserializeObject(message.Data, type);\r\n\r\n                try\r\n                {\r\n                    await _mediator.Publish((INotification)request, cancellationToken);\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    Console.WriteLine(e);\r\n                    throw;\r\n                }\r\n\r\n                await connection.ExecuteScalarAsync(sqlUpdateProcessedDate, new\r\n                {\r\n                    Date = DateTime.UtcNow,\r\n                    message.Id\r\n                });\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Inbox/ProcessInboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Inbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/InternalCommands/CommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands\n{\n    public class CommandsScheduler : ICommandsScheduler\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IInternalCommandsMapper _internalCommandsMapper;\n\n        public CommandsScheduler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IInternalCommandsMapper internalCommandsMapper)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _internalCommandsMapper = internalCommandsMapper;\n        }\n\n        public async Task EnqueueAsync(ICommand command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [administration].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = _internalCommandsMapper.GetName(command.GetType()),\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n\n        public async Task EnqueueAsync<T>(ICommand<T> command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [administration].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = _internalCommandsMapper.GetName(command.GetType()),\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/InternalCommands/InternalCommandsModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing Module = Autofac.Module;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class InternalCommandsModule : Module\n    {\n        private readonly BiDictionary<string, Type> _internalCommandsMap;\n\n        public InternalCommandsModule(BiDictionary<string, Type> internalCommandsMap)\n        {\n            _internalCommandsMap = internalCommandsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<InternalCommandsMapper>()\n                .As<IInternalCommandsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"internalCommandsMap\", _internalCommandsMap)\n                .SingleInstance();\n\n            this.CheckMappings();\n        }\n\n        private void CheckMappings()\n        {\n            var internalCommands = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.BaseType != null &&\n                            (\n                                (x.BaseType.IsGenericType &&\n                                x.BaseType.GetGenericTypeDefinition() == typeof(InternalCommandBase<>)) ||\n                                x.BaseType == typeof(InternalCommandBase)))\n                .ToList();\n\n            List<Type> notMappedInternalCommands = [];\n            foreach (var internalCommand in internalCommands)\n            {\n                _internalCommandsMap.TryGetBySecond(internalCommand, out var name);\n\n                if (name == null)\n                {\n                    notMappedInternalCommands.Add(internalCommand);\n                }\n            }\n\n            if (notMappedInternalCommands.Any())\n            {\n                throw new ApplicationException($\"Internal Commands {notMappedInternalCommands.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing Newtonsoft.Json;\r\nusing Polly;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands\r\n{\r\n    internal class ProcessInternalCommandsCommandHandler : ICommandHandler<ProcessInternalCommandsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly IInternalCommandsMapper _internalCommandsMapper;\r\n\r\n        public ProcessInternalCommandsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IInternalCommandsMapper internalCommandsMapper)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _internalCommandsMapper = internalCommandsMapper;\r\n        }\r\n\r\n        public async Task Handle(ProcessInternalCommandsCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n\r\n            const string sql = $\"\"\"\r\n                          SELECT\r\n                              [Command].[Id] AS [{nameof(InternalCommandDto.Id)}], \r\n                              [Command].[Type] AS [{nameof(InternalCommandDto.Type)}], \r\n                              [Command].[Data] AS [{nameof(InternalCommandDto.Data)}] \r\n                          FROM [administration].[InternalCommands] AS [Command] \r\n                          WHERE [Command].[ProcessedDate] IS NULL \r\n                          ORDER BY [Command].[EnqueueDate]\r\n                          \"\"\";\r\n\r\n            var commands = await connection.QueryAsync<InternalCommandDto>(sql);\r\n\r\n            var internalCommandsList = commands.AsList();\r\n            var policy = Policy\r\n                .Handle<Exception>()\r\n                .WaitAndRetryAsync(new[]\r\n                {\r\n                    TimeSpan.FromSeconds(1),\r\n                    TimeSpan.FromSeconds(2),\r\n                    TimeSpan.FromSeconds(3)\r\n                });\r\n            foreach (var internalCommand in internalCommandsList)\r\n            {\r\n                var result = await policy.ExecuteAndCaptureAsync(() => ProcessCommand(\r\n                    internalCommand));\r\n\r\n                if (result.Outcome == OutcomeType.Failure)\r\n                {\r\n                    const string updateOnErrorSql = \"UPDATE [administration].[InternalCommands] \" +\r\n                                                    \"SET ProcessedDate = @NowDate, \" +\r\n                                                    \"Error = @Error \" +\r\n                                                    \"WHERE [Id] = @Id\";\r\n\r\n                    await connection.ExecuteScalarAsync(\r\n                        updateOnErrorSql,\r\n                        new\r\n                        {\r\n                            NowDate = DateTime.UtcNow,\r\n                            Error = result.FinalException.ToString(),\r\n                            internalCommand.Id\r\n                        });\r\n                }\r\n            }\r\n        }\r\n\r\n        private async Task ProcessCommand(\r\n            InternalCommandDto internalCommand)\r\n        {\r\n            var type = _internalCommandsMapper.GetType(internalCommand.Type);\r\n            dynamic commandToProcess = JsonConvert.DeserializeObject(internalCommand.Data, type);\r\n\r\n            await CommandsExecutor.Execute(commandToProcess);\r\n        }\r\n\r\n        private class InternalCommandDto\r\n        {\r\n            public Guid Id { get; set; }\r\n\r\n            public string Type { get; set; }\r\n\r\n            public string Data { get; set; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInternalCommandsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInternalCommandsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/LoggingCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\r\nusing Serilog;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\r\n{\r\n    internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ILogger _logger;\r\n        private readonly IExecutionContextAccessor _executionContextAccessor;\r\n        private readonly ICommandHandler<T> _decorated;\r\n\r\n        public LoggingCommandHandlerDecorator(\r\n            ILogger logger,\r\n            IExecutionContextAccessor executionContextAccessor,\r\n            ICommandHandler<T> decorated)\r\n        {\r\n            _logger = logger;\r\n            _executionContextAccessor = executionContextAccessor;\r\n            _decorated = decorated;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            if (command is IRecurringCommand)\r\n            {\r\n                await _decorated.Handle(command, cancellationToken);\r\n\r\n                return;\r\n            }\r\n\r\n            using (\r\n                LogContext.Push(\r\n                    new RequestLogEnricher(_executionContextAccessor),\r\n                    new CommandLogEnricher(command)))\r\n            {\r\n                try\r\n                {\r\n                    this._logger.Information(\r\n                        \"Executing command {Command}\",\r\n                        command.GetType().Name);\r\n\r\n                    await _decorated.Handle(command, cancellationToken);\r\n\r\n                    this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\r\n                }\r\n                catch (Exception exception)\r\n                {\r\n                    this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\r\n                    throw;\r\n                }\r\n            }\r\n        }\r\n\r\n        private class CommandLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly ICommand _command;\r\n\r\n            public CommandLogEnricher(ICommand command)\r\n            {\r\n                _command = command;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\r\n            }\r\n        }\r\n\r\n        private class RequestLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IExecutionContextAccessor _executionContextAccessor;\r\n\r\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\r\n            {\r\n                _executionContextAccessor = executionContextAccessor;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                if (_executionContextAccessor.IsAvailable)\r\n                {\r\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/LoggingCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public LoggingCommandHandlerWithResultDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T, TResult> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                return await _decorated.Handle(command, cancellationToken);\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {@Command}\",\n                        command);\n\n                    var result = await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command processed successful, result {Result}\", result);\n\n                    return result;\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command processing failed\");\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand<TResult> _command;\n\n            public CommandLogEnricher(ICommand<TResult> command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Outbox/OutboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox\n{\n    public class OutboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Outbox/OutboxModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Outbox;\nusing Module = Autofac.Module;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class OutboxModule : Module\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public OutboxModule(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<OutboxAccessor>()\n                .As<IOutbox>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .InstancePerLifetimeScope();\n\n            this.CheckMappings();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"domainNotificationsMap\", _domainNotificationsMap)\n                .SingleInstance();\n        }\n\n        private void CheckMappings()\n        {\n            var domainEventNotifications = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.GetInterfaces().Contains(typeof(IDomainEventNotification)))\n                .ToList();\n\n            List<Type> notMappedNotifications = [];\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                _domainNotificationsMap.TryGetBySecond(domainEventNotification, out var name);\n\n                if (name == null)\n                {\n                    notMappedNotifications.Add(domainEventNotification);\n                }\n            }\n\n            if (notMappedNotifications.Any())\n            {\n                throw new ApplicationException($\"Domain Event Notifications {notMappedNotifications.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox\n{\n    public class ProcessOutboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox\r\n{\r\n    internal class ProcessOutboxCommandHandler : ICommandHandler<ProcessOutboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\r\n\r\n        public ProcessOutboxCommandHandler(\r\n            IMediator mediator,\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IDomainNotificationsMapper domainNotificationsMapper)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _domainNotificationsMapper = domainNotificationsMapper;\r\n        }\r\n\r\n        public async Task Handle(ProcessOutboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                                SELECT\r\n                                    [OutboxMessage].[Id] AS [{nameof(OutboxMessageDto.Id)}],\r\n                                    [OutboxMessage].[Type] AS [{nameof(OutboxMessageDto.Type)}],\r\n                                    [OutboxMessage].[Data] AS [{nameof(OutboxMessageDto.Data)}]\r\n                                FROM [administration].[OutboxMessages] AS [OutboxMessage]\r\n                                WHERE [OutboxMessage].[ProcessedDate] IS NULL\r\n                                ORDER BY [OutboxMessage].[OccurredOn]\r\n                                \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\r\n            var messagesList = messages.AsList();\r\n\r\n            const string sqlUpdateProcessedDate = \"UPDATE [administration].[OutboxMessages] \" +\r\n                                                  \"SET [ProcessedDate] = @Date \" +\r\n                                                  \"WHERE [Id] = @Id\";\r\n            if (messagesList.Count > 0)\r\n            {\r\n                foreach (var message in messagesList)\r\n                {\r\n                    var type = _domainNotificationsMapper.GetType(message.Type);\r\n                    var @event = JsonConvert.DeserializeObject(message.Data, type) as IDomainEventNotification;\r\n\r\n                    using (LogContext.Push(new OutboxMessageContextEnricher(@event)))\r\n                    {\r\n                        await this._mediator.Publish(@event, cancellationToken);\r\n\r\n                        await connection.ExecuteAsync(sqlUpdateProcessedDate, new\r\n                        {\r\n                            Date = DateTime.UtcNow,\r\n                            message.Id\r\n                        });\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private class OutboxMessageContextEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IDomainEventNotification _notification;\r\n\r\n            public OutboxMessageContextEnricher(IDomainEventNotification notification)\r\n            {\r\n                _notification = notification;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"OutboxMessage:{_notification.Id.ToString()}\")));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessOutboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessOutboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/ProcessingModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal class ProcessingModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<DomainEventsDispatcher>()\n                .As<IDomainEventsDispatcher>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainEventsAccessor>()\n                .As<IDomainEventsAccessor>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<UnitOfWork>()\n                .As<IUnitOfWork>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<CommandsScheduler>()\n                .As<ICommandsScheduler>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerDecorator<>),\n                typeof(IRequestHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerWithResultDecorator<,>),\n                typeof(IRequestHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(DomainEventsDispatcherNotificationHandlerDecorator<>),\n                typeof(INotificationHandler<>));\n\n            builder.RegisterAssemblyTypes(Assemblies.Application)\n                .AsClosedTypesOf(typeof(IDomainEventNotification<>))\n                .InstancePerDependency()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\r\nusing Microsoft.EntityFrameworkCore;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\r\n{\r\n    internal class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly AdministrationContext _administrationContext;\r\n        private readonly ICommandHandler<T> _decorated;\r\n        private readonly IUnitOfWork _unitOfWork;\r\n\r\n        public UnitOfWorkCommandHandlerDecorator(\r\n            ICommandHandler<T> decorated,\r\n            IUnitOfWork unitOfWork,\r\n            AdministrationContext administrationContext)\r\n        {\r\n            _decorated = decorated;\r\n            _unitOfWork = unitOfWork;\r\n            _administrationContext = administrationContext;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            await _decorated.Handle(command, cancellationToken);\r\n\r\n            if (command is InternalCommandBase)\r\n            {\r\n                InternalCommand internalCommand = await _administrationContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken);\r\n\r\n                if (internalCommand != null)\r\n                {\r\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\r\n                }\r\n            }\r\n\r\n            await _unitOfWork.CommitAsync(cancellationToken);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ICommandHandler<T, TResult> _decorated;\n        private readonly IUnitOfWork _unitOfWork;\n        private readonly AdministrationContext _administrationContext;\n\n        public UnitOfWorkCommandHandlerWithResultDecorator(\n            ICommandHandler<T, TResult> decorated,\n            IUnitOfWork unitOfWork,\n            AdministrationContext administrationContext)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n            _administrationContext = administrationContext;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var result = await this._decorated.Handle(command, cancellationToken);\n\n            if (command is InternalCommandBase<TResult>)\n            {\n                var internalCommand = await _administrationContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\n\n                if (internalCommand != null)\n                {\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\n                }\n            }\n\n            await this._unitOfWork.CommitAsync(cancellationToken);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T> _decorated;\n\n        public ValidationCommandHandlerDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            await _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Quartz/QuartzModule.cs",
    "content": "﻿using Autofac;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Quartz\n{\n    public class QuartzModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterAssemblyTypes(ThisAssembly)\n                .Where(x => typeof(IJob).IsAssignableFrom(x)).InstancePerDependency();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Quartz/QuartzStartup.cs",
    "content": "﻿using System.Collections.Specialized;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Inbox;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox;\nusing Quartz;\nusing Quartz.Impl;\nusing Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Quartz\n{\n    internal static class QuartzStartup\n    {\n        private static IScheduler _scheduler;\n\n        internal static void Initialize(ILogger logger, long? internalProcessingPoolingInterval)\n        {\n            logger.Information(\"Quartz starting...\");\n\n            var schedulerConfiguration = new NameValueCollection();\n            schedulerConfiguration.Add(\"quartz.scheduler.instanceName\", \"Administration\");\n\n            ISchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerConfiguration);\n            _scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult();\n\n            LogProvider.SetCurrentLogProvider(new SerilogLogProvider(logger));\n\n            _scheduler.Start().GetAwaiter().GetResult();\n\n            var processOutboxJob = JobBuilder.Create<ProcessOutboxJob>().Build();\n\n            ITrigger trigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            _scheduler\n                .ScheduleJob(processOutboxJob, trigger)\n                .GetAwaiter().GetResult();\n\n            var processInboxJob = JobBuilder.Create<ProcessInboxJob>().Build();\n            var processInboxTrigger =\n                TriggerBuilder\n                    .Create()\n                    .StartNow()\n                    .WithCronSchedule(\"0/2 * * ? * *\")\n                    .Build();\n\n            _scheduler\n                .ScheduleJob(processInboxJob, processInboxTrigger)\n                .GetAwaiter().GetResult();\n\n            var processInternalCommandsJob = JobBuilder.Create<ProcessInternalCommandsJob>().Build();\n            var triggerCommandsProcessing =\n                TriggerBuilder\n                    .Create()\n                    .StartNow()\n                    .WithCronSchedule(\"0/2 * * ? * *\")\n                    .Build();\n            _scheduler.ScheduleJob(processInternalCommandsJob, triggerCommandsProcessing).GetAwaiter().GetResult();\n\n            logger.Information(\"Quartz started.\");\n        }\n\n        internal static void StopQuartz()\n        {\n            _scheduler.Shutdown();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Quartz/SerilogLogProvider.cs",
    "content": "﻿using Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Quartz\n{\n    internal class SerilogLogProvider : ILogProvider\n    {\n        private readonly ILogger _logger;\n\n        internal SerilogLogProvider(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public Logger GetLogger(string name)\n        {\n            return (level, func, exception, parameters) =>\n            {\n                if (func == null)\n                {\n                    return true;\n                }\n\n                if (level == LogLevel.Debug || level == LogLevel.Trace)\n                {\n                    _logger.Debug(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Info)\n                {\n                    _logger.Information(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Warn)\n                {\n                    _logger.Warning(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Error)\n                {\n                    _logger.Error(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Fatal)\n                {\n                    _logger.Fatal(exception, func(), parameters);\n                }\n\n                return true;\n            };\n        }\n\n        public IDisposable OpenNestedContext(string message)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, string value)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, object value, bool destructure = false)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Configuration/Users/UserContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Users\n{\n    internal class UserContext : IUserContext\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public UserContext(IExecutionContextAccessor executionContextAccessor)\n        {\n            this._executionContextAccessor = executionContextAccessor;\n        }\n\n        public UserId UserId => new UserId(_executionContextAccessor.UserId);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Domain/MeetingGroupProposals/MeetingGroupProposalEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.MeetingGroupProposals\n{\n    internal class MeetingGroupProposalEntityTypeConfiguration : IEntityTypeConfiguration<MeetingGroupProposal>\n    {\n        public void Configure(EntityTypeBuilder<MeetingGroupProposal> builder)\n        {\n            builder.ToTable(\"MeetingGroupProposals\", \"administration\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n            builder.Property<string>(\"_description\").HasColumnName(\"Description\");\n            builder.Property<UserId>(\"_proposalUserId\").HasColumnName(\"ProposalUserId\");\n            builder.Property<DateTime>(\"_proposalDate\").HasColumnName(\"ProposalDate\");\n\n            builder.OwnsOne<MeetingGroupLocation>(\"_location\", b =>\n            {\n                b.Property(p => p.City).HasColumnName(\"LocationCity\");\n                b.Property(p => p.CountryCode).HasColumnName(\"LocationCountryCode\");\n            });\n\n            builder.OwnsOne<MeetingGroupProposalStatus>(\"_status\", b =>\n            {\n                b.Property(p => p.Value).HasColumnName(\"StatusCode\");\n            });\n\n            builder.OwnsOne<MeetingGroupProposalDecision>(\"_decision\", b =>\n            {\n                b.Property(p => p.Code).HasColumnName(\"DecisionCode\");\n                b.Property(p => p.Date).HasColumnName(\"DecisionDate\");\n                b.Property(p => p.RejectReason).HasColumnName(\"DecisionRejectReason\");\n                b.Property(p => p.UserId).HasColumnName(\"DecisionUserId\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Domain/MeetingGroupProposals/MeetingGroupProposalRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.MeetingGroupProposals\n{\n    internal class MeetingGroupProposalRepository : IMeetingGroupProposalRepository\n    {\n        private readonly AdministrationContext _context;\n\n        internal MeetingGroupProposalRepository(AdministrationContext context)\n        {\n            _context = context;\n        }\n\n        public async Task AddAsync(MeetingGroupProposal meetingGroupProposal)\n        {\n            await _context.MeetingGroupProposals.AddAsync(meetingGroupProposal);\n        }\n\n        public async Task<MeetingGroupProposal> GetByIdAsync(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            return await _context.MeetingGroupProposals.FirstOrDefaultAsync(x => x.Id == meetingGroupProposalId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Domain/Members/MemberEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.Members\n{\n    internal class MemberEntityTypeConfiguration : IEntityTypeConfiguration<Member>\n    {\n        public void Configure(EntityTypeBuilder<Member> builder)\n        {\n            builder.ToTable(\"Members\", \"administration\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_login\").HasColumnName(\"Login\");\n            builder.Property<string>(\"_email\").HasColumnName(\"Email\");\n            builder.Property<string>(\"_firstName\").HasColumnName(\"FirstName\");\n            builder.Property<string>(\"_lastName\").HasColumnName(\"LastName\");\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Domain/Members/MemberRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Domain.Members\n{\n    internal class MemberRepository : IMemberRepository\n    {\n        private readonly AdministrationContext _administrationContext;\n\n        internal MemberRepository(AdministrationContext meetingsContext)\n        {\n            _administrationContext = meetingsContext;\n        }\n\n        public async Task AddAsync(Member member)\n        {\n            await _administrationContext.Members.AddAsync(member);\n        }\n\n        public async Task<Member> GetByIdAsync(MemberId memberId)\n        {\n            return await _administrationContext.Members.FirstOrDefaultAsync(x => x.Id == memberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/InternalCommands/InternalCommandEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.InternalCommands\n{\n    internal class InternalCommandEntityTypeConfiguration : IEntityTypeConfiguration<InternalCommand>\n    {\n        public void Configure(EntityTypeBuilder<InternalCommand> builder)\n        {\n            builder.ToTable(\"InternalCommands\", \"administration\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Outbox/OutboxAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Outbox\n{\n    internal class OutboxAccessor : IOutbox\n    {\n        private readonly AdministrationContext _context;\n\n        internal OutboxAccessor(AdministrationContext context)\n        {\n            _context = context;\n        }\n\n        public void Add(OutboxMessage message)\n        {\n            _context.OutboxMessages.Add(message);\n        }\n\n        public Task Save()\n        {\n            // Save is done automatically using EF Core Change Tracking mechanism during SaveChanges.\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Infrastructure/Outbox/OutboxMessageEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Infrastructure.Outbox\n{\n    internal class OutboxMessageEntityTypeConfiguration : IEntityTypeConfiguration<OutboxMessage>\n    {\n        public void Configure(EntityTypeBuilder<OutboxMessage> builder)\n        {\n            builder.ToTable(\"OutboxMessages\", \"administration\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/IntegrationEvents/CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Administration/IntegrationEvents/MeetingGroupProposals/MeetingGroupProposalAcceptedIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.MeetingGroupProposals\n{\n    public class MeetingGroupProposalAcceptedIntegrationEvent : IntegrationEvent\n    {\n        public MeetingGroupProposalAcceptedIntegrationEvent(\n            Guid id,\n            DateTime occurredOn,\n            Guid meetingGroupProposalId)\n            : base(id, occurredOn)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        public Guid MeetingGroupProposalId { get; }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Administration/Tests/ArchTests/Application/ApplicationTests.cs",
    "content": "using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.ArchTests.SeedWork;\nusing FluentValidation;\nusing MediatR;\nusing NetArchTest.Rules;\nusing Newtonsoft.Json;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.ArchTests.Application\n{\n    [TestFixture]\n    public class ApplicationTests : TestBase\n    {\n        [Test]\n        public void Command_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(CommandBase))\n                .Or()\n                .Inherit(typeof(CommandBase<>))\n                .Or()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .Or()\n                .ImplementInterface(typeof(ICommand))\n                .Or()\n                .ImplementInterface(typeof(ICommand<>))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Query_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(typeof(IQuery<>)).GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void CommandHandler_Should_Have_Name_EndingWith_CommandHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(ICommandHandler<>))\n                    .Or()\n                .ImplementInterface(typeof(ICommandHandler<,>))\n                .And()\n                .DoNotHaveNameMatching(\".*Decorator.*\").Should()\n                .HaveNameEndingWith(\"CommandHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void QueryHandler_Should_Have_Name_EndingWith_QueryHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(IQueryHandler<,>))\n                .Should()\n                .HaveNameEndingWith(\"QueryHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Command_And_Query_Handlers_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                    .ImplementInterface(typeof(IQueryHandler<,>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<,>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void Validator_Should_Have_Name_EndingWith_Validator()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should()\n                .HaveNameEndingWith(\"Validator\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Validators_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void InternalCommand_Should_Have_JsonConstructorAttribute()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n\n            foreach (var type in types)\n            {\n                bool hasJsonConstructorDefined = false;\n                var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var jsonConstructorAttribute = constructorInfo.GetCustomAttributes(typeof(JsonConstructorAttribute), false);\n                    if (jsonConstructorAttribute.Length > 0)\n                    {\n                        hasJsonConstructorDefined = true;\n                        break;\n                    }\n                }\n\n                if (!hasJsonConstructorDefined)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void MediatR_RequestHandler_Should_NotBe_Used_Directly()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().DoNotHaveName(\"ICommandHandler`1\")\n                .Should().ImplementInterface(typeof(IRequestHandler<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                bool isCommandHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));\n                bool isCommandWithResultHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<,>));\n                bool isQueryHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(IQueryHandler<,>));\n                if (!isCommandHandler && !isCommandWithResultHandler && !isQueryHandler)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Command_With_Result_Should_Not_Return_Unit()\n        {\n            Type commandWithResultHandlerType = typeof(ICommandHandler<,>);\n            IEnumerable<Type> types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(commandWithResultHandlerType)\n                .GetTypes().ToList();\n\n            List<Type> failingTypes = [];\n            foreach (Type type in types)\n            {\n                Type interfaceType = type.GetInterface(commandWithResultHandlerType.Name);\n                if (interfaceType?.GenericTypeArguments[1] == typeof(Unit))\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/ArchTests/CompanyName.MyMeetings.Modules.Administration.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Administration/Tests/ArchTests/Domain/DomainTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Administration.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.ArchTests.Domain\n{\n    public class DomainTests : TestBase\n    {\n        [Test]\n        public void DomainEvent_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                    .Inherit(typeof(DomainEventBase))\n                        .Or()\n                    .ImplementInterface(typeof(IDomainEvent))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void ValueObject_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Entity_Which_Is_Not_Aggregate_Root_Cannot_Have_Public_Members()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity))\n                .And().DoNotImplementInterface(typeof(IAggregateRoot)).GetTypes();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.Public |\n                                              BindingFlags.Instance |\n                                              BindingFlags.Static;\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                var publicFields = type.GetFields(bindingFlags);\n                var publicProperties = type.GetProperties(bindingFlags);\n                var publicMethods = type.GetMethods(bindingFlags);\n\n                if (publicFields.Any() || publicProperties.Any() || publicMethods.Any())\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Cannot_Have_Reference_To_Other_AggregateRoot()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            var aggregateRoots = Types.InAssembly(DomainAssembly)\n                .That().ImplementInterface(typeof(IAggregateRoot)).GetTypes().ToList();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.NonPublic |\n                                              BindingFlags.Instance;\n\n            List<Type> failingTypes = [];\n            foreach (var type in entityTypes)\n            {\n                var fields = type.GetFields(bindingFlags);\n\n                foreach (var field in fields)\n                {\n                    if (aggregateRoots.Contains(field.FieldType) ||\n                        field.FieldType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n\n                var properties = type.GetProperties(bindingFlags);\n                foreach (var property in properties)\n                {\n                    if (aggregateRoots.Contains(property.PropertyType) ||\n                        property.PropertyType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Should_Have_Parameterless_Private_Constructor()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in entityTypes)\n            {\n                bool hasPrivateParameterlessConstructor = false;\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (constructorInfo.IsPrivate && constructorInfo.GetParameters().Length == 0)\n                    {\n                        hasPrivateParameterlessConstructor = true;\n                    }\n                }\n\n                if (!hasPrivateParameterlessConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Domain_Object_Should_Have_Only_Private_Constructors()\n        {\n            var domainObjectTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                        .Inherit(typeof(Entity))\n                    .Or()\n                        .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var domainObjectType in domainObjectTypes)\n            {\n                var constructors = domainObjectType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (!constructorInfo.IsPrivate)\n                    {\n                        failingTypes.Add(domainObjectType);\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void ValueObject_Should_Have_Private_Constructor_With_Parameters_For_His_State()\n        {\n            var valueObjects = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in valueObjects)\n            {\n                bool hasExpectedConstructor = false;\n\n                const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                                  BindingFlags.Public |\n                                                  BindingFlags.Instance;\n                var names = entityType.GetFields(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                var propertyNames = entityType.GetProperties(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                names.AddRange(propertyNames);\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var parameters = constructorInfo.GetParameters().Select(x => x.Name.ToLower()).ToList();\n\n                    if (names.Intersect(parameters).Count() == names.Count)\n                    {\n                        hasExpectedConstructor = true;\n                        break;\n                    }\n                }\n\n                if (!hasExpectedConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void DomainEvent_Should_Have_DomainEventPostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(DomainEventBase))\n                .Or()\n                .ImplementInterface(typeof(IDomainEvent))\n                .Should().HaveNameEndingWith(\"DomainEvent\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void BusinessRule_Should_Have_RulePostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .ImplementInterface(typeof(IBusinessRule))\n                .Should().HaveNameEndingWith(\"Rule\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/ArchTests/Module/LayersTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.ArchTests.Module\n{\n    [TestFixture]\n    public class LayersTests : TestBase\n    {\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToApplicationLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void ApplicationLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .Should()\n                .NotHaveDependencyOn(InfrastructureAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApplicationAssembly => typeof(CreateMemberCommand).Assembly;\n\n        protected static Assembly DomainAssembly => typeof(MeetingGroupProposal).Assembly;\n\n        protected static Assembly InfrastructureAssembly => typeof(AdministrationContext).Assembly;\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Administration.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/MeetingGroupProposals/MeetingGroupProposalSampleData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.MeetingGroupProposals\n{\n    public struct MeetingGroupProposalSampleData\n    {\n        public static Guid MeetingGroupProposalId = Guid.NewGuid();\n\n        public static string Name = \"Great Meeting\";\n\n        public static string Description = \"Great Meeting description\";\n\n        public static string LocationCity = \"Warsaw\";\n\n        public static string LocationCountryCode = \"PL\";\n\n        public static Guid ProposalUserId = Guid.NewGuid();\n\n        public static DateTime ProposalDate = new DateTime(2020, 1, 1, 10, 20, 00);\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/MeetingGroupProposals/MeetingGroupProposalTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.RequestMeetingGroupProposalVerification;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Rules;\nusing CompanyName.MyMeetings.Modules.Administration.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.MeetingGroupProposals\n{\n    [TestFixture]\n    public class MeetingGroupProposalTests : TestBase\n    {\n        [Test]\n        public async Task RequestMeetingGroupProposalVerification_Test()\n        {\n            var proposalId = await AdministrationModule.ExecuteCommandAsync(new RequestMeetingGroupProposalVerificationCommand(\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.Name,\n                MeetingGroupProposalSampleData.Description,\n                MeetingGroupProposalSampleData.LocationCity,\n                MeetingGroupProposalSampleData.LocationCountryCode,\n                MeetingGroupProposalSampleData.ProposalUserId,\n                MeetingGroupProposalSampleData.ProposalDate));\n\n            var meetingGroupProposal = await AdministrationModule.ExecuteQueryAsync(new GetMeetingGroupProposalQuery(proposalId));\n\n            Assert.That(meetingGroupProposal.Id, Is.EqualTo(MeetingGroupProposalSampleData.MeetingGroupProposalId));\n            Assert.That(meetingGroupProposal.StatusCode, Is.EqualTo(MeetingGroupProposalStatus.ToVerify.Value));\n            Assert.That(meetingGroupProposal.Name, Is.EqualTo(MeetingGroupProposalSampleData.Name));\n            Assert.That(meetingGroupProposal.Description, Is.EqualTo(MeetingGroupProposalSampleData.Description));\n            Assert.That(meetingGroupProposal.LocationCity, Is.EqualTo(MeetingGroupProposalSampleData.LocationCity));\n            Assert.That(meetingGroupProposal.LocationCountryCode, Is.EqualTo(MeetingGroupProposalSampleData.LocationCountryCode));\n            Assert.That(meetingGroupProposal.ProposalUserId, Is.EqualTo(MeetingGroupProposalSampleData.ProposalUserId));\n            Assert.That(meetingGroupProposal.ProposalDate, Is.EqualTo(MeetingGroupProposalSampleData.ProposalDate));\n        }\n\n        [Test]\n        public async Task AcceptMeetingGroupProposal_WhenProposalIsNotAccepted_IsSuccessful()\n        {\n            var proposalId = await AdministrationModule.ExecuteCommandAsync(new RequestMeetingGroupProposalVerificationCommand(\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.Name,\n                MeetingGroupProposalSampleData.Description,\n                MeetingGroupProposalSampleData.LocationCity,\n                MeetingGroupProposalSampleData.LocationCountryCode,\n                MeetingGroupProposalSampleData.ProposalUserId,\n                MeetingGroupProposalSampleData.ProposalDate));\n\n            await AdministrationModule.ExecuteCommandAsync(\n                new AcceptMeetingGroupProposalCommand(MeetingGroupProposalSampleData.MeetingGroupProposalId));\n\n            var meetingGroupProposal = await AdministrationModule.ExecuteQueryAsync(new GetMeetingGroupProposalQuery(proposalId));\n            Assert.That(meetingGroupProposal.StatusCode, Is.EqualTo(MeetingGroupProposalStatus.Verified.Value));\n            Assert.That(meetingGroupProposal.DecisionUserId, Is.EqualTo(ExecutionContext.UserId));\n\n            var acceptedNotification = await GetLastOutboxMessage<MeetingGroupProposalAcceptedNotification>();\n\n            Assert.That(acceptedNotification.DomainEvent.MeetingGroupProposalId.Value, Is.EqualTo(proposalId));\n        }\n\n        [Test]\n        public async Task AcceptMeetingGroupProposal_WhenProposalIsAlreadyAccepted_BreaksMeetingGroupProposalCanBeVerifiedOnceRule()\n        {\n            var proposalId = await AdministrationModule.ExecuteCommandAsync(new RequestMeetingGroupProposalVerificationCommand(\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.MeetingGroupProposalId,\n                MeetingGroupProposalSampleData.Name,\n                MeetingGroupProposalSampleData.Description,\n                MeetingGroupProposalSampleData.LocationCity,\n                MeetingGroupProposalSampleData.LocationCountryCode,\n                MeetingGroupProposalSampleData.ProposalUserId,\n                MeetingGroupProposalSampleData.ProposalDate));\n\n            await AdministrationModule.ExecuteCommandAsync(\n                new AcceptMeetingGroupProposalCommand(MeetingGroupProposalSampleData.MeetingGroupProposalId));\n\n            AssertBrokenRule<MeetingGroupProposalCanBeVerifiedOnceRule>(async () =>\n                await AdministrationModule.ExecuteCommandAsync(\n                    new AcceptMeetingGroupProposalCommand(MeetingGroupProposalSampleData.MeetingGroupProposalId)));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/Members/CreateMemberTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Members.GetMember;\nusing CompanyName.MyMeetings.Modules.Administration.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.Members\n{\n    [TestFixture]\n    public class CreateMemberTests : TestBase\n    {\n        [Test]\n        public async Task CreateMember_Test()\n        {\n            var memberId = await AdministrationModule.ExecuteCommandAsync(new CreateMemberCommand(\n                Guid.NewGuid(),\n                MemberSampleData.MemberId,\n                MemberSampleData.Login,\n                MemberSampleData.Email,\n                MemberSampleData.FirstName,\n                MemberSampleData.LastName,\n                MemberSampleData.Name));\n\n            var member = await AdministrationModule.ExecuteQueryAsync(new GetMemberQuery(memberId));\n\n            Assert.That(member.Id, Is.EqualTo(MemberSampleData.MemberId));\n            Assert.That(member.LastName, Is.EqualTo(MemberSampleData.LastName));\n            Assert.That(member.Login, Is.EqualTo(MemberSampleData.Login));\n            Assert.That(member.Email, Is.EqualTo(MemberSampleData.Email));\n            Assert.That(member.FirstName, Is.EqualTo(MemberSampleData.FirstName));\n            Assert.That(member.Name, Is.EqualTo(MemberSampleData.Name));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/Members/MemberSampleData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.Members\n{\n    public struct MemberSampleData\n    {\n        public static Guid MemberId = Guid.Parse(\"60fa7e87-b0ef-484f-af7a-3ce4f35b0fa7\");\n\n        public static string Login = \"jdoe\";\n\n        public static string Email = \"jdoe@mail.com\";\n\n        public static string FirstName = \"John\";\n        public static string LastName = \"Doe\";\n        public static string Name = \"John Doe\";\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/SeedWork/OutboxMessagesHelper.cs",
    "content": "﻿using System.Data;\nusing System.Reflection;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration.Processing.Outbox;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.SeedWork\n{\n    public class OutboxMessagesHelper\n    {\n        public static async Task<List<OutboxMessageDto>> GetOutboxMessages(IDbConnection connection)\n        {\n            const string sql = \"\"\"\n                               SELECT \n                                   [OutboxMessage].[Id], \n                                   [OutboxMessage].[Type], \n                                   [OutboxMessage].[Data] \n                               FROM [administration].[OutboxMessages] AS [OutboxMessage] \n                               ORDER BY [OutboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            return messages.AsList();\n        }\n\n        public static T Deserialize<T>(OutboxMessageDto message)\n            where T : class, INotification\n        {\n            Type type = Assembly.GetAssembly(typeof(MeetingGroupProposalAcceptedNotification)).GetType(typeof(T).FullName);\n            return JsonConvert.DeserializeObject(message.Data, type) as T;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration;\nusing Dapper;\nusing MediatR;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IAdministrationModule AdministrationModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        protected ExecutionContextMock ExecutionContext { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = new LoggerConfiguration()\n                .Enrich.FromLogContext()\n                .WriteTo.Console(\n                    outputTemplate:\n                    \"[{Timestamp:HH:mm:ss} {Level:u3}] [{Module}] [{Context}] {Message:lj}{NewLine}{Exception}\")\n                .CreateLogger();\n\n            EmailSender = Substitute.For<IEmailSender>();\n            ExecutionContext = new ExecutionContextMock(Guid.NewGuid());\n\n            AdministrationStartup.Initialize(\n                ConnectionString,\n                ExecutionContext,\n                Logger,\n                null);\n\n            AdministrationModule = new AdministrationModule();\n        }\n\n        protected async Task<T> GetLastOutboxMessage<T>()\n            where T : class, INotification\n        {\n            using (var connection = new SqlConnection(ConnectionString))\n            {\n                var messages = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n                return OutboxMessagesHelper.Deserialize<T>(messages.Last());\n            }\n        }\n\n        protected static void AssertBrokenRule<TRule>(AsyncTestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.CatchAsync<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [administration].[InboxMessages] \" +\n                               \"DELETE FROM [administration].[InternalCommands] \" +\n                               \"DELETE FROM [administration].[OutboxMessages] \" +\n                               \"DELETE FROM [administration].[MeetingGroupProposals] \" +\n                               \"DELETE FROM [administration].[Members] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/UnitTests/CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Administration/Tests/UnitTests/MeetingGroupProposals/MeetingGroupProposalTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Events;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals.Rules;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.SeedWork;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Users;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.MeetingGroupProposals\n{\n    [TestFixture]\n    public class MeetingGroupProposalTests : TestBase\n    {\n        [Test]\n        public void CreateProposalToVerify_IsSuccessful()\n        {\n            var meetingGroupProposalId = Guid.NewGuid();\n            var location = MeetingGroupLocation.Create(\"Warsaw\", \"Poland\");\n            var proposalUserId = new UserId(Guid.NewGuid());\n            var proposalDate = DateTime.Now;\n\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                meetingGroupProposalId,\n                \"meetingName\",\n                \"meetingDescription\",\n                location,\n                proposalUserId,\n                proposalDate);\n\n            var meetingGroupProposalVerificationRequested = AssertPublishedDomainEvent<MeetingGroupProposalVerificationRequestedDomainEvent>(meetingGroupProposal);\n            Assert.That(meetingGroupProposalVerificationRequested.MeetingGroupProposalId, Is.EqualTo(new MeetingGroupProposalId(meetingGroupProposalId)));\n        }\n\n        [Test]\n        public void AcceptProposal_WhenDecisionIsNotMade_IsSuccessful()\n        {\n            var meetingGroupProposalId = Guid.NewGuid();\n            var location = MeetingGroupLocation.Create(\"Warsaw\", \"Poland\");\n            var proposalUserId = new UserId(Guid.NewGuid());\n            var proposalDate = DateTime.Now;\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                meetingGroupProposalId,\n                \"meetingName\",\n                \"meetingDescription\",\n                location,\n                proposalUserId,\n                proposalDate);\n\n            meetingGroupProposal.Accept(new UserId(Guid.NewGuid()));\n\n            var meetingGroupProposalAccepted = AssertPublishedDomainEvent<MeetingGroupProposalAcceptedDomainEvent>(meetingGroupProposal);\n\n            Assert.That(meetingGroupProposalAccepted.MeetingGroupProposalId, Is.EqualTo(new MeetingGroupProposalId(meetingGroupProposalId)));\n        }\n\n        [Test]\n        public void AcceptProposal_WhenDecisionIsMade_CanBeVerifiedOnlyOnce()\n        {\n            var meetingGroupProposalId = Guid.NewGuid();\n            var location = MeetingGroupLocation.Create(\"Warsaw\", \"Poland\");\n            var userId = new UserId(Guid.NewGuid());\n            var proposalUserId = userId;\n            var proposalDate = DateTime.Now;\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                meetingGroupProposalId,\n                \"meetingName\",\n                \"meetingDescription\",\n                location,\n                proposalUserId,\n                proposalDate);\n\n            meetingGroupProposal.Accept(userId);\n\n            AssertBrokenRule<MeetingGroupProposalCanBeVerifiedOnceRule>(() =>\n            {\n                meetingGroupProposal.Accept(userId);\n            });\n        }\n\n        [Test]\n        public void RejectProposal_WhenDecisionIsMade_CanBeVerifiedOnlyOnce()\n        {\n            var meetingGroupProposalId = Guid.NewGuid();\n            var location = MeetingGroupLocation.Create(\"Warsaw\", \"Poland\");\n            var userId = new UserId(Guid.NewGuid());\n            var proposalUserId = userId;\n            var proposalDate = DateTime.Now;\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                meetingGroupProposalId,\n                \"meetingName\",\n                \"meetingDescription\",\n                location,\n                proposalUserId,\n                proposalDate);\n\n            meetingGroupProposal.Accept(userId);\n\n            AssertBrokenRule<MeetingGroupProposalCanBeVerifiedOnceRule>(() =>\n            {\n                meetingGroupProposal.Reject(userId, \"rejectReason\");\n            });\n        }\n\n        [Test]\n        public void RejectProposal_WithoutProvidedReason_CannotBeRejected()\n        {\n            var meetingGroupProposalId = Guid.NewGuid();\n            var location = MeetingGroupLocation.Create(\"Warsaw\", \"Poland\");\n            var userId = new UserId(Guid.NewGuid());\n            var proposalUserId = userId;\n            var proposalDate = DateTime.Now;\n            var meetingGroupProposal = MeetingGroupProposal.CreateToVerify(\n                meetingGroupProposalId,\n                \"meetingName\",\n                \"meetingDescription\",\n                location,\n                proposalUserId,\n                proposalDate);\n\n            AssertBrokenRule<MeetingGroupProposalRejectionMustHaveAReasonRule>(() =>\n            {\n                meetingGroupProposal.Reject(userId, string.Empty);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/UnitTests/Members/MemberTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Administration.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.Members.Events;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.Members\n{\n    [TestFixture]\n    public class MemberTests : TestBase\n    {\n        [Test]\n        public void CreateMember_IsSuccessful()\n        {\n            MemberId memberId = new MemberId(Guid.NewGuid());\n            var member = Member.Create(\n                memberId.Value,\n                \"memberLogin\",\n                \"memberEmail@mail.com\",\n                \"John\",\n                \"Doe\",\n                \"John Doe\");\n\n            var memberCreated = AssertPublishedDomainEvent<MemberCreatedDomainEvent>(member);\n\n            Assert.That(memberCreated.MemberId, Is.EqualTo(memberId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/UnitTests/SeedWork/DomainEventsTestHelper.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.SeedWork\n{\n    public class DomainEventsTestHelper\n    {\n        public static List<IDomainEvent> GetAllDomainEvents(Entity aggregate)\n        {\n            List<IDomainEvent> domainEvents = [];\n\n            if (aggregate.DomainEvents != null)\n            {\n                domainEvents.AddRange(aggregate.DomainEvents);\n            }\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = typeof(Entity).IsAssignableFrom(field.FieldType);\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    domainEvents.AddRange(GetAllDomainEvents(entity).ToList());\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                domainEvents.AddRange(GetAllDomainEvents(entityItem));\n                            }\n                        }\n                    }\n                }\n            }\n\n            return domainEvents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Administration/Tests/UnitTests/SeedWork/TestBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Administration.Domain.UnitTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        public static T AssertPublishedDomainEvent<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static List<T> AssertPublishedDomainEvents<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvents = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().ToList();\n\n            if (!domainEvents.Any())\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvents;\n        }\n\n        public static void AssertBrokenRule<TRule>(TestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.Catch<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/CompanyName.MyMeetings.Modules.Meetings.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Administration\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\Payments\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Payments.IntegrationEvents.csproj\"/>\n    <ProjectReference Include=\"..\\..\\Registrations\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\UserAccess\\IntegrationEvents\\CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/Meetings/Application/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Configuration/Queries/IQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries\n{\n    public interface IQueryHandler<in TQuery, TResult> :\n        IRequestHandler<TQuery, TResult>\n        where TQuery : IQuery<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/CommandBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public abstract class CommandBase : ICommand\n    {\n        public Guid Id { get; }\n\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n\n    public abstract class CommandBase<TResult> : ICommand<TResult>\n    {\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/ICommand.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public interface ICommand<out TResult> : IRequest<TResult>\n    {\n        Guid Id { get; }\n    }\n\n    public interface ICommand : IRequest\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/IMeetingsModule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public interface IMeetingsModule\n    {\n        Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n        Task ExecuteCommandAsync(ICommand command);\n\n        Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/IQuery.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public interface IQuery<out TResult> : IRequest<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Contracts/QueryBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Contracts\n{\n    public abstract class QueryBase<TResult> : IQuery<TResult>\n    {\n        public Guid Id { get; }\n\n        protected QueryBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected QueryBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Countries/CountryDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Countries\n{\n    public class CountryDto\n    {\n        public string Code { get; set; }\n\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Countries/GetAllCountriesQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Countries\n{\n    public class GetAllCountriesQuery : QueryBase<List<CountryDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Countries/GetAllCountriesQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Countries\n{\n    internal class GetAllCountriesQueryHandler : IQueryHandler<GetAllCountriesQuery, List<CountryDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetAllCountriesQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<CountryDto>> Handle(GetAllCountriesQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT\n                                   [Country].[Code] AS [{nameof(CountryDto.Code)}],\n                                   [Country].[Name] AS [{nameof(CountryDto.Name)}]\n                               FROM [meetings].[v_Countries] AS [Country]\n                               \"\"\";\n\n            return (await connection.QueryAsync<CountryDto>(sql)).AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/DisableMeetingCommentingConfiguration/DisableMeetingCommentingConfigurationCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.DisableMeetingCommentingConfiguration\n{\n    public class DisableMeetingCommentingConfigurationCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public DisableMeetingCommentingConfigurationCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/DisableMeetingCommentingConfiguration/DisableMeetingCommentingConfigurationCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.DisableMeetingCommentingConfiguration\r\n{\r\n    internal class DisableMeetingCommentingConfigurationCommandHandler : ICommandHandler<DisableMeetingCommentingConfigurationCommand>\r\n    {\r\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        public DisableMeetingCommentingConfigurationCommandHandler(\r\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository,\r\n            IMeetingGroupRepository meetingGroupRepository,\r\n            IMeetingRepository meetingRepository,\r\n            IMemberContext memberContext)\r\n        {\r\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _meetingRepository = meetingRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(DisableMeetingCommentingConfigurationCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(new MeetingId(command.MeetingId));\r\n            if (meetingCommentingConfiguration == null)\r\n            {\r\n                throw new InvalidCommandException([\"Meeting commenting configuration for disabling commenting must exist.\"]);\r\n            }\r\n\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(command.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meetingCommentingConfiguration.DisableCommenting(_memberContext.MemberId, meetingGroup);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/EnableMeetingCommentingConfiguration/EnableMeetingCommentingConfigurationCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.EnableMeetingCommentingConfiguration\n{\n    public class EnableMeetingCommentingConfigurationCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public EnableMeetingCommentingConfigurationCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/EnableMeetingCommentingConfiguration/EnableMeetingCommentingConfigurationCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.EnableMeetingCommentingConfiguration\r\n{\r\n    internal class EnableMeetingCommentingConfigurationCommandHandler : ICommandHandler<EnableMeetingCommentingConfigurationCommand>\r\n    {\r\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        public EnableMeetingCommentingConfigurationCommandHandler(\r\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository,\r\n            IMeetingRepository meetingRepository,\r\n            IMeetingGroupRepository meetingGroupRepository,\r\n            IMemberContext memberContext)\r\n        {\r\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(EnableMeetingCommentingConfigurationCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(new MeetingId(command.MeetingId));\r\n            if (meetingCommentingConfiguration == null)\r\n            {\r\n                throw new InvalidCommandException([\"Meeting commenting configuration for enabling commenting must exist.\"]);\r\n            }\r\n\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(command.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meetingCommentingConfiguration.EnableCommenting(_memberContext.MemberId, meetingGroup);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/GetMeetingCommentingConfiguration/GetMeetingCommentingConfigurationQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration\n{\n    public class GetMeetingCommentingConfigurationQuery : QueryBase<MeetingCommentingConfigurationDto>\n    {\n        public Guid MeetingId { get; }\n\n        public GetMeetingCommentingConfigurationQuery(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/GetMeetingCommentingConfiguration/GetMeetingCommentingConfigurationQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration\n{\n    internal class GetMeetingCommentingConfigurationQueryHandler : IQueryHandler<GetMeetingCommentingConfigurationQuery, MeetingCommentingConfigurationDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingCommentingConfigurationQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MeetingCommentingConfigurationDto> Handle(GetMeetingCommentingConfigurationQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT\n                                    [MeetingCommentingConfiguration].[MeetingId] AS [{nameof(MeetingCommentingConfigurationDto.MeetingId)}],\n                                    [MeetingCommentingConfiguration].[IsCommentingEnabled] AS [{nameof(MeetingCommentingConfigurationDto.IsCommentingEnabled)}]\n                                FROM [meetings].[MeetingCommentingConfigurations] AS [MeetingCommentingConfiguration]\n                                WHERE [MeetingCommentingConfiguration].[MeetingId] = @MeetingId\n                                \"\"\";\n\n            return await connection.QuerySingleOrDefaultAsync<MeetingCommentingConfigurationDto>(sql, new { query.MeetingId });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/GetMeetingCommentingConfiguration/MeetingCommentingConfigurationDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration\n{\n    public class MeetingCommentingConfigurationDto\n    {\n        public Guid MeetingId { get; }\n\n        public bool IsCommentingEnabled { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingCommentingConfigurations/MeetingCreatedEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations\n{\n    internal class MeetingCreatedEventHandler : INotificationHandler<MeetingCreatedDomainEvent>\n    {\n        private readonly IMeetingRepository _meetingRepository;\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\n\n        public MeetingCreatedEventHandler(\n            IMeetingRepository meetingRepository,\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository)\n        {\n            _meetingRepository = meetingRepository;\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\n        }\n\n        public async Task Handle(MeetingCreatedDomainEvent @event, CancellationToken cancellationToken)\n        {\n            var meeting = await _meetingRepository.GetByIdAsync(@event.MeetingId);\n\n            var meetingCommentingConfiguration = meeting.CreateCommentingConfiguration();\n\n            await _meetingCommentingConfigurationRepository.AddAsync(meetingCommentingConfiguration);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingComment/AddMeetingCommentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment\n{\n    public class AddMeetingCommentCommand : CommandBase<Guid>\n    {\n        public Guid MeetingId { get; }\n\n        public string Comment { get; }\n\n        public AddMeetingCommentCommand(Guid meetingId, string comment)\n        {\n            MeetingId = meetingId;\n            Comment = comment;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingComment/AddMeetingCommentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment\n{\n    internal class AddMeetingCommentCommandHandler : ICommandHandler<AddMeetingCommentCommand, Guid>\n    {\n        private readonly IMeetingRepository _meetingRepository;\n        private readonly IMeetingCommentRepository _meetingCommentRepository;\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\n        private readonly IMemberContext _memberContext;\n\n        public AddMeetingCommentCommandHandler(\n            IMeetingRepository meetingRepository,\n            IMeetingCommentRepository meetingCommentRepository,\n            IMeetingGroupRepository meetingGroupRepository,\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository,\n            IMemberContext memberContext)\n        {\n            _meetingGroupRepository = meetingGroupRepository;\n            _meetingRepository = meetingRepository;\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\n            _meetingCommentRepository = meetingCommentRepository;\n            _memberContext = memberContext;\n        }\n\n        public async Task<Guid> Handle(AddMeetingCommentCommand command, CancellationToken cancellationToken)\n        {\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(command.MeetingId));\n            if (meeting == null)\n            {\n                throw new InvalidCommandException([\"Meeting for adding comment must exist.\"]);\n            }\n\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\n\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(new MeetingId(command.MeetingId));\n\n            var meetingComment = meeting.AddComment(_memberContext.MemberId, command.Comment, meetingGroup, meetingCommentingConfiguration);\n\n            await _meetingCommentRepository.AddAsync(meetingComment);\n\n            return meetingComment.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingComment/AddMeetingCommentCommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment\n{\n    internal class AddMeetingCommentCommandValidator : AbstractValidator<AddMeetingCommentCommand>\n    {\n        public AddMeetingCommentCommandValidator()\n        {\n            this.RuleFor(c => c.MeetingId).NotEmpty()\n                .WithMessage(\"Id of meeting member cannot be empty.\");\n\n            this.RuleFor(c => c.Comment).NotNull().NotEmpty()\n                .WithMessage(\"Comment cannot be null or empty.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentLike/AddMeetingCommentLikeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentLike\n{\n    public class AddMeetingCommentLikeCommand : CommandBase\n    {\n        public Guid MeetingCommentId { get; }\n\n        public AddMeetingCommentLikeCommand(Guid meetingCommentId)\n        {\n            MeetingCommentId = meetingCommentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentLike/AddMeetingCommentLikeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentLike\r\n{\r\n    internal class AddMeetingCommentLikeCommandHandler : ICommandHandler<AddMeetingCommentLikeCommand>\r\n    {\r\n        private readonly IMeetingCommentRepository _meetingCommentRepository;\r\n        private readonly IMeetingMemberCommentLikesRepository _meetingMemberCommentLikesRepository;\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public AddMeetingCommentLikeCommandHandler(\r\n            IMeetingCommentRepository meetingCommentRepository,\r\n            IMeetingMemberCommentLikesRepository meetingMemberCommentLikesRepository,\r\n            IMemberContext memberContext,\r\n            ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _meetingCommentRepository = meetingCommentRepository;\r\n            _memberContext = memberContext;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _meetingMemberCommentLikesRepository = meetingMemberCommentLikesRepository;\r\n        }\r\n\r\n        public async Task Handle(AddMeetingCommentLikeCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(request.MeetingCommentId));\r\n            if (meetingComment == null)\r\n            {\r\n                throw new InvalidCommandException([\"To add like the comment must exist.\"]);\r\n            }\r\n\r\n            var connection = _sqlConnectionFactory.GetOpenConnection();\r\n            var likerMeetingGroupMemberData = await MembersQueryHelper.GetMeetingGroupMember(_memberContext.MemberId, meetingComment.GetMeetingId(), connection);\r\n\r\n            var meetingMemeberCommentLikesCount = await _meetingMemberCommentLikesRepository.CountMemberCommentLikesAsync(\r\n                    _memberContext.MemberId,\r\n                    new MeetingCommentId(request.MeetingCommentId));\r\n\r\n            var like = meetingComment.Like(_memberContext.MemberId, likerMeetingGroupMemberData, meetingMemeberCommentLikesCount);\r\n\r\n            await _meetingMemberCommentLikesRepository.AddAsync(like);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentReply/AddReplyToMeetingCommentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentReply\n{\n    public class AddReplyToMeetingCommentCommand : CommandBase<Guid>\n    {\n        public Guid InReplyToCommentId { get; }\n\n        public string Reply { get; }\n\n        public AddReplyToMeetingCommentCommand(Guid inReplyToCommentId, string reply)\n        {\n            InReplyToCommentId = inReplyToCommentId;\n            Reply = reply;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/AddMeetingCommentReply/AddReplyToMeetingCommentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentReply\n{\n    internal class AddReplyToMeetingCommentCommandHandler : ICommandHandler<AddReplyToMeetingCommentCommand, Guid>\n    {\n        private readonly IMeetingCommentRepository _meetingCommentRepository;\n        private readonly IMeetingRepository _meetingRepository;\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\n        private readonly IMemberContext _memberContext;\n\n        internal AddReplyToMeetingCommentCommandHandler(IMeetingCommentRepository meetingCommentRepository, IMeetingRepository meetingRepository, IMeetingGroupRepository meetingGroupRepository, IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository, IMemberContext memberContext)\n        {\n            _meetingCommentRepository = meetingCommentRepository;\n            _meetingRepository = meetingRepository;\n            _meetingGroupRepository = meetingGroupRepository;\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\n            _memberContext = memberContext;\n        }\n\n        public async Task<Guid> Handle(AddReplyToMeetingCommentCommand command, CancellationToken cancellationToken)\n        {\n            var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(command.InReplyToCommentId));\n            if (meetingComment == null)\n            {\n                throw new InvalidCommandException([\"To create reply the comment must exist.\"]);\n            }\n\n            var meeting = await _meetingRepository.GetByIdAsync(meetingComment.GetMeetingId());\n\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\n\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(meetingComment.GetMeetingId());\n\n            var replyToComment = meetingComment.Reply(_memberContext.MemberId, command.Reply, meetingGroup, meetingCommentingConfiguration);\n            await _meetingCommentRepository.AddAsync(replyToComment);\n\n            return replyToComment.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/EditMeetingComment/EditMeetingCommentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.EditMeetingComment\n{\n    public class EditMeetingCommentCommand : CommandBase\n    {\n        public Guid MeetingCommentId { get; }\n\n        public string EditedComment { get; }\n\n        public EditMeetingCommentCommand(Guid meetingCommentId, string editedComment)\n        {\n            EditedComment = editedComment;\n            MeetingCommentId = meetingCommentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/EditMeetingComment/EditMeetingCommentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.EditMeetingComment\r\n{\r\n    internal class EditMeetingCommentCommandHandler : ICommandHandler<EditMeetingCommentCommand>\r\n    {\r\n        private readonly IMeetingCommentRepository _meetingCommentRepository;\r\n        private readonly IMeetingCommentingConfigurationRepository _meetingCommentingConfigurationRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal EditMeetingCommentCommandHandler(\r\n            IMeetingCommentRepository meetingCommentRepository,\r\n            IMeetingCommentingConfigurationRepository meetingCommentingConfigurationRepository,\r\n            IMemberContext memberContext)\r\n        {\r\n            _meetingCommentRepository = meetingCommentRepository;\r\n            _meetingCommentingConfigurationRepository = meetingCommentingConfigurationRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(EditMeetingCommentCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(command.MeetingCommentId));\r\n            if (meetingComment == null)\r\n            {\r\n                throw new InvalidCommandException([\"Meeting comment for editing must exist.\"]);\r\n            }\r\n\r\n            var meetingCommentingConfiguration = await _meetingCommentingConfigurationRepository.GetByMeetingIdAsync(meetingComment.GetMeetingId());\r\n\r\n            meetingComment.Edit(_memberContext.MemberId, command.EditedComment, meetingCommentingConfiguration);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/EditMeetingComment/EditMeetingCommentCommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.EditMeetingComment\n{\n    internal class EditMeetingCommentCommandValidator : AbstractValidator<EditMeetingCommentCommand>\n    {\n        public EditMeetingCommentCommandValidator()\n        {\n            RuleFor(c => c.EditedComment).NotNull().NotEmpty()\n                .WithMessage(\"Comment cannot be null or empty.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingCommentLikers/GetMeetingCommentLikersQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingCommentLikers\n{\n    public class GetMeetingCommentLikersQuery : IQuery<List<MeetingCommentLikerDto>>\n    {\n        public Guid MeetingCommentId { get; }\n\n        public GetMeetingCommentLikersQuery(Guid meetingCommentId)\n        {\n            MeetingCommentId = meetingCommentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingCommentLikers/GetMeetingCommentLikersQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingCommentLikers\n{\n    internal class GetMeetingCommentLikersQueryHandler : IQueryHandler<GetMeetingCommentLikersQuery, List<MeetingCommentLikerDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingCommentLikersQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingCommentLikerDto>> Handle(GetMeetingCommentLikersQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT\n                                  [Liker].[Id] as [{nameof(MeetingCommentLikerDto.Id)}],\n                                  [Liker].[Name] as [{nameof(MeetingCommentLikerDto.Name)}]\n                               FROM [meetings].[Members] AS [Liker]\n                                   INNER JOIN [meetings].[MeetingMemberCommentLikes] AS [Like]\n                                         ON [Liker].[Id] = [Like].[MemberId]\n                               WHERE [Like].[MeetingCommentId] = @MeetingCommentId\n                               \"\"\";\n\n            var meetingCommentLikers = await connection.QueryAsync<MeetingCommentLikerDto>(sql, new { query.MeetingCommentId });\n\n            return meetingCommentLikers.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingCommentLikers/MeetingCommentLikerDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingCommentLikers\n{\n    public class MeetingCommentLikerDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingComments/GetMeetingCommentsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments\n{\n    public class GetMeetingCommentsQuery : QueryBase<List<MeetingCommentDto>>\n    {\n        public Guid MeetingId { get; }\n\n        public GetMeetingCommentsQuery(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingComments/GetMeetingCommentsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments\n{\n    internal class GetMeetingCommentsQueryHandler : IQueryHandler<GetMeetingCommentsQuery, List<MeetingCommentDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingCommentsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingCommentDto>> Handle(GetMeetingCommentsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT\n                                    [MeetingComment].[Id] AS [{nameof(MeetingCommentDto.Id)}],\n                                    [MeetingComment].[InReplyToCommentId] AS [{nameof(MeetingCommentDto.InReplyToCommentId)}],\n                                    [MeetingComment].[AuthorId] AS [{nameof(MeetingCommentDto.AuthorId)}],\n                                    [MeetingComment].[Comment] AS [{nameof(MeetingCommentDto.Comment)}],\n                                    [MeetingComment].[CreateDate] AS [{nameof(MeetingCommentDto.CreateDate)}],\n                                    [MeetingComment].[EditDate] AS [{nameof(MeetingCommentDto.EditDate)}],\n                                    [MeetingComment].[LikesCount] AS [{nameof(MeetingCommentDto.LikesCount)}]\n                                FROM [meetings].[v_MeetingComments] AS [MeetingComment]\n                                WHERE [MeetingComment].[MeetingId] = @MeetingId\n                                \"\"\";\n            var meetingComments = await connection.QueryAsync<MeetingCommentDto>(sql, new { query.MeetingId });\n\n            return meetingComments.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/GetMeetingComments/MeetingCommentDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments\n{\n    public class MeetingCommentDto\n    {\n        public Guid Id { get; }\n\n        public Guid? InReplyToCommentId { get; }\n\n        public Guid AuthorId { get; }\n\n        public string Comment { get; }\n\n        public DateTime CreateDate { get; }\n\n        public DateTime? EditDate { get; }\n\n        public int LikesCount { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/MeetingCommentLikedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments\n{\n    public class MeetingCommentLikedNotification : DomainNotificationBase<MeetingCommentLikedDomainEvent>\n    {\n        public MeetingCommentLikedNotification(MeetingCommentLikedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/MeetingCommentLikedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing Dapper;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments\n{\n    internal class MeetingCommentLikedNotificationHandler : INotificationHandler<MeetingCommentLikedNotification>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public MeetingCommentLikedNotificationHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(MeetingCommentLikedNotification notification, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = \"\"\"\n                               UPDATE [meetings].[MeetingComments] \n                               SET [LikesCount] = (SELECT count(*) FROM [meetings].[MeetingMemberCommentLikes] WHERE [MeetingCommentId] = @MeetingCommentId) \n                               WHERE [Id] = @MeetingCommentId;\n                               \"\"\";\n\n            await connection.ExecuteAsync(\n                sql,\n                new\n                {\n                    MeetingCommentId = notification.DomainEvent.MeetingCommentId.Value\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/MeetingCommentUnlikeNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing Dapper;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments\n{\n    public class MeetingCommentUnlikeNotificationHandler : INotificationHandler<MeetingCommentUnlikedNotification>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public MeetingCommentUnlikeNotificationHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(MeetingCommentUnlikedNotification notification, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = \"UPDATE [meetings].[MeetingComments] \" +\n                               \"SET [LikesCount] = \" +\n                               \"(SELECT count(*) FROM [meetings].[MeetingMemberCommentLikes] WHERE [MeetingCommentId] = @MeetingCommentId) \" +\n                               \"WHERE [Id] = @MeetingCommentId;\";\n\n            await connection.ExecuteAsync(\n                sql,\n                new\n                {\n                    MeetingCommentId = notification.DomainEvent.MeetingCommentId.Value\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/MeetingCommentUnlikedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments\n{\n    public class MeetingCommentUnlikedNotification : DomainNotificationBase<MeetingCommentUnlikedDomainEvent>\n    {\n        public MeetingCommentUnlikedNotification(MeetingCommentUnlikedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/RemoveMeetingComment/RemoveMeetingCommentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingComment\n{\n    public class RemoveMeetingCommentCommand : CommandBase\n    {\n        public Guid MeetingCommentId { get; }\n\n        public string Reason { get; }\n\n        public RemoveMeetingCommentCommand(Guid meetingCommentId, string reason)\n        {\n            MeetingCommentId = meetingCommentId;\n            Reason = reason;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/RemoveMeetingComment/RemoveMeetingCommentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingComment\r\n{\r\n    internal class RemoveMeetingCommentCommandHandler : ICommandHandler<RemoveMeetingCommentCommand>\r\n    {\r\n        private readonly IMeetingCommentRepository _meetingCommentRepository;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal RemoveMeetingCommentCommandHandler(IMeetingCommentRepository meetingCommentRepository, IMeetingRepository meetingRepository, IMeetingGroupRepository meetingGroupRepository, IMemberContext memberContext)\r\n        {\r\n            _meetingCommentRepository = meetingCommentRepository;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(RemoveMeetingCommentCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingComment = await _meetingCommentRepository.GetByIdAsync(new MeetingCommentId(command.MeetingCommentId));\r\n            if (meetingComment == null)\r\n            {\r\n                throw new InvalidCommandException([\"Meeting comment for removing must exist.\"]);\r\n            }\r\n\r\n            var meeting = await _meetingRepository.GetByIdAsync(meetingComment.GetMeetingId());\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meetingComment.Remove(_memberContext.MemberId, meetingGroup, command.Reason);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/RemoveMeetingCommentLike/RemoveMeetingCommentLikeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingCommentLike\n{\n    public class RemoveMeetingCommentLikeCommand : CommandBase\n    {\n        public Guid MeetingCommentId { get; }\n\n        public RemoveMeetingCommentLikeCommand(Guid meetingCommentId)\n        {\n            MeetingCommentId = meetingCommentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingComments/RemoveMeetingCommentLike/RemoveMeetingCommentLikeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingCommentLike\r\n{\r\n    internal class RemoveMeetingCommentLikeCommandHandler : ICommandHandler<RemoveMeetingCommentLikeCommand>\r\n    {\r\n        private readonly IMeetingMemberCommentLikesRepository _meetingMemberCommentLikesRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal RemoveMeetingCommentLikeCommandHandler(IMeetingMemberCommentLikesRepository meetingMemberCommentLikesRepository, IMemberContext memberContext)\r\n        {\r\n            _meetingMemberCommentLikesRepository = meetingMemberCommentLikesRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(RemoveMeetingCommentLikeCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var commentLike = await _meetingMemberCommentLikesRepository.GetAsync(_memberContext.MemberId, new MeetingCommentId(command.MeetingCommentId));\r\n            if (commentLike == null)\r\n            {\r\n                throw new InvalidCommandException([\"Meeting comment like for removing must exist.\"]);\r\n            }\r\n\r\n            commentLike.Remove();\r\n\r\n            _meetingMemberCommentLikesRepository.Remove(commentLike);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/AcceptMeetingGroupProposalCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    public class AcceptMeetingGroupProposalCommand : InternalCommandBase\n    {\n        public Guid MeetingGroupProposalId { get; }\n\n        [JsonConstructor]\n        public AcceptMeetingGroupProposalCommand(Guid id, Guid meetingGroupProposalId)\n            : base(id)\n        {\n            this.MeetingGroupProposalId = meetingGroupProposalId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/AcceptMeetingGroupProposalCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\r\n{\r\n    internal class AcceptMeetingGroupProposalCommandHandler : ICommandHandler<AcceptMeetingGroupProposalCommand>\r\n    {\r\n        private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\r\n\r\n        public AcceptMeetingGroupProposalCommandHandler(IMeetingGroupProposalRepository meetingGroupProposalRepository)\r\n        {\r\n            _meetingGroupProposalRepository = meetingGroupProposalRepository;\r\n        }\r\n\r\n        public async Task Handle(AcceptMeetingGroupProposalCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroupProposal = await _meetingGroupProposalRepository.GetByIdAsync(new MeetingGroupProposalId(request.MeetingGroupProposalId));\r\n\r\n            meetingGroupProposal.Accept();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/AcceptMeetingGroupProposalCommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    internal class AcceptMeetingGroupProposalCommandValidator : AbstractValidator<AcceptMeetingGroupProposalCommand>\n    {\n        public AcceptMeetingGroupProposalCommandValidator()\n        {\n            this.RuleFor(x => x.MeetingGroupProposalId).NotEmpty()\n                .WithMessage(\"Id of meeting group proposal cannot be empty\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/MeetingGroupProposalAcceptedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    public class MeetingGroupProposalAcceptedNotification : DomainNotificationBase<MeetingGroupProposalAcceptedDomainEvent>\n    {\n        public MeetingGroupProposalAcceptedNotification(MeetingGroupProposalAcceptedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/AcceptMeetingGroupProposal/MeetingGroupProposalAcceptedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.CreateNewMeetingGroup;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal\n{\n    internal class MeetingGroupProposalAcceptedNotificationHandler : INotificationHandler<MeetingGroupProposalAcceptedNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal MeetingGroupProposalAcceptedNotificationHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingGroupProposalAcceptedNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new CreateNewMeetingGroupCommand(\n                    Guid.NewGuid(),\n                    notification.DomainEvent.MeetingGroupProposalId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetAllMeetingGroupProposals/GetAllMeetingGroupProposalsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Queries;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetAllMeetingGroupProposals\n{\n    public class GetAllMeetingGroupProposalsQuery : QueryBase<List<MeetingGroupProposalDto>>, IPagedQuery\n    {\n        public GetAllMeetingGroupProposalsQuery(int? page, int? perPage)\n        {\n            Page = page;\n            PerPage = perPage;\n        }\n\n        public int? Page { get; }\n\n        public int? PerPage { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetAllMeetingGroupProposals/GetAllMeetingGroupProposalsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Queries;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetAllMeetingGroupProposals\n{\n    internal class GetAllMeetingGroupProposalsQueryHandler : IQueryHandler<GetAllMeetingGroupProposalsQuery, List<MeetingGroupProposalDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetAllMeetingGroupProposalsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingGroupProposalDto>> Handle(GetAllMeetingGroupProposalsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            var parameters = new DynamicParameters();\n            var pageData = PagedQueryHelper.GetPageData(query);\n            parameters.Add(nameof(PagedQueryHelper.Offset), pageData.Offset);\n            parameters.Add(nameof(PagedQueryHelper.Next), pageData.Next);\n\n            var sql = $\"\"\"\n                       SELECT\n                           [MeetingGroupProposal].[Id] AS [{nameof(MeetingGroupProposalDto.Id)}],\n                           [MeetingGroupProposal].[Name] AS [{nameof(MeetingGroupProposalDto.Name)}],\n                           [MeetingGroupProposal].[ProposalUserId] AS [{nameof(MeetingGroupProposalDto.ProposalUserId)}],\n                           [MeetingGroupProposal].[LocationCity] AS [{nameof(MeetingGroupProposalDto.LocationCity)}],\n                           [MeetingGroupProposal].[LocationCountryCode] AS [{nameof(MeetingGroupProposalDto.LocationCountryCode)}],\n                           [MeetingGroupProposal].[Description] AS [{nameof(MeetingGroupProposalDto.Description)}],\n                           [MeetingGroupProposal].[ProposalDate] AS [{nameof(MeetingGroupProposalDto.ProposalDate)}],\n                           [MeetingGroupProposal].[StatusCode] AS [{nameof(MeetingGroupProposalDto.StatusCode)}]\n                       FROM [meetings].[v_MeetingGroupProposals] AS [MeetingGroupProposal]\n                       ORDER BY [MeetingGroupProposal].[Name]\n                       \"\"\";\n\n            sql = PagedQueryHelper.AppendPageStatement(sql);\n\n            var meetingGroupProposals = await connection.QueryAsync<MeetingGroupProposalDto>(sql, parameters);\n\n            return meetingGroupProposals.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetMeetingGroupProposal/GetMeetingGroupProposalQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    public class GetMeetingGroupProposalQuery : QueryBase<MeetingGroupProposalDto>\n    {\n        public GetMeetingGroupProposalQuery(Guid meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        public Guid MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetMeetingGroupProposal/GetMeetingGroupProposalQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    internal class GetMeetingGroupProposalQueryHandler : IQueryHandler<GetMeetingGroupProposalQuery, MeetingGroupProposalDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingGroupProposalQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MeetingGroupProposalDto> Handle(GetMeetingGroupProposalQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT [MeetingGroupProposal].[Id] AS [{nameof(MeetingGroupProposalDto.Id)}],\n                                       [MeetingGroupProposal].[Name] AS [{nameof(MeetingGroupProposalDto.Name)}],\n                                       [MeetingGroupProposal].[ProposalUserId] AS [{nameof(MeetingGroupProposalDto.ProposalUserId)}],\n                                       [MeetingGroupProposal].[LocationCity] AS [{nameof(MeetingGroupProposalDto.LocationCity)}],\n                                       [MeetingGroupProposal].[LocationCountryCode] AS [{nameof(MeetingGroupProposalDto.LocationCountryCode)}],\n                                       [MeetingGroupProposal].[Description] AS [{nameof(MeetingGroupProposalDto.Description)}],\n                                       [MeetingGroupProposal].[ProposalDate] AS [{nameof(MeetingGroupProposalDto.ProposalDate)}],\n                                       [MeetingGroupProposal].[StatusCode] AS [{nameof(MeetingGroupProposalDto.StatusCode)}]\n                                FROM [meetings].[v_MeetingGroupProposals] AS [MeetingGroupProposal]\n                                WHERE [MeetingGroupProposal].[Id] = @MeetingGroupProposalId\n                                \"\"\";\n\n            return await connection.QuerySingleAsync<MeetingGroupProposalDto>(sql, new { query.MeetingGroupProposalId });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetMeetingGroupProposal/MeetingGroupProposalDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal\n{\n    public class MeetingGroupProposalDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationCountryCode { get; set; }\n\n        public Guid ProposalUserId { get; set; }\n\n        public DateTime ProposalDate { get; set; }\n\n        public string StatusCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetMemberMeetingGroupProposals/GetMemberMeetingGroupProposalsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMemberMeetingGroupProposals\n{\n    public class GetMemberMeetingGroupProposalsQuery : QueryBase<List<MeetingGroupProposalDto>>\n    {\n        public GetMemberMeetingGroupProposalsQuery()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/GetMemberMeetingGroupProposals/GetMemberMeetingGroupProposalsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMemberMeetingGroupProposals\n{\n    internal class GetMemberMeetingGroupProposalsQueryHandler : IQueryHandler<GetMemberMeetingGroupProposalsQuery, List<MeetingGroupProposalDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IMemberContext _memberContext;\n\n        public GetMemberMeetingGroupProposalsQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IMemberContext memberContext)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _memberContext = memberContext;\n        }\n\n        public async Task<List<MeetingGroupProposalDto>> Handle(GetMemberMeetingGroupProposalsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT \n                                   [MeetingGroupProposal].[Id] AS [{nameof(MeetingGroupProposalDto.Id)}],\n                                   [MeetingGroupProposal].[Name] AS [{nameof(MeetingGroupProposalDto.Name)}], \n                                   [MeetingGroupProposal].[ProposalUserId] AS [{nameof(MeetingGroupProposalDto.ProposalUserId)}],\n                                   [MeetingGroupProposal].[LocationCity] AS [{nameof(MeetingGroupProposalDto.LocationCity)}],\n                                   [MeetingGroupProposal].[LocationCountryCode] AS [{nameof(MeetingGroupProposalDto.LocationCountryCode)}],\n                                   [MeetingGroupProposal].[Description] AS [{nameof(MeetingGroupProposalDto.Description)}],\n                                   [MeetingGroupProposal].[ProposalDate] AS [{nameof(MeetingGroupProposalDto.ProposalDate)}], \n                                   [MeetingGroupProposal].[StatusCode] AS [{nameof(MeetingGroupProposalDto.StatusCode)}] \n                               FROM [meetings].[v_MeetingGroupProposals] AS [MeetingGroupProposal] \n                               WHERE [MeetingGroupProposal].ProposalUserId = @MemberId \n                               ORDER BY [MeetingGroupProposal].[Name]\n                               \"\"\";\n\n            var meetingGroupProposals = await connection.QueryAsync<MeetingGroupProposalDto>(\n                sql,\n                new\n                {\n                    MemberId = _memberContext.MemberId.Value\n                });\n\n            return meetingGroupProposals.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/MeetingGroupProposalAcceptedIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals\n{\n    public class MeetingGroupProposalAcceptedIntegrationEventHandler :\n        INotificationHandler<MeetingGroupProposalAcceptedIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public MeetingGroupProposalAcceptedIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingGroupProposalAcceptedIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new AcceptMeetingGroupProposalCommand(\n                Guid.NewGuid(),\n                notification.MeetingGroupProposalId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/MeetingGroupProposedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals\n{\n    public class MeetingGroupProposedNotification : DomainNotificationBase<MeetingGroupProposedDomainEvent>\n    {\n        [JsonConstructor]\n        public MeetingGroupProposedNotification(MeetingGroupProposedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/MeetingGroupProposedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals\n{\n    public class MeetingGroupProposedNotificationHandler : INotificationHandler<MeetingGroupProposedNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public MeetingGroupProposedNotificationHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(MeetingGroupProposedNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new MeetingGroupProposedIntegrationEvent(\n                notification.Id,\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.MeetingGroupProposalId.Value,\n                notification.DomainEvent.Name,\n                notification.DomainEvent.Description,\n                notification.DomainEvent.LocationCity,\n                notification.DomainEvent.LocationCountryCode,\n                notification.DomainEvent.ProposalUserId.Value,\n                notification.DomainEvent.ProposalDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/ProposeMeetingGroup/ProposeMeetingGroupCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup\n{\n    public class ProposeMeetingGroupCommand : CommandBase<Guid>\n    {\n        public ProposeMeetingGroupCommand(string name, string description, string locationCity, string locationCountryCode)\n        {\n            Name = name;\n            Description = description;\n            LocationCity = locationCity;\n            LocationCountryCode = locationCountryCode;\n        }\n\n        public string Name { get; }\n\n        public string Description { get; }\n\n        public string LocationCity { get; }\n\n        public string LocationCountryCode { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/ProposeMeetingGroup/ProposeMeetingGroupCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup\n{\n    internal class ProposeMeetingGroupCommandHandler : ICommandHandler<ProposeMeetingGroupCommand, Guid>\n    {\n        private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\n        private readonly IMemberContext _memberContext;\n\n        internal ProposeMeetingGroupCommandHandler(\n            IMeetingGroupProposalRepository meetingGroupProposalRepository,\n            IMemberContext memberContext)\n        {\n            _meetingGroupProposalRepository = meetingGroupProposalRepository;\n            _memberContext = memberContext;\n        }\n\n        public async Task<Guid> Handle(ProposeMeetingGroupCommand request, CancellationToken cancellationToken)\n        {\n            var meetingGroupProposal = MeetingGroupProposal.ProposeNew(\n                request.Name,\n                request.Description,\n                MeetingGroupLocation.CreateNew(request.LocationCity, request.LocationCountryCode),\n                _memberContext.MemberId);\n\n            await _meetingGroupProposalRepository.AddAsync(meetingGroupProposal);\n\n            return meetingGroupProposal.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroupProposals/ProposeMeetingGroup/ProposeMeetingGroupCommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup\n{\n    internal class ProposeMeetingGroupCommandValidator : AbstractValidator<ProposeMeetingGroupCommand>\n    {\n        public ProposeMeetingGroupCommandValidator()\n        {\n            this.RuleFor(x => x.Name).NotEmpty().WithMessage(\"Meeting group name cannot be empty\");\n            this.RuleFor(x => x.LocationCity).NotEmpty().WithMessage(\"Meeting group city cannot be empty\");\n            this.RuleFor(x => x.LocationCountryCode).NotEmpty().WithMessage(\"Meeting country code cannot be empty\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/CreateNewMeetingGroup/CreateNewMeetingGroupCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.CreateNewMeetingGroup\n{\n    public class CreateNewMeetingGroupCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public CreateNewMeetingGroupCommand(Guid id, MeetingGroupProposalId meetingGroupProposalId)\n            : base(id)\n        {\n            this.MeetingGroupProposalId = meetingGroupProposalId;\n        }\n\n        internal MeetingGroupProposalId MeetingGroupProposalId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/CreateNewMeetingGroup/CreateNewMeetingGroupCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.CreateNewMeetingGroup\r\n{\r\n    internal class CreateNewMeetingGroupCommandHandler : ICommandHandler<CreateNewMeetingGroupCommand>\r\n    {\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMeetingGroupProposalRepository _meetingGroupProposalRepository;\r\n\r\n        internal CreateNewMeetingGroupCommandHandler(\r\n            IMeetingGroupRepository meetingGroupRepository,\r\n            IMeetingGroupProposalRepository meetingGroupProposalRepository)\r\n        {\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _meetingGroupProposalRepository = meetingGroupProposalRepository;\r\n        }\r\n\r\n        public async Task Handle(CreateNewMeetingGroupCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroupProposal = await _meetingGroupProposalRepository.GetByIdAsync(request.MeetingGroupProposalId);\r\n\r\n            var meetingGroup = meetingGroupProposal.CreateMeetingGroup();\r\n\r\n            await _meetingGroupRepository.AddAsync(meetingGroup);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/EditMeetingGroupGeneralAttributes/EditMeetingGroupGeneralAttributesCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.EditMeetingGroupGeneralAttributes\n{\n    public class EditMeetingGroupGeneralAttributesCommand : CommandBase\n    {\n        public EditMeetingGroupGeneralAttributesCommand(Guid meetingGroupId, string name, string description, string locationCity, string locationCountry)\n        {\n            MeetingGroupId = meetingGroupId;\n            Name = name;\n            Description = description;\n            LocationCity = locationCity;\n            LocationCountry = locationCountry;\n        }\n\n        public string LocationCountry { get; }\n\n        internal Guid MeetingGroupId { get; }\n\n        internal string Name { get; }\n\n        internal string Description { get; }\n\n        internal string LocationCity { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/EditMeetingGroupGeneralAttributes/EditMeetingGroupGeneralAttributesCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.EditMeetingGroupGeneralAttributes\r\n{\r\n    internal class EditMeetingGroupGeneralAttributesCommandHandler : ICommandHandler<EditMeetingGroupGeneralAttributesCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        internal EditMeetingGroupGeneralAttributesCommandHandler(IMemberContext memberContext, IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(EditMeetingGroupGeneralAttributesCommand request, CancellationToken cancellationToken)\r\n        {\r\n            MeetingGroup meetingGroup =\r\n                await _meetingGroupRepository.GetByIdAsync(new MeetingGroupId(request.MeetingGroupId));\r\n\r\n            meetingGroup.EditGeneralAttributes(request.Name, request.Description, MeetingGroupLocation.CreateNew(request.LocationCity, request.LocationCountry));\r\n\r\n            await _meetingGroupRepository.Commit();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAllMeetingGroups/GetAllMeetingGroupsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups\n{\n    public class GetAllMeetingGroupsQuery : IQuery<List<MeetingGroupDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAllMeetingGroups/GetAllMeetingGroupsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups\n{\n    internal class GetAllMeetingGroupsQueryHandler : IQueryHandler<GetAllMeetingGroupsQuery, List<MeetingGroupDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        internal GetAllMeetingGroupsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingGroupDto>> Handle(GetAllMeetingGroupsQuery request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT \n                                    [MeetingGroup].[Id] as [{nameof(MeetingGroupDto.Id)}] , \n                                    [MeetingGroup].[Name] as [{nameof(MeetingGroupDto.Name)}], \n                                    [MeetingGroup].[Description] as [{nameof(MeetingGroupDto.Description)}], \n                                    [MeetingGroup].[LocationCountryCode] as [{nameof(MeetingGroupDto.LocationCountryCode)}],\n                                    [MeetingGroup].[LocationCity] as [{nameof(MeetingGroupDto.LocationCity)}]\n                               FROM [meetings].[v_MeetingGroups] AS [MeetingGroup]\n                               \"\"\";\n            var meetingGroups = await connection.QueryAsync<MeetingGroupDto>(sql);\n\n            return meetingGroups.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAllMeetingGroups/MeetingGroupDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups\n{\n    public class MeetingGroupDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCountryCode { get; set; }\n\n        public string LocationCity { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAuthenticationMemberMeetingGroups/GetAuthenticationMemberMeetingGroupsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAuthenticationMemberMeetingGroups\n{\n    public class GetAuthenticationMemberMeetingGroupsQuery : QueryBase<List<MemberMeetingGroupDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAuthenticationMemberMeetingGroups/GetAuthenticationMemberMeetingGroupsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAuthenticationMemberMeetingGroups\n{\n    internal class GetAuthenticationMemberMeetingGroupsQueryHandler :\n        IQueryHandler<GetAuthenticationMemberMeetingGroupsQuery, List<MemberMeetingGroupDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public GetAuthenticationMemberMeetingGroupsQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _executionContextAccessor = executionContextAccessor;\n        }\n\n        public async Task<List<MemberMeetingGroupDto>> Handle(\n            GetAuthenticationMemberMeetingGroupsQuery query,\n            CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT \n                                   [MemberMeetingGroup].[Id] AS [{nameof(MemberMeetingGroupDto.Id)}], \n                                   [MemberMeetingGroup].[Name] AS [{nameof(MemberMeetingGroupDto.Name)}], \n                                   [MemberMeetingGroup].[Description] AS [{nameof(MemberMeetingGroupDto.Description)}], \n                                   [MemberMeetingGroup].[LocationCountryCode] AS [{nameof(MemberMeetingGroupDto.LocationCountryCode)}], \n                                   [MemberMeetingGroup].[LocationCity] AS [{nameof(MemberMeetingGroupDto.LocationCity)}], \n                                   [MemberMeetingGroup].[MemberId] AS [{nameof(MemberMeetingGroupDto.MemberId)}], \n                                   [MemberMeetingGroup].[RoleCode] AS [{nameof(MemberMeetingGroupDto.RoleCode)}] \n                               FROM [meetings].[v_MemberMeetingGroups] AS [MemberMeetingGroup] \n                               WHERE \n                                   [MemberMeetingGroup].MemberId = @MemberId AND\n                                   [MemberMeetingGroup].[IsActive] = 1\n                               \"\"\";\n\n            var meetingGroups = await connection.QueryAsync<MemberMeetingGroupDto>(\n                sql,\n                new\n                {\n                    MemberId = _executionContextAccessor.UserId\n                });\n\n            return meetingGroups.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetAuthenticationMemberMeetingGroups/MemberMeetingGroupDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAuthenticationMemberMeetingGroups\n{\n    public class MemberMeetingGroupDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCountryCode { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public Guid MemberId { get; set; }\n\n        public string RoleCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetMeetingGroupDetails/GetMeetingGroupDetailsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetMeetingGroupDetails\n{\n    public class GetMeetingGroupDetailsQuery : QueryBase<MeetingGroupDetailsDto>\n    {\n        public GetMeetingGroupDetailsQuery(Guid meetingGroupId)\n        {\n            MeetingGroupId = meetingGroupId;\n        }\n\n        public Guid MeetingGroupId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetMeetingGroupDetails/GetMeetingGroupDetailsQueryHandler.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetMeetingGroupDetails\n{\n    internal class GetMeetingGroupDetailsQueryHandler : IQueryHandler<GetMeetingGroupDetailsQuery, MeetingGroupDetailsDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingGroupDetailsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MeetingGroupDetailsDto> Handle(GetMeetingGroupDetailsQuery query, CancellationToken cancellationToken)\n        {\n            using var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT\n                                    [MeetingGroup].[Id] AS [{nameof(MeetingGroupDetailsDto.Id)}],\n                                    [MeetingGroup].[Name] AS [{nameof(MeetingGroupDetailsDto.Name)}],\n                                    [MeetingGroup].[Description] AS [{nameof(MeetingGroupDetailsDto.Description)}],\n                                    [MeetingGroup].[LocationCity] AS [{nameof(MeetingGroupDetailsDto.LocationCity)}],\n                                    [MeetingGroup].[LocationCountryCode] AS [{nameof(MeetingGroupDetailsDto.LocationCountryCode)}]\n                                FROM [meetings].[v_MeetingGroups] AS [MeetingGroup]\n                                WHERE [MeetingGroup].[Id] = @MeetingGroupId\n                                \"\"\";\n            var meetingGroup = await connection.QuerySingleAsync<MeetingGroupDetailsDto>(\n                sql,\n                new\n                {\n                    query.MeetingGroupId\n                });\n\n            meetingGroup.MembersCount = await GetMembersCount(query.MeetingGroupId, connection);\n\n            return meetingGroup;\n        }\n\n        private static async Task<int> GetMembersCount(Guid meetingGroupId, IDbConnection connection)\n        {\n            const string sql = \"\"\"\n                               SELECT COUNT(*)\n                               FROM [meetings].[v_MemberMeetingGroups] AS [MemberMeetingGroup]\n                               WHERE\n                                   [MemberMeetingGroup].[Id] = @MeetingGroupId AND\n                                   [MemberMeetingGroup].[IsActive] = 1\n                               \"\"\";\n\n            return await connection.ExecuteScalarAsync<int>(\n                sql,\n                new\n                {\n                    meetingGroupId\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/GetMeetingGroupDetails/MeetingGroupDetailsDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetMeetingGroupDetails\n{\n    public class MeetingGroupDetailsDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationCountryCode { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public int MembersCount { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/JoinToGroup/JoinToGroupCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.JoinToGroup\n{\n    public class JoinToGroupCommand : CommandBase\n    {\n        public JoinToGroupCommand(Guid meetingGroupId)\n        {\n            MeetingGroupId = meetingGroupId;\n        }\n\n        internal Guid MeetingGroupId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/JoinToGroup/JoinToGroupCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.JoinToGroup\r\n{\r\n    internal class JoinToGroupCommandHandler : ICommandHandler<JoinToGroupCommand>\r\n    {\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal JoinToGroupCommandHandler(\r\n            IMeetingGroupRepository meetingGroupRepository,\r\n            IMemberContext memberContext)\r\n        {\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(JoinToGroupCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(new MeetingGroupId(request.MeetingGroupId));\r\n\r\n            meetingGroup.JoinToGroupMember(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/LeaveMeetingGroup/LeaveMeetingGroupCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.LeaveMeetingGroup\n{\n    public class LeaveMeetingGroupCommand : CommandBase\n    {\n        public LeaveMeetingGroupCommand(Guid meetingGroupId)\n        {\n            MeetingGroupId = meetingGroupId;\n        }\n\n        internal Guid MeetingGroupId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/LeaveMeetingGroup/LeaveMeetingGroupCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.LeaveMeetingGroup\r\n{\r\n    internal class LeaveMeetingGroupCommandHandler : ICommandHandler<LeaveMeetingGroupCommand>\r\n    {\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal LeaveMeetingGroupCommandHandler(\r\n            IMeetingGroupRepository meetingGroupRepository,\r\n            IMemberContext memberContext)\r\n        {\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(LeaveMeetingGroupCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(new MeetingGroupId(request.MeetingGroupId));\r\n\r\n            meetingGroup.LeaveGroup(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/MeetingGroupCreatedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups\n{\n    public class MeetingGroupCreatedNotification : DomainNotificationBase<MeetingGroupCreatedDomainEvent>\n    {\n        [JsonConstructor]\n        internal MeetingGroupCreatedNotification(MeetingGroupCreatedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/MeetingGroupCreatedSendEmailHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SendMeetingGroupCreatedEmail;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups\n{\n    internal class MeetingGroupCreatedSendEmailHandler : INotificationHandler<MeetingGroupCreatedNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public MeetingGroupCreatedSendEmailHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingGroupCreatedNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new SendMeetingGroupCreatedEmailCommand(\n                    Guid.NewGuid(),\n                    notification.DomainEvent.MeetingGroupId,\n                    notification.DomainEvent.CreatorId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/SendMeetingGroupCreatedEmail/SendMeetingGroupCreatedEmailCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SendMeetingGroupCreatedEmail\n{\n    internal class SendMeetingGroupCreatedEmailCommand : InternalCommandBase\n    {\n        internal MeetingGroupId MeetingGroupId { get; }\n\n        internal MemberId CreatorId { get; }\n\n        [JsonConstructor]\n        internal SendMeetingGroupCreatedEmailCommand(Guid id, MeetingGroupId meetingGroupId, MemberId creatorId)\n            : base(id)\n        {\n            MeetingGroupId = meetingGroupId;\n            CreatorId = creatorId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/SendMeetingGroupCreatedEmail/SendMeetingGroupCreatedEmailCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members;\r\nusing Dapper;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SendMeetingGroupCreatedEmail\r\n{\r\n    internal class SendMeetingGroupCreatedEmailCommandHandler : ICommandHandler<SendMeetingGroupCreatedEmailCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n        private readonly IEmailSender _emailSender;\r\n\r\n        public SendMeetingGroupCreatedEmailCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IEmailSender emailSender)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _emailSender = emailSender;\r\n        }\r\n\r\n        public async Task Handle(SendMeetingGroupCreatedEmailCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var connection = _sqlConnectionFactory.GetOpenConnection();\r\n\r\n            const string sql = $\"\"\"\r\n                                SELECT\r\n                                    [MeetingGroup].[Name] as [{nameof(MeetingGroupDto.Name)}],\r\n                                    [MeetingGroup].[LocationCountryCode] as [{nameof(MeetingGroupDto.LocationCountryCode)}],\r\n                                    [MeetingGroup].[LocationCity] as [{nameof(MeetingGroupDto.LocationCity)}]\r\n                                FROM [meetings].[v_MeetingGroups] AS [MeetingGroup]\r\n                                WHERE [MeetingGroup].[Id] = @Id\r\n                                \"\"\";\r\n            var meetingGroup = await connection.QuerySingleAsync<MeetingGroupDto>(\r\n                sql,\r\n                new\r\n                      {\r\n                          Id = request.MeetingGroupId.Value\r\n                      });\r\n\r\n            var member = await MembersQueryHelper.GetMember(request.CreatorId, connection);\r\n\r\n            var email = new EmailMessage(\r\n                member.Email,\r\n                $\"{meetingGroup.Name} created\",\r\n                $\"{meetingGroup.Name} created at {meetingGroup.LocationCity}, {meetingGroup.LocationCountryCode}\");\r\n\r\n            await _emailSender.SendEmail(email);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/SetMeetingGroupExpirationDate/SetMeetingGroupExpirationDateCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SetMeetingGroupExpirationDate\n{\n    public class SetMeetingGroupExpirationDateCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public SetMeetingGroupExpirationDateCommand(Guid id, Guid meetingGroupId, DateTime dateTo)\n            : base(id)\n        {\n            MeetingGroupId = meetingGroupId;\n            DateTo = dateTo;\n        }\n\n        internal Guid MeetingGroupId { get; }\n\n        internal DateTime DateTo { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MeetingGroups/SetMeetingGroupExpirationDate/SetMeetingGroupExpirationDateCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SetMeetingGroupExpirationDate\r\n{\r\n    internal class SetMeetingGroupExpirationDateCommandHandler : ICommandHandler<SetMeetingGroupExpirationDateCommand>\r\n    {\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        internal SetMeetingGroupExpirationDateCommandHandler(IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(SetMeetingGroupExpirationDateCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(new MeetingGroupId(request.MeetingGroupId));\r\n\r\n            meetingGroup.SetExpirationDate(request.DateTo);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/AddMeetingAttendee/AddMeetingAttendeeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingAttendee\n{\n    public class AddMeetingAttendeeCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public int GuestsNumber { get; }\n\n        public AddMeetingAttendeeCommand(Guid meetingId, int guestsNumber)\n        {\n            MeetingId = meetingId;\n            GuestsNumber = guestsNumber;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/AddMeetingAttendee/AddMeetingAttendeeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingAttendee\r\n{\r\n    internal class AddMeetingAttendeeCommandHandler : ICommandHandler<AddMeetingAttendeeCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        public AddMeetingAttendeeCommandHandler(\r\n            IMemberContext memberContext,\r\n            IMeetingRepository meetingRepository,\r\n            IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(AddMeetingAttendeeCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meeting.AddAttendee(meetingGroup, _memberContext.MemberId, request.GuestsNumber);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/AddMeetingNotAttendee/AddMeetingNotAttendeeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingNotAttendee\n{\n    public class AddMeetingNotAttendeeCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public AddMeetingNotAttendeeCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/AddMeetingNotAttendee/AddMeetingNotAttendeeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingNotAttendee\r\n{\r\n    internal class AddMeetingNotAttendeeCommandHandler : ICommandHandler<AddMeetingNotAttendeeCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n\r\n        public AddMeetingNotAttendeeCommandHandler(IMemberContext memberContext, IMeetingRepository meetingRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n        }\r\n\r\n        public async Task Handle(AddMeetingNotAttendeeCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.AddNotAttendee(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/CancelMeeting/CancelMeetingCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CancelMeeting\n{\n    public class CancelMeetingCommand : CommandBase\n    {\n        public CancelMeetingCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/CancelMeeting/CancelMeetingCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CancelMeeting\r\n{\r\n    internal class CancelMeetingCommandHandler : ICommandHandler<CancelMeetingCommand>\r\n    {\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal CancelMeetingCommandHandler(IMeetingRepository meetingRepository, IMemberContext memberContext)\r\n        {\r\n            _meetingRepository = meetingRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(CancelMeetingCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.Cancel(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/ChangeMeetingMainAttributes/ChangeMeetingMainAttributesCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeMeetingMainAttributes\n{\n    public class ChangeMeetingMainAttributesCommand : CommandBase\n    {\n        public ChangeMeetingMainAttributesCommand(\n            Guid meetingId,\n            string title,\n            DateTime termStartDate,\n            DateTime termEndDate,\n            string description,\n            string meetingLocationName,\n            string meetingLocationAddress,\n            string meetingLocationPostalCode,\n            string meetingLocationCity,\n            int? attendeesLimit,\n            int guestsLimit,\n            DateTime? rsvpTermStartDate,\n            DateTime? rsvpTermEndDate,\n            decimal? eventFeeValue,\n            string eventFeeCurrency)\n        {\n            MeetingId = meetingId;\n            Title = title;\n            TermStartDate = termStartDate;\n            TermEndDate = termEndDate;\n            Description = description;\n            MeetingLocationName = meetingLocationName;\n            MeetingLocationAddress = meetingLocationAddress;\n            MeetingLocationPostalCode = meetingLocationPostalCode;\n            MeetingLocationCity = meetingLocationCity;\n            AttendeesLimit = attendeesLimit;\n            GuestsLimit = guestsLimit;\n            RSVPTermStartDate = rsvpTermStartDate;\n            RSVPTermEndDate = rsvpTermEndDate;\n            EventFeeValue = eventFeeValue;\n            EventFeeCurrency = eventFeeCurrency;\n        }\n\n        public Guid MeetingId { get; }\n\n        public string Title { get; }\n\n        public DateTime TermStartDate { get; }\n\n        public DateTime TermEndDate { get; }\n\n        public string Description { get; }\n\n        public string MeetingLocationName { get; }\n\n        public string MeetingLocationAddress { get; }\n\n        public string MeetingLocationPostalCode { get; }\n\n        public string MeetingLocationCity { get; }\n\n        public int? AttendeesLimit { get; }\n\n        public int GuestsLimit { get; }\n\n        public DateTime? RSVPTermStartDate { get; }\n\n        public DateTime? RSVPTermEndDate { get; }\n\n        public decimal? EventFeeValue { get; }\n\n        public string EventFeeCurrency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/ChangeMeetingMainAttributes/ChangeMeetingMainAttributesCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeMeetingMainAttributes\r\n{\r\n    internal class ChangeMeetingMainAttributesCommandHandler : ICommandHandler<ChangeMeetingMainAttributesCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n\r\n        public ChangeMeetingMainAttributesCommandHandler(IMemberContext memberContext, IMeetingRepository meetingRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n        }\r\n\r\n        public async Task Handle(ChangeMeetingMainAttributesCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.ChangeMainAttributes(\r\n                request.Title,\r\n                MeetingTerm.CreateNewBetweenDates(request.TermStartDate, request.TermStartDate),\r\n                request.Description,\r\n                MeetingLocation.CreateNew(request.MeetingLocationName, request.MeetingLocationAddress, request.MeetingLocationPostalCode, request.MeetingLocationCity),\r\n                MeetingLimits.Create(request.AttendeesLimit, request.GuestsLimit),\r\n                Term.CreateNewBetweenDates(request.RSVPTermStartDate, request.RSVPTermEndDate),\r\n                request.EventFeeValue.HasValue ? MoneyValue.Of(request.EventFeeValue.Value, request.EventFeeCurrency) : MoneyValue.Undefined,\r\n                _memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/ChangeNotAttendeeDecision/ChangeNotAttendeeDecisionCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeNotAttendeeDecision\n{\n    public class ChangeNotAttendeeDecisionCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public ChangeNotAttendeeDecisionCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/ChangeNotAttendeeDecision/ChangeNotAttendeeDecisionCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.ChangeNotAttendeeDecision\r\n{\r\n    internal class ChangeNotAttendeeDecisionCommandHandler : ICommandHandler<ChangeNotAttendeeDecisionCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n\r\n        public ChangeNotAttendeeDecisionCommandHandler(IMemberContext memberContext, IMeetingRepository meetingRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n        }\r\n\r\n        public async Task Handle(ChangeNotAttendeeDecisionCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.ChangeNotAttendeeDecision(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/CreateMeeting/CreateMeetingCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CreateMeeting\n{\n    public class CreateMeetingCommand : CommandBase<Guid>\n    {\n        public CreateMeetingCommand(\n            Guid meetingGroupId,\n            string title,\n            DateTime termStartDate,\n            DateTime termEndDate,\n            string description,\n            string meetingLocationName,\n            string meetingLocationAddress,\n            string meetingLocationPostalCode,\n            string meetingLocationCity,\n            int? attendeesLimit,\n            int guestsLimit,\n            DateTime? rsvpTermStartDate,\n            DateTime? rsvpTermEndDate,\n            decimal? eventFeeValue,\n            string eventFeeCurrency,\n            List<Guid> hostMemberIds)\n        {\n            MeetingGroupId = meetingGroupId;\n            Title = title;\n            TermStartDate = termStartDate;\n            TermEndDate = termEndDate;\n            Description = description;\n            MeetingLocationName = meetingLocationName;\n            MeetingLocationAddress = meetingLocationAddress;\n            MeetingLocationPostalCode = meetingLocationPostalCode;\n            MeetingLocationCity = meetingLocationCity;\n            AttendeesLimit = attendeesLimit;\n            GuestsLimit = guestsLimit;\n            RSVPTermStartDate = rsvpTermStartDate;\n            RSVPTermEndDate = rsvpTermEndDate;\n            EventFeeValue = eventFeeValue;\n            EventFeeCurrency = eventFeeCurrency;\n            HostMemberIds = hostMemberIds;\n        }\n\n        public Guid MeetingGroupId { get; }\n\n        public string Title { get; }\n\n        public DateTime TermStartDate { get; }\n\n        public DateTime TermEndDate { get; }\n\n        public string Description { get; }\n\n        public string MeetingLocationName { get; }\n\n        public string MeetingLocationAddress { get; }\n\n        public string MeetingLocationPostalCode { get; }\n\n        public string MeetingLocationCity { get; }\n\n        public int? AttendeesLimit { get; }\n\n        public int GuestsLimit { get; }\n\n        public DateTime? RSVPTermStartDate { get; }\n\n        public DateTime? RSVPTermEndDate { get; }\n\n        public decimal? EventFeeValue { get; }\n\n        public string EventFeeCurrency { get; }\n\n        public List<Guid> HostMemberIds { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/CreateMeeting/CreateMeetingCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CreateMeeting\n{\n    internal class CreateMeetingCommandHandler : ICommandHandler<CreateMeetingCommand, Guid>\n    {\n        private readonly IMemberContext _memberContext;\n        private readonly IMeetingRepository _meetingRepository;\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\n\n        internal CreateMeetingCommandHandler(\n            IMemberContext memberContext,\n            IMeetingRepository meetingRepository,\n            IMeetingGroupRepository meetingGroupRepository)\n        {\n            _memberContext = memberContext;\n            _meetingRepository = meetingRepository;\n            _meetingGroupRepository = meetingGroupRepository;\n        }\n\n        public async Task<Guid> Handle(CreateMeetingCommand request, CancellationToken cancellationToken)\n        {\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(new MeetingGroupId(request.MeetingGroupId));\n\n            var hostsMembersIds = request.HostMemberIds.Select(x => new MemberId(x)).ToList();\n\n            var meeting = meetingGroup.CreateMeeting(\n                request.Title,\n                MeetingTerm.CreateNewBetweenDates(request.TermStartDate, request.TermStartDate),\n                request.Description,\n                MeetingLocation.CreateNew(request.MeetingLocationName, request.MeetingLocationAddress, request.MeetingLocationPostalCode, request.MeetingLocationCity),\n                request.AttendeesLimit,\n                request.GuestsLimit,\n                Term.CreateNewBetweenDates(request.RSVPTermStartDate, request.RSVPTermEndDate),\n                request.EventFeeValue.HasValue ? MoneyValue.Of(request.EventFeeValue.Value, request.EventFeeCurrency) : MoneyValue.Undefined,\n                hostsMembersIds,\n                _memberContext.MemberId);\n\n            await _meetingRepository.AddAsync(meeting);\n\n            return meeting.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetAuthenticatedMemberMeetings/GetAuthenticatedMemberMeetingsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetAuthenticatedMemberMeetings\n{\n    public class GetAuthenticatedMemberMeetingsQuery : QueryBase<List<MemberMeetingDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetAuthenticatedMemberMeetings/GetAuthenticatedMemberMeetingsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetAuthenticatedMemberMeetings\n{\n    internal class GetAuthenticatedMemberMeetingsQueryHandler : IQueryHandler<GetAuthenticatedMemberMeetingsQuery, List<MemberMeetingDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public GetAuthenticatedMemberMeetingsQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _executionContextAccessor = executionContextAccessor;\n        }\n\n        public async Task<List<MemberMeetingDto>> Handle(GetAuthenticatedMemberMeetingsQuery request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            return (await connection.QueryAsync<MemberMeetingDto>(\n                $\"\"\"\n                 SELECT [Meeting].[Id] AS [{nameof(MemberMeetingDto.MeetingId)}], \n                        [Meeting].[RoleCode] AS [{nameof(MemberMeetingDto.RoleCode)}], \n                        [Meeting].[LocationCity] AS [{nameof(MemberMeetingDto.LocationCity)}], \n                        [Meeting].[LocationAddress] AS [{nameof(MemberMeetingDto.LocationAddress)}], \n                        [Meeting].[LocationPostalCode] AS [{nameof(MemberMeetingDto.LocationPostalCode)}], \n                        [Meeting].[TermStartDate] AS [{nameof(MemberMeetingDto.TermStartDate)}], \n                        [Meeting].[TermEndDate] AS [{nameof(MemberMeetingDto.TermEndDate)}], \n                        [Meeting].[Title] AS [{nameof(MemberMeetingDto.Title)}] \n                 FROM [meetings].[v_MemberMeetings] AS [Meeting] \n                 WHERE [Meeting].[AttendeeId] = @AttendeeId AND [Meeting].[IsRemoved] = 0\n                 \"\"\",\n                new\n                {\n                    AttendeeId = _executionContextAccessor.UserId\n                })).AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetAuthenticatedMemberMeetings/MemberMeetingDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetAuthenticatedMemberMeetings\n{\n    public class MemberMeetingDto\n    {\n        public Guid MeetingId { get; set; }\n\n        public string Title { get; set; }\n\n        public string LocationAddress { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationPostalCode { get; set; }\n\n        public DateTime TermStartDate { get; set; }\n\n        public DateTime TermEndDate { get; set; }\n\n        public string RoleCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingAttendees/GetMeetingAttendeesQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingAttendees\n{\n    public class GetMeetingAttendeesQuery : QueryBase<List<MeetingAttendeeDto>>\n    {\n        public GetMeetingAttendeesQuery(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingAttendees/GetMeetingAttendeesQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingAttendees\n{\n    internal class GetMeetingAttendeesQueryHandler : IQueryHandler<GetMeetingAttendeesQuery, List<MeetingAttendeeDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingAttendeesQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingAttendeeDto>> Handle(GetMeetingAttendeesQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n            const string sql = $\"\"\"\n                                SELECT\n                                    [MeetingAttendee].[FirstName] AS [{nameof(MeetingAttendeeDto.FirstName)}],\n                                    [MeetingAttendee].[LastName] AS [{nameof(MeetingAttendeeDto.LastName)}],\n                                    [MeetingAttendee].[RoleCode] AS [{nameof(MeetingAttendeeDto.RoleCode)}],\n                                    [MeetingAttendee].[DecisionDate] AS [{nameof(MeetingAttendeeDto.DecisionDate)}],\n                                    [MeetingAttendee].[GuestsNumber] AS [{nameof(MeetingAttendeeDto.GuestsNumber)}],\n                                    [MeetingAttendee].[AttendeeId] AS [{nameof(MeetingAttendeeDto.AttendeeId)}]\n                                FROM [meetings].[v_MeetingAttendees] AS [MeetingAttendee]\n                                WHERE [MeetingAttendee].[MeetingId] = @MeetingId\n                                \"\"\";\n            return (await connection.QueryAsync<MeetingAttendeeDto>(\n                sql,\n                new\n                {\n                    query.MeetingId\n                })).AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingAttendees/MeetingAttendeeDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingAttendees\n{\n    public class MeetingAttendeeDto\n    {\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public Guid AttendeeId { get; set; }\n\n        public string RoleCode { get; set; }\n\n        public int GuestsNumber { get; set; }\n\n        public DateTime DecisionDate { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingDetails/GetMeetingDetailsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingDetails\n{\n    public class GetMeetingDetailsQuery : QueryBase<MeetingDetailsDto>\n    {\n        public GetMeetingDetailsQuery(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingDetails/GetMeetingDetailsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingDetails\n{\n    internal class GetMeetingDetailsQueryHandler : IQueryHandler<GetMeetingDetailsQuery, MeetingDetailsDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingDetailsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<MeetingDetailsDto> Handle(GetMeetingDetailsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            return await connection.QuerySingleAsync<MeetingDetailsDto>(\n                $\"\"\"\n                 SELECT \n                     [MeetingDetails].[Id] AS [{nameof(MeetingDetailsDto.Id)}], \n                     [MeetingDetails].[MeetingGroupId] AS [{nameof(MeetingDetailsDto.MeetingGroupId)}],\n                     [MeetingDetails].[Title] AS [{nameof(MeetingDetailsDto.Title)}], \n                     [MeetingDetails].[TermStartDate] AS [{nameof(MeetingDetailsDto.TermStartDate)}], \n                     [MeetingDetails].[TermEndDate] AS [{nameof(MeetingDetailsDto.TermEndDate)}], \n                     [MeetingDetails].[Description] AS [{nameof(MeetingDetailsDto.Description)}], \n                     [MeetingDetails].[LocationName] AS [{nameof(MeetingDetailsDto.LocationName)}], \n                     [MeetingDetails].[LocationAddress] AS [{nameof(MeetingDetailsDto.LocationAddress)}], \n                     [MeetingDetails].[LocationPostalCode] AS [{nameof(MeetingDetailsDto.LocationPostalCode)}], \n                     [MeetingDetails].[LocationCity] AS [{nameof(MeetingDetailsDto.LocationCity)}], \n                     [MeetingDetails].[AttendeesLimit] AS [{nameof(MeetingDetailsDto.AttendeesLimit)}], \n                     [MeetingDetails].[GuestsLimit] AS [{nameof(MeetingDetailsDto.GuestsLimit)}], \n                     [MeetingDetails].[RSVPTermStartDate] AS [{nameof(MeetingDetailsDto.RSVPTermStartDate)}], \n                     [MeetingDetails].[RSVPTermEndDate] AS [{nameof(MeetingDetailsDto.RSVPTermEndDate)}], \n                     [MeetingDetails].[EventFeeValue] AS [{nameof(MeetingDetailsDto.EventFeeValue)}], \n                     [MeetingDetails].[EventFeeCurrency] AS [{nameof(MeetingDetailsDto.EventFeeCurrency)}] \n                 FROM [meetings].[v_MeetingDetails] AS [MeetingDetails] \n                 WHERE [MeetingDetails].[Id] = @MeetingId\n                 \"\"\",\n                new\n                {\n                    query.MeetingId\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/GetMeetingDetails/MeetingDetailsDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingDetails\n{\n    public class MeetingDetailsDto\n    {\n        public Guid Id { get; set; }\n\n        public Guid MeetingGroupId { get; set; }\n\n        public string Title { get; set; }\n\n        public DateTime TermStartDate { get; set; }\n\n        public DateTime TermEndDate { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationName { get; set; }\n\n        public string LocationAddress { get; set; }\n\n        public string LocationPostalCode { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public int? AttendeesLimit { get; set; }\n\n        public int GuestsLimit { get; set; }\n\n        public DateTime? RSVPTermStartDate { get; set; }\n\n        public DateTime? RSVPTermEndDate { get; set; }\n\n        public decimal? EventFeeValue { get; set; }\n\n        public string EventFeeCurrency { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/MarkMeetingAttendeeFeeAsPayedCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings\n{\n    public class MarkMeetingAttendeeFeeAsPayedCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public MarkMeetingAttendeeFeeAsPayedCommand(Guid id, Guid memberId, Guid meetingId)\n            : base(id)\n        {\n            MemberId = memberId;\n\n            MeetingId = meetingId;\n        }\n\n        public Guid MemberId { get; }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/MarkMeetingAttendeeFeeAsPayedCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings\r\n{\r\n    internal class MarkMeetingAttendeeFeeAsPayedCommandHandler : ICommandHandler<MarkMeetingAttendeeFeeAsPayedCommand>\r\n    {\r\n        private readonly IMeetingRepository _meetingRepository;\r\n\r\n        public MarkMeetingAttendeeFeeAsPayedCommandHandler(IMeetingRepository meetingRepository)\r\n        {\r\n            _meetingRepository = meetingRepository;\r\n        }\r\n\r\n        public async Task Handle(MarkMeetingAttendeeFeeAsPayedCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(command.MeetingId));\r\n\r\n            meeting.MarkAttendeeFeeAsPayed(new MemberId(command.MemberId));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/MeetingDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings\n{\n    public class MeetingDto\n    {\n        public Guid Id { get; set; }\n\n        public string Title { get; set; }\n\n        public string Description { get; set; }\n\n        public string LocationAddress { get; set; }\n\n        public string LocationCity { get; set; }\n\n        public string LocationPostalCode { get; set; }\n\n        public DateTime TermStartDate { get; set; }\n\n        public DateTime TermEndDate { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/MeetingFeePaidIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings\n{\n    public class MeetingFeePaidIntegrationEventHandler : INotificationHandler<MeetingFeePaidIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public MeetingFeePaidIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingFeePaidIntegrationEvent @event, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new MarkMeetingAttendeeFeeAsPayedCommand(\n                Guid.NewGuid(),\n                @event.PayerId,\n                @event.MeetingId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/MeetingsQueryHelper.cs",
    "content": "﻿using System.Data;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing Dapper;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings\r\n{\r\n    public class MeetingsQueryHelper\r\n    {\r\n        public static async Task<MeetingDto> GetMeeting(MeetingId meetingId, IDbConnection connection)\r\n        {\r\n            const string sql = $\"\"\"\r\n                       SELECT\r\n                           [Meeting].Id as [{nameof(MeetingDto.Id)}],\r\n                           [Meeting].Title as [{nameof(MeetingDto.Title)}],\r\n                           [Meeting].Description as [{nameof(MeetingDto.Description)}],\r\n                           [Meeting].LocationAddress as [{nameof(MeetingDto.LocationAddress)}],\r\n                           [Meeting].LocationCity as [{nameof(MeetingDto.LocationCity)}],\r\n                           [Meeting].LocationPostalCode as [{nameof(MeetingDto.LocationPostalCode)}],\r\n                           [Meeting].TermStartDate as [{nameof(MeetingDto.TermStartDate)}],\r\n                           [Meeting].TermEndDate as [{nameof(MeetingDto.TermEndDate)}]\r\n                       FROM [meetings].[v_Meetings] AS [Meeting]\r\n                       WHERE [Meeting].[Id] = @Id\r\n                       \"\"\";\r\n            return await connection.QuerySingleAsync<MeetingDto>(\r\n                sql,\r\n                new\r\n                {\r\n                    Id = meetingId.Value\r\n                });\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/RemoveMeetingAttendee/RemoveMeetingAttendeeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.RemoveMeetingAttendee\n{\n    public class RemoveMeetingAttendeeCommand : CommandBase\n    {\n        public RemoveMeetingAttendeeCommand(Guid meetingId, Guid attendeeId, string removingReason)\n        {\n            MeetingId = meetingId;\n            AttendeeId = attendeeId;\n            RemovingReason = removingReason;\n        }\n\n        public Guid MeetingId { get; }\n\n        public Guid AttendeeId { get; }\n\n        public string RemovingReason { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/RemoveMeetingAttendee/RemoveMeetingAttendeeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.RemoveMeetingAttendee\r\n{\r\n    internal class RemoveMeetingAttendeeCommandHandler : ICommandHandler<RemoveMeetingAttendeeCommand>\r\n    {\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMemberContext _memberContext;\r\n\r\n        internal RemoveMeetingAttendeeCommandHandler(IMeetingRepository meetingRepository, IMemberContext memberContext)\r\n        {\r\n            _meetingRepository = meetingRepository;\r\n            _memberContext = memberContext;\r\n        }\r\n\r\n        public async Task Handle(RemoveMeetingAttendeeCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.RemoveAttendee(new MemberId(request.AttendeeId), _memberContext.MemberId, request.RemovingReason);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SendMeetingAttendeeAddedEmail/MeetingAttendeeAddedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail\n{\n    public class MeetingAttendeeAddedNotification : DomainNotificationBase<MeetingAttendeeAddedDomainEvent>\n    {\n        [JsonConstructor]\n        public MeetingAttendeeAddedNotification(MeetingAttendeeAddedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SendMeetingAttendeeAddedEmail/MeetingAttendeeAddedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail\n{\n    internal class MeetingAttendeeAddedNotificationHandler : INotificationHandler<MeetingAttendeeAddedNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal MeetingAttendeeAddedNotificationHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingAttendeeAddedNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new SendMeetingAttendeeAddedEmailCommand(\n                    Guid.NewGuid(),\n                    notification.DomainEvent.AttendeeId,\n                    notification.DomainEvent.MeetingId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SendMeetingAttendeeAddedEmail/MeetingAttendeeAddedPublishEventNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail\n{\n    internal class MeetingAttendeeAddedPublishEventNotificationHandler : INotificationHandler<MeetingAttendeeAddedNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        internal MeetingAttendeeAddedPublishEventNotificationHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(MeetingAttendeeAddedNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new MeetingAttendeeAddedIntegrationEvent(\n                Guid.NewGuid(),\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.MeetingId.Value,\n                notification.DomainEvent.AttendeeId.Value,\n                notification.DomainEvent.FeeValue,\n                notification.DomainEvent.FeeCurrency));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SendMeetingAttendeeAddedEmail/SendMeetingAttendeeAddedEmailCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail\n{\n    internal class SendMeetingAttendeeAddedEmailCommand : InternalCommandBase\n    {\n        internal MemberId AttendeeId { get; }\n\n        internal MeetingId MeetingId { get; }\n\n        [JsonConstructor]\n        internal SendMeetingAttendeeAddedEmailCommand(Guid id, MemberId attendeeId, MeetingId meetingId)\n            : base(id)\n        {\n            AttendeeId = attendeeId;\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SendMeetingAttendeeAddedEmail/SendMeetingAttendeeAddedEmailCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail\r\n{\r\n    internal class SendMeetingAttendeeAddedEmailCommandHandler : ICommandHandler<SendMeetingAttendeeAddedEmailCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n        private readonly IEmailSender _emailSender;\r\n\r\n        internal SendMeetingAttendeeAddedEmailCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IEmailSender emailSender)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _emailSender = emailSender;\r\n        }\r\n\r\n        public async Task Handle(SendMeetingAttendeeAddedEmailCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var connection = _sqlConnectionFactory.GetOpenConnection();\r\n\r\n            var member = await MembersQueryHelper.GetMember(request.AttendeeId, connection);\r\n\r\n            var meeting = await MeetingsQueryHelper.GetMeeting(request.MeetingId, connection);\r\n\r\n            var email = new EmailMessage(\r\n                member.Email,\r\n                $\"You joined to {meeting.Title} meeting.\",\r\n                $\"You joined to {meeting.Title} title at {meeting.TermStartDate.ToShortDateString()} - {meeting.TermEndDate.ToShortDateString()}, location {meeting.LocationAddress}, {meeting.LocationPostalCode}, {meeting.LocationCity}\");\r\n\r\n            await _emailSender.SendEmail(email);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SetMeetingAttendeeRole/SetMeetingAttendeeRoleCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingAttendeeRole\n{\n    public class SetMeetingAttendeeRoleCommand : CommandBase\n    {\n        public Guid MemberId { get; }\n\n        public Guid MeetingId { get; }\n\n        public SetMeetingAttendeeRoleCommand(Guid memberId, Guid meetingId)\n        {\n            MemberId = memberId;\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SetMeetingAttendeeRole/SetMeetingAttendeeRoleCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingAttendeeRole\r\n{\r\n    internal class SetMeetingAttendeeRoleCommandHandler : ICommandHandler<SetMeetingAttendeeRoleCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        internal SetMeetingAttendeeRoleCommandHandler(\r\n            IMemberContext memberContext,\r\n            IMeetingRepository meetingRepository,\r\n            IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(SetMeetingAttendeeRoleCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meeting.SetAttendeeRole(meetingGroup, _memberContext.MemberId, new MemberId(request.MemberId));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SetMeetingHostRole/SetMeetingHostRoleCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingHostRole\n{\n    public class SetMeetingHostRoleCommand : CommandBase\n    {\n        public Guid MemberId { get; }\n\n        public Guid MeetingId { get; }\n\n        public SetMeetingHostRoleCommand(Guid memberId, Guid meetingId)\n        {\n            MemberId = memberId;\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SetMeetingHostRole/SetMeetingHostRoleCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SetMeetingHostRole\r\n{\r\n    internal class SetMeetingHostRoleCommandHandler : ICommandHandler<SetMeetingHostRoleCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        internal SetMeetingHostRoleCommandHandler(\r\n            IMemberContext memberContext,\r\n            IMeetingRepository meetingRepository,\r\n            IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(SetMeetingHostRoleCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meeting.SetHostRole(meetingGroup, _memberContext.MemberId, new MemberId(request.MemberId));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SignOffMemberFromWaitlist/SignOffMemberFromWaitlistCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignOffMemberFromWaitlist\n{\n    public class SignOffMemberFromWaitlistCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public SignOffMemberFromWaitlistCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SignOffMemberFromWaitlist/SignOffMemberFromWaitlistCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignOffMemberFromWaitlist\r\n{\r\n    internal class SignOffMemberFromWaitlistCommandHandler : ICommandHandler<SignOffMemberFromWaitlistCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n\r\n        public SignOffMemberFromWaitlistCommandHandler(IMemberContext memberContext, IMeetingRepository meetingRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n        }\r\n\r\n        public async Task Handle(SignOffMemberFromWaitlistCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            meeting.SignOffMemberFromWaitlist(_memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SignUpMemberToWaitlist/SignUpMemberToWaitlistCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignUpMemberToWaitlist\n{\n    public class SignUpMemberToWaitlistCommand : CommandBase\n    {\n        public Guid MeetingId { get; }\n\n        public SignUpMemberToWaitlistCommand(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Meetings/SignUpMemberToWaitlist/SignUpMemberToWaitlistCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SignUpMemberToWaitlist\r\n{\r\n    internal class SignUpMemberToWaitlistCommandHandler : ICommandHandler<SignUpMemberToWaitlistCommand>\r\n    {\r\n        private readonly IMemberContext _memberContext;\r\n        private readonly IMeetingRepository _meetingRepository;\r\n        private readonly IMeetingGroupRepository _meetingGroupRepository;\r\n\r\n        public SignUpMemberToWaitlistCommandHandler(\r\n            IMemberContext memberContext,\r\n            IMeetingRepository meetingRepository,\r\n            IMeetingGroupRepository meetingGroupRepository)\r\n        {\r\n            _memberContext = memberContext;\r\n            _meetingRepository = meetingRepository;\r\n            _meetingGroupRepository = meetingGroupRepository;\r\n        }\r\n\r\n        public async Task Handle(SignUpMemberToWaitlistCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var meeting = await _meetingRepository.GetByIdAsync(new MeetingId(request.MeetingId));\r\n\r\n            var meetingGroup = await _meetingGroupRepository.GetByIdAsync(meeting.GetMeetingGroupId());\r\n\r\n            meeting.SignUpMemberToWaitlist(meetingGroup, _memberContext.MemberId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MemberSubscriptions/ChangeSubscriptionExpirationDateForMember/ChangeSubscriptionExpirationDateForMemberCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions.ChangeSubscriptionExpirationDateForMember\n{\n    public class ChangeSubscriptionExpirationDateForMemberCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public ChangeSubscriptionExpirationDateForMemberCommand(\n            Guid id,\n            MemberId memberId,\n            DateTime expirationDate)\n            : base(id)\n        {\n            MemberId = memberId;\n            ExpirationDate = expirationDate;\n        }\n\n        public MemberId MemberId { get; }\n\n        public DateTime ExpirationDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MemberSubscriptions/ChangeSubscriptionExpirationDateForMember/ChangeSubscriptionExpirationDateForMemberCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions.ChangeSubscriptionExpirationDateForMember\r\n{\r\n    internal class ChangeSubscriptionExpirationDateForMemberCommandHandler : ICommandHandler<ChangeSubscriptionExpirationDateForMemberCommand>\r\n    {\r\n        private readonly IMemberSubscriptionRepository _memberSubscriptionRepository;\r\n\r\n        public ChangeSubscriptionExpirationDateForMemberCommandHandler(IMemberSubscriptionRepository memberSubscriptionRepository)\r\n        {\r\n            _memberSubscriptionRepository = memberSubscriptionRepository;\r\n        }\r\n\r\n        public async Task Handle(ChangeSubscriptionExpirationDateForMemberCommand command, CancellationToken cancellationToken)\r\n        {\r\n            MemberSubscription memberSubscription = await _memberSubscriptionRepository.GetByIdOptionalAsync(new MemberSubscriptionId(command.MemberId.Value));\r\n\r\n            if (memberSubscription == null)\r\n            {\r\n                memberSubscription = MemberSubscription.CreateForMember(command.MemberId, command.ExpirationDate);\r\n                await _memberSubscriptionRepository.AddAsync(memberSubscription);\r\n            }\r\n            else\r\n            {\r\n                memberSubscription.ChangeExpirationDate(command.ExpirationDate);\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MemberSubscriptions/MemberSubscriptionExpirationDateChangedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions\n{\n    public class MemberSubscriptionExpirationDateChangedNotification : DomainNotificationBase<MemberSubscriptionExpirationDateChangedDomainEvent>\n    {\n        [JsonConstructor]\n        public MemberSubscriptionExpirationDateChangedNotification(MemberSubscriptionExpirationDateChangedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MemberSubscriptions/MemberSubscriptionExpirationDateChangedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SetMeetingGroupExpirationDate;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Policies;\nusing Dapper;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions\n{\n    public class MemberSubscriptionExpirationDateChangedNotificationHandler :\n        INotificationHandler<MemberSubscriptionExpirationDateChangedNotification>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public MemberSubscriptionExpirationDateChangedNotificationHandler(ISqlConnectionFactory sqlConnectionFactory, ICommandsScheduler commandsScheduler)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MemberSubscriptionExpirationDateChangedNotification notification, CancellationToken cancellationToken)\n        {\n            const string sql = $\"\"\"\n                               SELECT \n                                   [MeetingGroupMember].MeetingGroupId AS [{nameof(MeetingGroupMemberResponse.MeetingGroupId)}], \n                                   [MeetingGroupMember].RoleCode AS [{nameof(MeetingGroupMemberResponse.RoleCode)}] \n                               FROM [meetings].[v_MeetingGroupMembers] AS [MeetingGroupMember] \n                               WHERE [MeetingGroupMember].MemberId = @MemberId\n                               \"\"\";\n\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            var meetingGroupMembers = await connection.QueryAsync<MeetingGroupMemberResponse>(\n                sql,\n                new\n                {\n                    MemberId = notification.DomainEvent.MemberId.Value\n                });\n\n            var meetingGroupList = meetingGroupMembers.AsList();\n\n            List<MeetingGroupMemberData> meetingGroups = meetingGroupList\n                .Select(x =>\n                    new MeetingGroupMemberData(\n                        new MeetingGroupId(x.MeetingGroupId),\n                        MeetingGroupMemberRole.Of(x.RoleCode)))\n                .ToList();\n\n            var meetingGroupsCoveredByMemberSubscription =\n                MeetingGroupExpirationDatePolicy.GetMeetingGroupsCoveredByMemberSubscription(meetingGroups);\n\n            foreach (var meetingGroup in meetingGroupsCoveredByMemberSubscription)\n            {\n                await _commandsScheduler.EnqueueAsync(new SetMeetingGroupExpirationDateCommand(\n                    Guid.NewGuid(),\n                    meetingGroup.Value,\n                    notification.DomainEvent.ExpirationDate));\n            }\n        }\n\n        private class MeetingGroupMemberResponse\n        {\n            public Guid MeetingGroupId { get; set; }\n\n            public string RoleCode { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/MemberSubscriptions/SubscriptionExpirationDateChangedIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions.ChangeSubscriptionExpirationDateForMember;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions\n{\n    public class SubscriptionExpirationDateChangedIntegrationEventHandler : INotificationHandler<SubscriptionExpirationDateChangedIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public SubscriptionExpirationDateChangedIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(SubscriptionExpirationDateChangedIntegrationEvent @event, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new ChangeSubscriptionExpirationDateForMemberCommand(\n                Guid.NewGuid(),\n                new MemberId(@event.PayerId),\n                @event.ExpirationDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/CreateMember/CreateMemberCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember\n{\n    public class CreateMemberCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public CreateMemberCommand(\n            Guid id,\n            Guid memberId,\n            string login,\n            string email,\n            string firstName,\n            string lastName,\n            string name)\n            : base(id)\n        {\n            Login = login;\n            MemberId = memberId;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n        }\n\n        internal Guid MemberId { get; }\n\n        internal string Login { get; }\n\n        internal string Email { get; }\n\n        internal string FirstName { get; }\n\n        internal string LastName { get; }\n\n        internal string Name { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/CreateMember/CreateMemberCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember\r\n{\r\n    internal class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>\r\n    {\r\n        private readonly IMemberRepository _memberRepository;\r\n\r\n        public CreateMemberCommandHandler(IMemberRepository memberRepository)\r\n        {\r\n            _memberRepository = memberRepository;\r\n        }\r\n\r\n        public async Task Handle(CreateMemberCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var member = Member.Create(request.MemberId, request.Login, request.Email, request.FirstName, request.LastName, request.Name);\r\n\r\n            await _memberRepository.AddAsync(member);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/CreateMember/MemberCratedNotificationHandler.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember\n{\n    public class MemberCratedNotificationHandler : INotificationHandler<MemberCreatedNotification>\n    {\n        public Task Handle(MemberCreatedNotification notification, CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/CreateMember/MemberCreatedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember\n{\n    public class MemberCreatedNotification : DomainNotificationBase<MeetingCreatedDomainEvent>\n    {\n        [JsonConstructor]\n        public MemberCreatedNotification(MeetingCreatedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/CreateMember/NewUserRegisteredIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember\n{\n    public class NewUserRegisteredIntegrationEventHandler : INotificationHandler<NewUserRegisteredIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public NewUserRegisteredIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(NewUserRegisteredIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new\n                CreateMemberCommand(\n                    Guid.NewGuid(),\n                    notification.UserId,\n                    notification.Login,\n                    notification.Email,\n                    notification.FirstName,\n                    notification.LastName,\n                    notification.Name));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/MemberContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members\n{\n    public class MemberContext : IMemberContext\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public MemberContext(IExecutionContextAccessor executionContextAccessor)\n        {\n            this._executionContextAccessor = executionContextAccessor;\n        }\n\n        public MemberId MemberId => new MemberId(_executionContextAccessor.UserId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/MemberDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Application.Members\n{\n    public class MemberDto\n    {\n        public Guid Id { get; set; }\n\n        public string Name { get; set; }\n\n        public string Email { get; set; }\n\n        public string Login { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Application/Members/MembersQueryHelper.cs",
    "content": "﻿using System.Data;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\r\nusing Dapper;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Application.Members\r\n{\r\n    public class MembersQueryHelper\r\n    {\r\n        public static async Task<MemberDto> GetMember(MemberId memberId, IDbConnection connection)\r\n        {\r\n            const string sql = $\"\"\"\r\n                                SELECT \r\n                                    [Member].Id as [{nameof(MemberDto.Id)}], \r\n                                    [Member].[Name] as [{nameof(MemberDto.Name)}], \r\n                                    [Member].[Login] as [{nameof(MemberDto.Login)}], \r\n                                    [Member].[Email] as [{nameof(MemberDto.Email)}] \r\n                                FROM [meetings].[v_Members] AS [Member] \r\n                                WHERE [Member].[Id] = @Id\r\n                                \"\"\";\r\n            return await connection.QuerySingleAsync<MemberDto>(\r\n                sql,\r\n                new\r\n                {\r\n                    Id = memberId.Value\r\n                });\r\n        }\r\n\r\n        public static async Task<MeetingGroupMemberData> GetMeetingGroupMember(MemberId memberId, MeetingId meetingOfGroupId, IDbConnection connection)\r\n        {\r\n            const string sql = $\"\"\"\r\n                               SELECT\r\n                                   [MeetingGroupMember].{nameof(MeetingGroupMemberResponse.MeetingGroupId)},\r\n                                   [MeetingGroupMember].{nameof(MeetingGroupMemberResponse.MemberId)}\r\n                               FROM [meetings].[v_MeetingGroupMembers] AS [MeetingGroupMember]\r\n                                    INNER JOIN [meetings].[Meetings] AS [Meeting]\r\n                                            ON [Meeting].[MeetingGroupId] = [MeetingGroupMember].[MeetingGroupId]\r\n                               WHERE [MeetingGroupMember].[MemberId] = @MemberId\r\n                                     AND [Meeting].[Id] = @MeetingId\r\n                               \"\"\";\r\n            var result = await connection.QuerySingleAsync<MeetingGroupMemberResponse>(\r\n                sql,\r\n                new\r\n                {\r\n                    MemberId = memberId.Value,\r\n                    MeetingId = meetingOfGroupId.Value\r\n                });\r\n\r\n            return new MeetingGroupMemberData(\r\n                new MeetingGroupId(result.MeetingGroupId),\r\n                new MemberId(result.MemberId));\r\n        }\r\n\r\n        private class MeetingGroupMemberResponse\r\n        {\r\n            public Guid MeetingGroupId { get; set; }\r\n\r\n            public Guid MemberId { get; set; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/CompanyName.MyMeetings.Modules.Meetings.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/Events/MeetingCommentingConfigurationCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\n{\n    public class MeetingCommentingConfigurationCreatedDomainEvent : DomainEventBase\n    {\n        public MeetingId MeetingId { get; }\n\n        public bool IsEnabled { get; }\n\n        public MeetingCommentingConfigurationCreatedDomainEvent(MeetingId meetingId, bool isEnabled)\n        {\n            MeetingId = meetingId;\n            IsEnabled = isEnabled;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/Events/MeetingCommentingDisabledDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\n{\n    public class MeetingCommentingDisabledDomainEvent : DomainEventBase\n    {\n        public MeetingId MeetingId { get; }\n\n        public MeetingCommentingDisabledDomainEvent(MeetingId meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/Events/MeetingCommentingEnabledDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events\n{\n    public class MeetingCommentingEnabledDomainEvent : DomainEventBase\n    {\n        public MeetingId MeetingId { get; }\n\n        public MeetingCommentingEnabledDomainEvent(MeetingId meetingId)\n        {\n            MeetingId = meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/IMeetingCommentingConfigurationRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\n{\n    public interface IMeetingCommentingConfigurationRepository\n    {\n        Task AddAsync(MeetingCommentingConfiguration meetingCommentingConfiguration);\n\n        Task<MeetingCommentingConfiguration> GetByMeetingIdAsync(MeetingId meetingId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/MeetingCommentingConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\n{\n    public class MeetingCommentingConfiguration : Entity, IAggregateRoot\n    {\n        public MeetingCommentingConfigurationId Id { get; }\n\n        private MeetingId _meetingId;\n\n        private bool _isCommentingEnabled;\n\n        private MeetingCommentingConfiguration(MeetingId meetingId)\n        {\n            this.Id = new MeetingCommentingConfigurationId(Guid.NewGuid());\n            this._meetingId = meetingId;\n            this._isCommentingEnabled = true;\n\n            this.AddDomainEvent(new MeetingCommentingConfigurationCreatedDomainEvent(this._meetingId, this._isCommentingEnabled));\n        }\n\n        private MeetingCommentingConfiguration()\n        {\n            // Only for EF.\n        }\n\n        public void EnableCommenting(MemberId enablingMemberId, MeetingGroup meetingGroup)\n        {\n            CheckRule(new MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule(enablingMemberId, meetingGroup));\n\n            if (!this._isCommentingEnabled)\n            {\n                this._isCommentingEnabled = true;\n                AddDomainEvent(new MeetingCommentingEnabledDomainEvent(this._meetingId));\n            }\n        }\n\n        public void DisableCommenting(MemberId disablingMemberId, MeetingGroup meetingGroup)\n        {\n            CheckRule(new MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule(disablingMemberId, meetingGroup));\n\n            if (this._isCommentingEnabled)\n            {\n                this._isCommentingEnabled = false;\n                AddDomainEvent(new MeetingCommentingDisabledDomainEvent(this._meetingId));\n            }\n        }\n\n        public bool GetIsCommentingEnabled() => _isCommentingEnabled;\n\n        internal static MeetingCommentingConfiguration Create(MeetingId meetingId)\n            => new MeetingCommentingConfiguration(meetingId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/MeetingCommentingConfigurationId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations\n{\n    public class MeetingCommentingConfigurationId : TypedIdValueBase\n    {\n        public MeetingCommentingConfigurationId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/Rules/MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules\n{\n    public class MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n        private readonly MemberId _disablingMemberId;\n\n        public MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule(MemberId disablingMemberId, MeetingGroup meetingGroup)\n        {\n            _meetingGroup = meetingGroup;\n            _disablingMemberId = disablingMemberId;\n        }\n\n        public bool IsBroken() => !_meetingGroup.IsOrganizer(_disablingMemberId);\n\n        public string Message => \"Commenting for meeting can be disabled only by group organizer\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingCommentingConfigurations/Rules/MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules\n{\n    public class MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n        private readonly MemberId _enablingMemberId;\n\n        public MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule(MemberId enablingMemberId, MeetingGroup meetingGroup)\n        {\n            _meetingGroup = meetingGroup;\n            _enablingMemberId = enablingMemberId;\n        }\n\n        public bool IsBroken() => !_meetingGroup.IsOrganizer(_enablingMemberId);\n\n        public string Message => \"Commenting for meeting can be enabled only by group organizer\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Events/MeetingCommentAddedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events\n{\n    public class MeetingCommentAddedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public MeetingId MeetingId { get; }\n\n        public string Comment { get; }\n\n        public MeetingCommentAddedDomainEvent(MeetingCommentId meetingCommentId, MeetingId meetingId, string comment)\n        {\n            MeetingCommentId = meetingCommentId;\n            MeetingId = meetingId;\n            Comment = comment;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Events/MeetingCommentEditedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events\n{\n    public class MeetingCommentEditedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public string EditedComment { get; }\n\n        public MeetingCommentEditedDomainEvent(MeetingCommentId meetingCommentId, string editedComment)\n        {\n            MeetingCommentId = meetingCommentId;\n            EditedComment = editedComment;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Events/MeetingCommentRemovedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events\n{\n    public class MeetingCommentRemovedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public MeetingCommentRemovedDomainEvent(MeetingCommentId meetingCommentId)\n        {\n            MeetingCommentId = meetingCommentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Events/ReplyToMeetingCommentAddedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events\n{\n    public class ReplyToMeetingCommentAddedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public MeetingCommentId InReplyToCommentId { get; }\n\n        public string Reply { get; }\n\n        public ReplyToMeetingCommentAddedDomainEvent(MeetingCommentId meetingCommentId, MeetingCommentId inReplyToCommentId, string reply)\n        {\n            MeetingCommentId = meetingCommentId;\n            InReplyToCommentId = inReplyToCommentId;\n            Reply = reply;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/IMeetingCommentRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments\n{\n    public interface IMeetingCommentRepository\n    {\n        Task AddAsync(MeetingComment meetingComment);\n\n        Task<MeetingComment> GetByIdAsync(MeetingCommentId meetingCommentId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/MeetingComment.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\n#nullable enable\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments\n{\n    public class MeetingComment : Entity, IAggregateRoot\n    {\n        public MeetingCommentId Id { get; }\n\n        private MeetingId _meetingId;\n\n        private MemberId _authorId;\n\n        private MeetingCommentId? _inReplyToCommentId;\n\n        private string _comment;\n\n        private DateTime _createDate;\n\n        private DateTime? _editDate;\n\n#pragma warning disable CS0414 // Field is assigned but its value is never used\n        private bool _isRemoved;\n#pragma warning restore CS0414 // Field is assigned but its value is never used\n\n        private string _removedByReason;\n\n        private MeetingComment(\n            MeetingId meetingId,\n            MemberId authorId,\n            string comment,\n            MeetingCommentId? inReplyToCommentId,\n            MeetingCommentingConfiguration meetingCommentingConfiguration,\n            MeetingGroup meetingGroup)\n        {\n            this.CheckRule(new CommentTextMustBeProvidedRule(comment));\n            this.CheckRule(new CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule(meetingCommentingConfiguration));\n            this.CheckRule(new CommentCanBeAddedOnlyByMeetingGroupMemberRule(authorId, meetingGroup));\n\n            this.Id = new MeetingCommentId(Guid.NewGuid());\n            _meetingId = meetingId;\n            _authorId = authorId;\n            _comment = comment;\n\n            _inReplyToCommentId = inReplyToCommentId;\n\n            _createDate = SystemClock.Now;\n            _editDate = null;\n\n            _isRemoved = false;\n            _removedByReason = string.Empty;\n\n            if (inReplyToCommentId == null)\n            {\n                this.AddDomainEvent(new MeetingCommentAddedDomainEvent(this.Id, _meetingId, comment));\n            }\n            else\n            {\n                this.AddDomainEvent(new ReplyToMeetingCommentAddedDomainEvent(this.Id, inReplyToCommentId, comment));\n            }\n        }\n\n#pragma warning disable CS8618\n        private MeetingComment()\n#pragma warning restore CS8618\n        {\n            // Only for EF.\n        }\n\n        public void Edit(MemberId editorId, string editedComment, MeetingCommentingConfiguration meetingCommentingConfiguration)\n        {\n            this.CheckRule(new CommentTextMustBeProvidedRule(editedComment));\n            this.CheckRule(new MeetingCommentCanBeEditedOnlyByAuthorRule(this._authorId, editorId));\n            this.CheckRule(new CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule(meetingCommentingConfiguration));\n\n            _comment = editedComment;\n            _editDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MeetingCommentEditedDomainEvent(this.Id, editedComment));\n        }\n\n        public void Remove(MemberId removingMemberId, MeetingGroup meetingGroup, string reason = \"\")\n        {\n            this.CheckRule(new MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule(meetingGroup, this._authorId, removingMemberId));\n            this.CheckRule(new RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule(meetingGroup, removingMemberId, reason));\n\n            _isRemoved = true;\n            _removedByReason = reason ?? string.Empty;\n\n            this.AddDomainEvent(new MeetingCommentRemovedDomainEvent(this.Id));\n        }\n\n        public MeetingComment Reply(MemberId replierId, string reply, MeetingGroup meetingGroup, MeetingCommentingConfiguration meetingCommentingConfiguration)\n            => new MeetingComment(\n                _meetingId,\n                replierId,\n                reply,\n                this.Id,\n                meetingCommentingConfiguration,\n                meetingGroup);\n\n        public MeetingMemberCommentLike Like(\n            MemberId likerId,\n            MeetingGroupMemberData likerMeetingGroupMember,\n            int meetingMemberCommentLikesCount)\n        {\n            this.CheckRule(new CommentCanBeLikedOnlyByMeetingGroupMemberRule(likerMeetingGroupMember));\n            this.CheckRule(new CommentCannotBeLikedByTheSameMemberMoreThanOnceRule(meetingMemberCommentLikesCount));\n\n            return MeetingMemberCommentLike.Create(this.Id, likerId);\n        }\n\n        public MeetingId GetMeetingId() => this._meetingId;\n\n        internal static MeetingComment Create(\n            MeetingId meetingId,\n            MemberId authorId,\n            string comment,\n            MeetingGroup meetingGroup,\n            MeetingCommentingConfiguration meetingCommentingConfiguration)\n            => new MeetingComment(\n                meetingId,\n                authorId,\n                comment,\n                inReplyToCommentId: null,\n                meetingCommentingConfiguration,\n                meetingGroup);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/MeetingCommentId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments\n{\n    public class MeetingCommentId : TypedIdValueBase\n    {\n        public MeetingCommentId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentCanBeAddedOnlyByMeetingGroupMemberRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentCanBeAddedOnlyByMeetingGroupMemberRule : IBusinessRule\n    {\n        private readonly MemberId _authorId;\n        private readonly MeetingGroup _meetingGroup;\n\n        public CommentCanBeAddedOnlyByMeetingGroupMemberRule(MemberId authorId, MeetingGroup meetingGroup)\n        {\n            _authorId = authorId;\n            _meetingGroup = meetingGroup;\n        }\n\n        public bool IsBroken() => !_meetingGroup.IsMemberOfGroup(_authorId);\n\n        public string Message => \"Only meeting attendee can add comments\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule : IBusinessRule\n    {\n        private readonly MeetingCommentingConfiguration _meetingCommentingConfiguration;\n\n        public CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule(MeetingCommentingConfiguration meetingCommentingConfiguration)\n        {\n            _meetingCommentingConfiguration = meetingCommentingConfiguration;\n        }\n\n        public bool IsBroken() => !_meetingCommentingConfiguration.GetIsCommentingEnabled();\n\n        public string Message => \"Commenting for meeting is disabled.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule : IBusinessRule\n    {\n        private readonly MeetingCommentingConfiguration _meetingCommentingConfiguration;\n\n        public CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule(MeetingCommentingConfiguration meetingCommentingConfiguration)\n        {\n            _meetingCommentingConfiguration = meetingCommentingConfiguration;\n        }\n\n        public bool IsBroken() => !_meetingCommentingConfiguration.GetIsCommentingEnabled();\n\n        public string Message => \"Commenting for meeting is disabled.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentCanBeLikedOnlyByMeetingGroupMemberRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentCanBeLikedOnlyByMeetingGroupMemberRule : IBusinessRule\n    {\n        private readonly MeetingGroupMemberData _likerMeetingGroupMember;\n\n        #nullable enable\n        public CommentCanBeLikedOnlyByMeetingGroupMemberRule(MeetingGroupMemberData? likerMeetingGroupMember)\n        {\n            _likerMeetingGroupMember = likerMeetingGroupMember;\n        }\n\n        public bool IsBroken() => _likerMeetingGroupMember == null;\n\n        public string Message => \"Comment can be liked only by meeting group member.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentCannotBeLikedByTheSameMemberMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentCannotBeLikedByTheSameMemberMoreThanOnceRule : IBusinessRule\n    {\n        private readonly int _memberCommentLikesCount;\n\n        public CommentCannotBeLikedByTheSameMemberMoreThanOnceRule(int memberCommentLikesCount)\n        {\n            _memberCommentLikesCount = memberCommentLikesCount;\n        }\n\n        public bool IsBroken() => _memberCommentLikesCount > 0;\n\n        public string Message => \"Member cannot like one comment more than once.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/CommentTextMustBeProvidedRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class CommentTextMustBeProvidedRule : IBusinessRule\n    {\n        private readonly string _comment;\n\n        public CommentTextMustBeProvidedRule(string comment)\n        {\n            _comment = comment;\n        }\n\n        public bool IsBroken() => string.IsNullOrEmpty(_comment);\n\n        public string Message => \"Comment text must be provided.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/MeetingCommentCanBeEditedOnlyByAuthorRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class MeetingCommentCanBeEditedOnlyByAuthorRule : IBusinessRule\n    {\n        private readonly MemberId _authorId;\n        private readonly MemberId _editorId;\n\n        public MeetingCommentCanBeEditedOnlyByAuthorRule(MemberId authorId, MemberId editorId)\n        {\n            _authorId = authorId;\n            _editorId = editorId;\n        }\n\n        public bool IsBroken() => _editorId != _authorId;\n\n        public string Message => \"Only the author of a comment can edit it.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n        private readonly MemberId _authorId;\n        private readonly MemberId _removingMemberId;\n\n        public MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule(MeetingGroup meetingGroup, MemberId authorId, MemberId removingMemberId)\n        {\n            _meetingGroup = meetingGroup;\n            _authorId = authorId;\n            _removingMemberId = removingMemberId;\n        }\n\n        public bool IsBroken() => _removingMemberId != _authorId && !_meetingGroup.IsOrganizer(_removingMemberId);\n\n        public string Message => \"Only author of comment or group organizer can remove meeting comment.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingComments/Rules/RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules\n{\n    public class RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n        private readonly MemberId _removingMemberId;\n        private readonly string _removingReason;\n\n        public RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule(MeetingGroup meetingGroup, MemberId removingMemberId, string removingReason)\n        {\n            _meetingGroup = meetingGroup;\n            _removingMemberId = removingMemberId;\n            _removingReason = removingReason;\n        }\n\n        public bool IsBroken() =>\n            !string.IsNullOrEmpty(_removingReason) && !_meetingGroup.IsOrganizer(_removingMemberId);\n\n        public string Message => \"Only group organizer can provide comment's removing reason.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/Events/MeetingGroupProposalAcceptedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events\n{\n    public class MeetingGroupProposalAcceptedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\n\n        public MeetingGroupProposalAcceptedDomainEvent(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            MeetingGroupProposalId = meetingGroupProposalId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/Events/MeetingGroupProposedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events\n{\n    public class MeetingGroupProposedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupProposedDomainEvent(\n            MeetingGroupProposalId meetingGroupProposalId,\n            string name,\n            string description,\n            MemberId proposalUserId,\n            DateTime proposalDate,\n            string locationCity,\n            string locationCountryCode)\n        {\n            this.MeetingGroupProposalId = meetingGroupProposalId;\n            this.Name = name;\n            this.Description = description;\n            this.LocationCity = locationCity;\n            this.LocationCountryCode = locationCountryCode;\n            this.ProposalDate = proposalDate;\n            this.ProposalUserId = proposalUserId;\n        }\n\n        public MeetingGroupProposalId MeetingGroupProposalId { get; }\n\n        public string Name { get; }\n\n        public string Description { get; }\n\n        public string LocationCity { get; }\n\n        public string LocationCountryCode { get; }\n\n        public MemberId ProposalUserId { get; }\n\n        public DateTime ProposalDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/IMeetingGroupProposalRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\n{\n    public interface IMeetingGroupProposalRepository\n    {\n        Task AddAsync(MeetingGroupProposal meetingGroupProposal);\n\n        Task<MeetingGroupProposal> GetByIdAsync(MeetingGroupProposalId meetingGroupProposalId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/MeetingGroupProposal.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposal : Entity, IAggregateRoot\n    {\n        public MeetingGroupProposalId Id { get; private set; }\n\n        private string _name;\n\n        private string _description;\n\n        private MeetingGroupLocation _location;\n\n        private DateTime _proposalDate;\n\n        private MemberId _proposalUserId;\n\n        private MeetingGroupProposalStatus _status;\n\n        public MeetingGroup CreateMeetingGroup()\n        {\n            return MeetingGroup.CreateBasedOnProposal(this.Id, _name, _description, _location, _proposalUserId);\n        }\n\n        private MeetingGroupProposal()\n        {\n            // Only for EF.\n        }\n\n        private MeetingGroupProposal(\n            string name,\n            string description,\n            MeetingGroupLocation location,\n            MemberId proposalUserId)\n        {\n            Id = new MeetingGroupProposalId(Guid.NewGuid());\n            _name = name;\n            _description = description;\n            _location = location;\n            _proposalUserId = proposalUserId;\n            _proposalDate = SystemClock.Now;\n            _status = MeetingGroupProposalStatus.InVerification;\n\n            this.AddDomainEvent(new MeetingGroupProposedDomainEvent(this.Id, _name, _description, proposalUserId, _proposalDate, _location.City, _location.CountryCode));\n        }\n\n        public static MeetingGroupProposal ProposeNew(\n            string name,\n            string description,\n            MeetingGroupLocation location,\n            MemberId proposalMemberId)\n        {\n            return new MeetingGroupProposal(name, description, location, proposalMemberId);\n        }\n\n        public void Accept()\n        {\n            this.CheckRule(new MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule(_status));\n\n            _status = MeetingGroupProposalStatus.Accepted;\n\n            this.AddDomainEvent(new MeetingGroupProposalAcceptedDomainEvent(this.Id));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/MeetingGroupProposalId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposalId : TypedIdValueBase\n    {\n        public MeetingGroupProposalId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/MeetingGroupProposalStatus.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals\n{\n    public class MeetingGroupProposalStatus : ValueObject\n    {\n        public string Value { get; }\n\n        internal static MeetingGroupProposalStatus InVerification => new MeetingGroupProposalStatus(\"InVerification\");\n\n        internal static MeetingGroupProposalStatus Accepted => new MeetingGroupProposalStatus(\"Accepted\");\n\n        internal bool IsAccepted => Value == \"Accepted\";\n\n        private MeetingGroupProposalStatus(string value)\n        {\n            Value = value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroupProposals/Rules/MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Rules\n{\n    public class MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule : IBusinessRule\n    {\n        private readonly MeetingGroupProposalStatus _actualStatus;\n\n        internal MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule(MeetingGroupProposalStatus actualStatus)\n        {\n            _actualStatus = actualStatus;\n        }\n\n        public bool IsBroken() => _actualStatus.IsAccepted;\n\n        public string Message => \"Meeting group proposal cannot be accepted more than once rule\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingAttendeeChangedDecisionDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingAttendeeChangedDecisionDomainEvent : DomainEventBase\n    {\n        public MeetingAttendeeChangedDecisionDomainEvent(MemberId memberId, MeetingId meetingId)\n        {\n            MemberId = memberId;\n            MeetingId = meetingId;\n        }\n\n        public MemberId MemberId { get; }\n\n        public MeetingId MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingGroupCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingGroupCreatedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public MemberId CreatorId { get; }\n\n        public MeetingGroupCreatedDomainEvent(MeetingGroupId meetingGroupId, MemberId creatorId)\n        {\n            this.MeetingGroupId = meetingGroupId;\n            this.CreatorId = creatorId;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingGroupGeneralAttributesEditedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingGroupGeneralAttributesEditedDomainEvent : DomainEventBase\n    {\n        public string NewName { get; }\n\n        public string NewDescription { get; }\n\n        public MeetingGroupLocation NewLocation { get; }\n\n        public MeetingGroupGeneralAttributesEditedDomainEvent(string newName, string newDescription, MeetingGroupLocation newLocation)\n        {\n            this.NewName = newName;\n            this.NewDescription = newDescription;\n            this.NewLocation = newLocation;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingGroupMemberLeftGroupDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingGroupMemberLeftGroupDomainEvent : DomainEventBase\n    {\n        public MeetingGroupMemberLeftGroupDomainEvent(MeetingGroupId meetingGroupId, MemberId memberId)\n        {\n            MeetingGroupId = meetingGroupId;\n            MemberId = memberId;\n        }\n\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public MemberId MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingGroupPaymentInfoUpdatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingGroupPaymentInfoUpdatedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupPaymentInfoUpdatedDomainEvent(MeetingGroupId meetingGroupId, DateTime paymentDateTo)\n        {\n            MeetingGroupId = meetingGroupId;\n            PaymentDateTo = paymentDateTo;\n        }\n\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public DateTime PaymentDateTo { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/MeetingNotAttendeeChangedDecisionDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class MeetingNotAttendeeChangedDecisionDomainEvent : DomainEventBase\n    {\n        public MeetingNotAttendeeChangedDecisionDomainEvent(MemberId memberId, MeetingId meetingId)\n        {\n            MemberId = memberId;\n            MeetingId = meetingId;\n        }\n\n        public MemberId MemberId { get; }\n\n        public MeetingId MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Events/NewMeetingGroupMemberJoinedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events\n{\n    public class NewMeetingGroupMemberJoinedDomainEvent : DomainEventBase\n    {\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public MemberId MemberId { get; }\n\n        public MeetingGroupMemberRole Role { get; }\n\n        public NewMeetingGroupMemberJoinedDomainEvent(MeetingGroupId meetingGroupId, MemberId memberId, MeetingGroupMemberRole role)\n        {\n            this.MeetingGroupId = meetingGroupId;\n            this.MemberId = memberId;\n            this.Role = role;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/IMeetingGroupRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public interface IMeetingGroupRepository\n    {\n        Task AddAsync(MeetingGroup meetingGroup);\n\n        Task<int> Commit();\n\n        Task<MeetingGroup> GetByIdAsync(MeetingGroupId id);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/MeetingGroup.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public class MeetingGroup : Entity, IAggregateRoot\n    {\n        public MeetingGroupId Id { get; private set; }\n\n        private string _name;\n\n        private string _description;\n\n        private MeetingGroupLocation _location;\n\n        private MemberId _creatorId;\n\n        private List<MeetingGroupMember> _members;\n\n        private DateTime _createDate;\n\n        private DateTime? _paymentDateTo;\n\n        internal static MeetingGroup CreateBasedOnProposal(\n            MeetingGroupProposalId meetingGroupProposalId,\n            string name,\n            string description,\n            MeetingGroupLocation location,\n            MemberId creatorId)\n        {\n            return new MeetingGroup(meetingGroupProposalId, name, description, location, creatorId);\n        }\n\n        private MeetingGroup()\n        {\n            // Only for EF.\n        }\n\n        private MeetingGroup(MeetingGroupProposalId meetingGroupProposalId, string name, string description, MeetingGroupLocation location, MemberId creatorId)\n        {\n            this.Id = new MeetingGroupId(meetingGroupProposalId.Value);\n            this._name = name;\n            this._description = description;\n            this._creatorId = creatorId;\n            this._location = location;\n            this._createDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MeetingGroupCreatedDomainEvent(this.Id, creatorId));\n\n            this._members = [MeetingGroupMember.CreateNew(this.Id, this._creatorId, MeetingGroupMemberRole.Organizer)];\n        }\n\n        public void EditGeneralAttributes(string name, string description, MeetingGroupLocation location)\n        {\n            this._name = name;\n            this._description = description;\n            this._location = location;\n\n            this.AddDomainEvent(new MeetingGroupGeneralAttributesEditedDomainEvent(this._name, this._description, this._location));\n        }\n\n        public void JoinToGroupMember(MemberId memberId)\n        {\n            this.CheckRule(new MeetingGroupMemberCannotBeAddedTwiceRule(_members, memberId));\n\n            this._members.Add(MeetingGroupMember.CreateNew(this.Id, memberId, MeetingGroupMemberRole.Member));\n        }\n\n        public void LeaveGroup(MemberId memberId)\n        {\n            this.CheckRule(new NotActualGroupMemberCannotLeaveGroupRule(_members, memberId));\n\n            var member = this._members.Single(x => x.IsMember(memberId));\n\n            member.Leave();\n        }\n\n        public void SetExpirationDate(DateTime dateTo)\n        {\n            _paymentDateTo = dateTo;\n\n            this.AddDomainEvent(new MeetingGroupPaymentInfoUpdatedDomainEvent(this.Id, _paymentDateTo.Value));\n        }\n\n        public Meeting CreateMeeting(\n            string title,\n            MeetingTerm term,\n            string description,\n            MeetingLocation location,\n            int? attendeesLimit,\n            int guestsLimit,\n            Term rsvpTerm,\n            MoneyValue eventFee,\n            List<MemberId> hostsMembersIds,\n            MemberId creatorId)\n        {\n            this.CheckRule(new MeetingCanBeOrganizedOnlyByPayedGroupRule(_paymentDateTo));\n\n            this.CheckRule(new MeetingHostMustBeAMeetingGroupMemberRule(creatorId, hostsMembersIds, _members));\n\n            return Meeting.CreateNew(\n                this.Id,\n                title,\n                term,\n                description,\n                location,\n                MeetingLimits.Create(attendeesLimit, guestsLimit),\n                rsvpTerm,\n                eventFee,\n                hostsMembersIds,\n                creatorId);\n        }\n\n        internal bool IsMemberOfGroup(MemberId attendeeId)\n        {\n            return _members.Any(x => x.IsMember(attendeeId));\n        }\n\n        internal bool IsOrganizer(MemberId memberId)\n        {\n            return _members.Any(x => x.IsOrganizer(memberId));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/MeetingGroupId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public class MeetingGroupId : TypedIdValueBase\n    {\n        public MeetingGroupId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/MeetingGroupLocation.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public class MeetingGroupLocation : ValueObject\n    {\n        public static MeetingGroupLocation CreateNew(string city, string countryCode)\n        {\n            return new MeetingGroupLocation(city, countryCode);\n        }\n\n        public string City { get; }\n\n        public string CountryCode { get; }\n\n        private MeetingGroupLocation(string city, string countryCode)\n        {\n            City = city;\n            CountryCode = countryCode;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/MeetingGroupMember.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public class MeetingGroupMember : Entity\n    {\n        internal MeetingGroupId MeetingGroupId { get; private set; }\n\n        internal MemberId MemberId { get; private set; }\n\n        private MeetingGroupMemberRole _role;\n\n        internal DateTime JoinedDate { get; private set; }\n\n        private bool _isActive;\n\n        private DateTime? _leaveDate;\n\n        private MeetingGroupMember()\n        {\n            // Only for EF.\n        }\n\n        private MeetingGroupMember(\n            MeetingGroupId meetingGroupId,\n            MemberId memberId,\n            MeetingGroupMemberRole role)\n        {\n            this.MeetingGroupId = meetingGroupId;\n            this.MemberId = memberId;\n            this._role = role;\n            this.JoinedDate = SystemClock.Now;\n            this._isActive = true;\n\n            this.AddDomainEvent(new NewMeetingGroupMemberJoinedDomainEvent(this.MeetingGroupId, this.MemberId, this._role));\n        }\n\n        internal static MeetingGroupMember CreateNew(\n            MeetingGroupId meetingGroupId,\n            MemberId memberId,\n            MeetingGroupMemberRole role)\n        {\n            return new MeetingGroupMember(meetingGroupId, memberId, role);\n        }\n\n        internal void Leave()\n        {\n            _isActive = false;\n            _leaveDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MeetingGroupMemberLeftGroupDomainEvent(this.MeetingGroupId, this.MemberId));\n        }\n\n        internal bool IsMember(MemberId memberId)\n        {\n            return this._isActive && this.MemberId == memberId;\n        }\n\n        internal bool IsOrganizer(MemberId memberId)\n        {\n            return this.IsMember(memberId) && _role == MeetingGroupMemberRole.Organizer;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/MeetingGroupMemberRole.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups\n{\n    public class MeetingGroupMemberRole : ValueObject\n    {\n        public static MeetingGroupMemberRole Organizer => new MeetingGroupMemberRole(\"Organizer\");\n\n        public static MeetingGroupMemberRole Member => new MeetingGroupMemberRole(\"Member\");\n\n        public string Value { get; }\n\n        private MeetingGroupMemberRole(string value)\n        {\n            this.Value = value;\n        }\n\n        public static MeetingGroupMemberRole Of(string roleCode)\n        {\n            return new MeetingGroupMemberRole(roleCode);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Policies/MeetingGroupExpirationDatePolicy.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Policies\n{\n    public static class MeetingGroupExpirationDatePolicy\n    {\n        public static List<MeetingGroupId> GetMeetingGroupsCoveredByMemberSubscription(\n            List<MeetingGroupMemberData> meetingGroups)\n        {\n            return meetingGroups\n                .Where(x => x.Role == MeetingGroupMemberRole.Organizer)\n                .Select(x => x.MeetingGroupId)\n                .ToList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Policies/MeetingGroupMemberData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Policies\n{\n    public class MeetingGroupMemberData\n    {\n        public MeetingGroupMemberData(MeetingGroupId meetingGroupId, MeetingGroupMemberRole role)\n        {\n            MeetingGroupId = meetingGroupId;\n            Role = role;\n        }\n\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public MeetingGroupMemberRole Role { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Rules/MeetingCanBeOrganizedOnlyByPayedGroupRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\n{\n    public class MeetingCanBeOrganizedOnlyByPayedGroupRule : IBusinessRule\n    {\n        private readonly DateTime? _paymentDateTo;\n\n        internal MeetingCanBeOrganizedOnlyByPayedGroupRule(DateTime? paymentDateTo)\n        {\n            _paymentDateTo = paymentDateTo;\n        }\n\n        public bool IsBroken() => !_paymentDateTo.HasValue || _paymentDateTo < SystemClock.Now;\n\n        public string Message => \"Meeting can be organized only by payed group\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Rules/MeetingGroupMemberCannotBeAddedTwiceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\n{\n    public class MeetingGroupMemberCannotBeAddedTwiceRule : IBusinessRule\n    {\n        private readonly List<MeetingGroupMember> _members;\n\n        private readonly MemberId _memberId;\n\n        public MeetingGroupMemberCannotBeAddedTwiceRule(List<MeetingGroupMember> members, MemberId memberId)\n            : base()\n        {\n            _members = members;\n            _memberId = memberId;\n        }\n\n        public bool IsBroken() => this._members.SingleOrDefault(x => x.IsMember(_memberId)) != null;\n\n        public string Message => \"Member cannot be added twice to the same group\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Rules/MeetingHostMustBeAMeetingGroupMemberRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\n{\n    public class MeetingHostMustBeAMeetingGroupMemberRule : IBusinessRule\n    {\n        private readonly MemberId _creatorId;\n\n        private readonly List<MemberId> _hostsMembersIds;\n\n        private readonly List<MeetingGroupMember> _members;\n\n        public MeetingHostMustBeAMeetingGroupMemberRule(\n            MemberId creatorId,\n            List<MemberId> hostsMembersIds,\n            List<MeetingGroupMember> members)\n        {\n            _creatorId = creatorId;\n            _hostsMembersIds = hostsMembersIds;\n            _members = members;\n        }\n\n        public bool IsBroken()\n        {\n            var memberIds = _members.Select(x => x.MemberId).ToList();\n            if (!_hostsMembersIds.Any() && !memberIds.Contains(_creatorId))\n            {\n                return true;\n            }\n\n            return _hostsMembersIds.Any() && _hostsMembersIds.Except(memberIds).Any();\n        }\n\n        public string Message => \"Meeting host must be a meeting group member\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingGroups/Rules/NotActualGroupMemberCannotLeaveGroupRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules\n{\n    public class NotActualGroupMemberCannotLeaveGroupRule : IBusinessRule\n    {\n        private readonly List<MeetingGroupMember> _members;\n\n        private readonly MemberId memberId;\n\n        public NotActualGroupMemberCannotLeaveGroupRule(List<MeetingGroupMember> members, MemberId memberId)\n            : base()\n        {\n            _members = members;\n            this.memberId = memberId;\n        }\n\n        public bool IsBroken() => this._members.SingleOrDefault(x => x.IsMember(memberId)) == null;\n\n        public string Message => \"Member is not member of this group so he cannot leave it\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingMemberCommentLikes/Events/MeetingCommentLikedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events\n{\n    public class MeetingCommentLikedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public MemberId LikerId { get; }\n\n        public MeetingCommentLikedDomainEvent(MeetingCommentId meetingCommentId, MemberId likerId)\n        {\n            MeetingCommentId = meetingCommentId;\n            LikerId = likerId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingMemberCommentLikes/Events/MeetingCommentUnlikedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events\n{\n    public class MeetingCommentUnlikedDomainEvent : DomainEventBase\n    {\n        public MeetingCommentId MeetingCommentId { get; }\n\n        public MemberId LikerId { get; }\n\n        public MeetingCommentUnlikedDomainEvent(MeetingCommentId meetingCommentId, MemberId likerId)\n        {\n            MeetingCommentId = meetingCommentId;\n            LikerId = likerId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingMemberCommentLikes/IMeetingMemberCommentLikesRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\n{\n    public interface IMeetingMemberCommentLikesRepository\n    {\n        Task AddAsync(MeetingMemberCommentLike meetingMemberCommentLike);\n\n        Task<MeetingMemberCommentLike> GetAsync(MemberId memberId, MeetingCommentId meetingCommentId);\n\n        Task<int> CountMemberCommentLikesAsync(MemberId memberId, MeetingCommentId meetingCommentId);\n\n        void Remove(MeetingMemberCommentLike meetingMemberCommentLike);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingMemberCommentLikes/MeetingMemberCommentLike.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\n{\n    public class MeetingMemberCommentLike : Entity, IAggregateRoot\n    {\n        public MeetingMemberCommentLikeId Id { get; }\n\n        private MeetingCommentId _meetingCommentId;\n\n        private MemberId _memberId;\n\n        private MeetingMemberCommentLike()\n        {\n            // Only for EF.\n        }\n\n        private MeetingMemberCommentLike(MeetingCommentId meetingCommentId, MemberId memberId)\n        {\n            Id = new MeetingMemberCommentLikeId(Guid.NewGuid());\n            _meetingCommentId = meetingCommentId;\n            _memberId = memberId;\n\n            this.AddDomainEvent(new MeetingCommentLikedDomainEvent(meetingCommentId, memberId));\n        }\n\n        public void Remove()\n        {\n            this.AddDomainEvent(new MeetingCommentUnlikedDomainEvent(_meetingCommentId, _memberId));\n        }\n\n        public static MeetingMemberCommentLike Create(MeetingCommentId meetingCommentId, MemberId memberId)\n            => new MeetingMemberCommentLike(meetingCommentId, memberId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/MeetingMemberCommentLikes/MeetingMemberCommentLikeId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes\n{\n    public class MeetingMemberCommentLikeId : TypedIdValueBase\n    {\n        public MeetingMemberCommentLikeId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingAttendeeAddedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingAttendeeAddedDomainEvent : DomainEventBase\n    {\n        public MeetingAttendeeAddedDomainEvent(\n            MeetingId meetingId,\n            MemberId attendeeId,\n            DateTime rsvpDate,\n            string role,\n            int guestsNumber,\n            decimal? feeValue,\n            string feeCurrency)\n        {\n            MeetingId = meetingId;\n            AttendeeId = attendeeId;\n            RSVPDate = rsvpDate;\n            Role = role;\n            GuestsNumber = guestsNumber;\n            FeeValue = feeValue;\n            FeeCurrency = feeCurrency;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId AttendeeId { get; }\n\n        public DateTime RSVPDate { get; }\n\n        public string Role { get; }\n\n        public int GuestsNumber { get; }\n\n        public decimal? FeeValue { get; }\n\n        public string FeeCurrency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingAttendeeFeePaidDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingAttendeeFeePaidDomainEvent : DomainEventBase\n    {\n        public MeetingAttendeeFeePaidDomainEvent(MeetingId meetingId, MemberId attendeeId)\n        {\n            MeetingId = meetingId;\n            AttendeeId = attendeeId;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId AttendeeId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingAttendeeRemovedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingAttendeeRemovedDomainEvent : DomainEventBase\n    {\n        public MeetingAttendeeRemovedDomainEvent(MemberId memberId, MeetingId meetingId, string reason)\n        {\n            MemberId = memberId;\n            MeetingId = meetingId;\n            Reason = reason;\n        }\n\n        public MemberId MemberId { get; }\n\n        public MeetingId MeetingId { get; }\n\n        public string Reason { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingCanceledDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingCanceledDomainEvent : DomainEventBase\n    {\n        public MeetingCanceledDomainEvent(MeetingId meetingId, MemberId cancelMemberId, DateTime cancelDate)\n        {\n            MeetingId = meetingId;\n            CancelMemberId = cancelMemberId;\n            CancelDate = cancelDate;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId CancelMemberId { get; }\n\n        public DateTime CancelDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingCreatedDomainEvent : DomainEventBase\n    {\n        public MeetingCreatedDomainEvent(MeetingId meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public MeetingId MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingEditedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingEditedDomainEvent : DomainEventBase\n    {\n        public MeetingEditedDomainEvent(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingMainAttributesChangedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingMainAttributesChangedDomainEvent : DomainEventBase\n    {\n        public MeetingMainAttributesChangedDomainEvent(MeetingId meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public MeetingId MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingNotAttendeeAddedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingNotAttendeeAddedDomainEvent : DomainEventBase\n    {\n        public MeetingId MeetingId { get; }\n\n        public MemberId MemberId { get; }\n\n        public MeetingNotAttendeeAddedDomainEvent(MeetingId meetingId, MemberId memberId)\n        {\n            MeetingId = meetingId;\n            MemberId = memberId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MeetingWaitlistMemberAddedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MeetingWaitlistMemberAddedDomainEvent : DomainEventBase\n    {\n        public MeetingWaitlistMemberAddedDomainEvent(MeetingId meetingId, MemberId memberId)\n        {\n            MeetingId = meetingId;\n            MemberId = memberId;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MemberSetAsAttendeeDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MemberSetAsAttendeeDomainEvent : DomainEventBase\n    {\n        public MemberSetAsAttendeeDomainEvent(MeetingId meetingId, MemberId hostId)\n        {\n            MeetingId = meetingId;\n            HostId = hostId;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId HostId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/MemberSignedOffFromMeetingWaitlistDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class MemberSignedOffFromMeetingWaitlistDomainEvent : DomainEventBase\n    {\n        public MemberSignedOffFromMeetingWaitlistDomainEvent(MeetingId meetingId, MemberId memberId)\n        {\n            MeetingId = meetingId;\n            MemberId = memberId;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Events/NewMeetingHostSetDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events\n{\n    public class NewMeetingHostSetDomainEvent : DomainEventBase\n    {\n        public NewMeetingHostSetDomainEvent(MeetingId meetingId, MemberId hostId)\n        {\n            MeetingId = meetingId;\n            HostId = hostId;\n        }\n\n        public MeetingId MeetingId { get; }\n\n        public MemberId HostId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/IMeetingRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public interface IMeetingRepository\n    {\n        Task AddAsync(Meeting meeting);\n\n        Task<Meeting> GetByIdAsync(MeetingId id);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Meeting.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class Meeting : Entity, IAggregateRoot\n    {\n        private readonly MeetingGroupId _meetingGroupId;\n\n        private readonly List<MeetingAttendee> _attendees;\n\n        private readonly List<MeetingNotAttendee> _notAttendees;\n\n        private readonly List<MeetingWaitlistMember> _waitlistMembers;\n\n        public MeetingId Id { get; private set; }\n\n        private string _title;\n\n        private MeetingTerm _term;\n\n        private string _description;\n\n        private MeetingLocation _location;\n\n        private MeetingLimits _meetingLimits;\n\n        private Term _rsvpTerm;\n\n        private MoneyValue _eventFee;\n\n        private MemberId _creatorId;\n\n        private DateTime _createDate;\n\n        private MemberId _changeMemberId;\n\n        private DateTime? _changeDate;\n\n        private DateTime? _cancelDate;\n\n        private MemberId _cancelMemberId;\n\n        private bool _isCanceled;\n\n        private Meeting()\n        {\n            _attendees = [];\n            _notAttendees = [];\n            _waitlistMembers = [];\n        }\n\n        internal static Meeting CreateNew(\n            MeetingGroupId meetingGroupId,\n            string title,\n            MeetingTerm term,\n            string description,\n            MeetingLocation location,\n            MeetingLimits meetingLimits,\n            Term rsvpTerm,\n            MoneyValue eventFee,\n            List<MemberId> hostsMembersIds,\n            MemberId creatorId)\n        {\n            return new Meeting(\n                meetingGroupId,\n                title,\n                term,\n                description,\n                location,\n                meetingLimits,\n                rsvpTerm,\n                eventFee,\n                hostsMembersIds,\n                creatorId);\n        }\n\n        private Meeting(\n            MeetingGroupId meetingGroupId,\n            string title,\n            MeetingTerm term,\n            string description,\n            MeetingLocation location,\n            MeetingLimits meetingLimits,\n            Term rsvpTerm,\n            MoneyValue eventFee,\n            List<MemberId> hostsMembersIds,\n            MemberId creatorId)\n        {\n            Id = new MeetingId(Guid.NewGuid());\n            _meetingGroupId = meetingGroupId;\n            _title = title;\n            _term = term;\n            _description = description;\n            _location = location;\n            _meetingLimits = meetingLimits;\n\n            this.SetRsvpTerm(rsvpTerm, _term);\n            _eventFee = eventFee;\n            _creatorId = creatorId;\n            _createDate = SystemClock.Now;\n\n            _attendees = [];\n            _notAttendees = [];\n            _waitlistMembers = [];\n\n            this.AddDomainEvent(new MeetingCreatedDomainEvent(this.Id));\n            var rsvpDate = SystemClock.Now;\n            if (hostsMembersIds.Any())\n            {\n                foreach (var hostMemberId in hostsMembersIds)\n                {\n                    _attendees.Add(MeetingAttendee.CreateNew(this.Id, hostMemberId, rsvpDate, MeetingAttendeeRole.Host, 0, MoneyValue.Undefined));\n                }\n            }\n            else\n            {\n                _attendees.Add(MeetingAttendee.CreateNew(this.Id, creatorId, rsvpDate, MeetingAttendeeRole.Host, 0, MoneyValue.Undefined));\n            }\n        }\n\n        public void ChangeMainAttributes(\n            string title,\n            MeetingTerm term,\n            string description,\n            MeetingLocation location,\n            MeetingLimits meetingLimits,\n            Term rsvpTerm,\n            MoneyValue eventFee,\n            MemberId modifyUserId)\n        {\n            this.CheckRule(new AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule(\n                meetingLimits,\n                this.GetAllActiveAttendeesWithGuestsNumber()));\n\n            _title = title;\n            _term = term;\n            _description = description;\n            _location = location;\n            _meetingLimits = meetingLimits;\n            this.SetRsvpTerm(rsvpTerm, _term);\n            _eventFee = eventFee;\n\n            _changeDate = SystemClock.Now;\n            _changeMemberId = modifyUserId;\n\n            this.AddDomainEvent(new MeetingMainAttributesChangedDomainEvent(this.Id));\n        }\n\n        public void AddAttendee(MeetingGroup meetingGroup, MemberId attendeeId, int guestsNumber)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new AttendeeCanBeAddedOnlyInRsvpTermRule(_rsvpTerm));\n\n            this.CheckRule(new MeetingAttendeeMustBeAMemberOfGroupRule(attendeeId, meetingGroup));\n\n            this.CheckRule(new MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule(attendeeId, _attendees));\n\n            this.CheckRule(new MeetingGuestsNumberIsAboveLimitRule(_meetingLimits.GuestsLimit, guestsNumber));\n\n            this.CheckRule(new MeetingAttendeesNumberIsAboveLimitRule(_meetingLimits.AttendeesLimit, this.GetAllActiveAttendeesWithGuestsNumber(), guestsNumber));\n\n            var notAttendee = this.GetActiveNotAttendee(attendeeId);\n            notAttendee?.ChangeDecision();\n\n            _attendees.Add(MeetingAttendee.CreateNew(\n                this.Id,\n                attendeeId,\n                SystemClock.Now,\n                MeetingAttendeeRole.Attendee,\n                guestsNumber,\n                _eventFee));\n        }\n\n        public void AddNotAttendee(MemberId memberId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new MemberCannotBeNotAttendeeTwiceRule(_notAttendees, memberId));\n\n            _notAttendees.Add(MeetingNotAttendee.CreateNew(this.Id, memberId));\n\n            var attendee = this.GetActiveAttendee(memberId);\n\n            attendee?.ChangeDecision();\n\n            var nextWaitlistMember = _waitlistMembers\n                .Where(x => x.IsActive())\n                .OrderBy(x => x.SignUpDate)\n                .FirstOrDefault();\n            if (nextWaitlistMember != null)\n            {\n                _attendees.Add(MeetingAttendee.CreateNew(\n                    this.Id,\n                    nextWaitlistMember.MemberId,\n                    nextWaitlistMember.SignUpDate,\n                    MeetingAttendeeRole.Attendee,\n                    0,\n                    this._eventFee));\n                nextWaitlistMember.MarkIsMovedToAttendees();\n            }\n        }\n\n        public void ChangeNotAttendeeDecision(MemberId memberId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new NotActiveNotAttendeeCannotChangeDecisionRule(_notAttendees, memberId));\n\n            var notAttendee = _notAttendees.Single(x => x.IsActiveNotAttendee(memberId));\n\n            notAttendee.ChangeDecision();\n        }\n\n        public void SignUpMemberToWaitlist(MeetingGroup meetingGroup, MemberId memberId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new AttendeeCanBeAddedOnlyInRsvpTermRule(_rsvpTerm));\n\n            this.CheckRule(new MemberOnWaitlistMustBeAMemberOfGroupRule(meetingGroup, memberId, _attendees));\n\n            this.CheckRule(new MemberCannotBeMoreThanOnceOnMeetingWaitlistRule(_waitlistMembers, memberId));\n\n            _waitlistMembers.Add(MeetingWaitlistMember.CreateNew(this.Id, memberId));\n        }\n\n        public void SignOffMemberFromWaitlist(MemberId memberId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new NotActiveMemberOfWaitlistCannotBeSignedOffRule(_waitlistMembers, memberId));\n\n            var memberOnWaitlist = this.GetActiveMemberOnWaitlist(memberId);\n\n            memberOnWaitlist.SignOff();\n        }\n\n        public void SetHostRole(MeetingGroup meetingGroup, MemberId settingMemberId, MemberId newOrganizerId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(settingMemberId, meetingGroup, _attendees));\n\n            this.CheckRule(new OnlyMeetingAttendeeCanHaveChangedRoleRule(_attendees, newOrganizerId));\n\n            var attendee = this.GetActiveAttendee(newOrganizerId);\n\n            attendee.SetAsHost();\n        }\n\n        public void SetAttendeeRole(MeetingGroup meetingGroup, MemberId settingMemberId, MemberId newOrganizerId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            this.CheckRule(new OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(settingMemberId, meetingGroup, _attendees));\n\n            this.CheckRule(new OnlyMeetingAttendeeCanHaveChangedRoleRule(_attendees, newOrganizerId));\n\n            var attendee = this.GetActiveAttendee(newOrganizerId);\n\n            attendee.SetAsAttendee();\n\n            var meetingHostNumber = _attendees.Count(x => x.IsActiveHost());\n\n            this.CheckRule(new MeetingMustHaveAtLeastOneHostRule(meetingHostNumber));\n        }\n\n        public MeetingGroupId GetMeetingGroupId() => _meetingGroupId;\n\n        public void Cancel(MemberId cancelMemberId)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n\n            if (!_isCanceled)\n            {\n                _isCanceled = true;\n                _cancelDate = SystemClock.Now;\n                _cancelMemberId = cancelMemberId;\n\n                this.AddDomainEvent(new MeetingCanceledDomainEvent(this.Id, _cancelMemberId, _cancelDate.Value));\n            }\n        }\n\n        public void RemoveAttendee(MemberId attendeeId, MemberId removingPersonId, string reason)\n        {\n            this.CheckRule(new MeetingCannotBeChangedAfterStartRule(_term));\n            this.CheckRule(new OnlyActiveAttendeeCanBeRemovedFromMeetingRule(_attendees, attendeeId));\n\n            var attendee = this.GetActiveAttendee(attendeeId);\n\n            attendee.Remove(removingPersonId, reason);\n        }\n\n        public void MarkAttendeeFeeAsPayed(MemberId memberId)\n        {\n            var attendee = GetActiveAttendee(memberId);\n\n            attendee.MarkFeeAsPayed();\n        }\n\n        public MeetingComment AddComment(MemberId authorId, string comment, MeetingGroup meetingGroup, MeetingCommentingConfiguration meetingCommentingConfiguration)\n            => MeetingComment.Create(\n                this.Id,\n                authorId,\n                comment,\n                meetingGroup,\n                meetingCommentingConfiguration);\n\n        public MeetingCommentingConfiguration CreateCommentingConfiguration()\n        {\n            return MeetingCommentingConfiguration.Create(this.Id);\n        }\n\n        private MeetingWaitlistMember GetActiveMemberOnWaitlist(MemberId memberId)\n        {\n            return _waitlistMembers.SingleOrDefault(x => x.IsActiveOnWaitList(memberId));\n        }\n\n        private MeetingAttendee GetActiveAttendee(MemberId attendeeId)\n        {\n            return _attendees.SingleOrDefault(x => x.IsActiveAttendee(attendeeId));\n        }\n\n        private MeetingNotAttendee GetActiveNotAttendee(MemberId memberId)\n        {\n            return _notAttendees.SingleOrDefault(x => x.IsActiveNotAttendee(memberId));\n        }\n\n        private int GetAllActiveAttendeesWithGuestsNumber()\n        {\n            return _attendees.Where(x => x.IsActive()).Sum(x => x.GetAttendeeWithGuestsNumber());\n        }\n\n        private void SetRsvpTerm(Term rsvpTerm, MeetingTerm meetingTerm)\n        {\n            if (!rsvpTerm.EndDate.HasValue || rsvpTerm.EndDate > meetingTerm.StartDate)\n            {\n                _rsvpTerm = Term.CreateNewBetweenDates(rsvpTerm.StartDate, meetingTerm.StartDate);\n            }\n            else\n            {\n                _rsvpTerm = rsvpTerm;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingAttendee.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingAttendee : Entity\n    {\n        internal MemberId AttendeeId { get; private set; }\n\n        internal MeetingId MeetingId { get; private set; }\n\n        private DateTime _decisionDate;\n\n        private MeetingAttendeeRole _role;\n\n        private int _guestsNumber;\n\n        private bool _decisionChanged;\n\n        private DateTime? _decisionChangeDate;\n\n        private DateTime? _removedDate;\n\n        private MemberId _removingMemberId;\n\n        private string _removingReason;\n\n        private bool _isRemoved;\n\n        private MoneyValue _fee;\n\n#pragma warning disable CS0414 // Field is assigned but its value is never used\n        private bool _isFeePaid;\n#pragma warning restore CS0414 // Field is assigned but its value is never used\n\n        private MeetingAttendee()\n        {\n        }\n\n        internal static MeetingAttendee CreateNew(\n            MeetingId meetingId,\n            MemberId attendeeId,\n            DateTime decisionDate,\n            MeetingAttendeeRole role,\n            int guestsNumber,\n            MoneyValue eventFee)\n        {\n            return new MeetingAttendee(meetingId, attendeeId, decisionDate, role, guestsNumber, eventFee);\n        }\n\n        private MeetingAttendee(\n            MeetingId meetingId,\n            MemberId attendeeId,\n            DateTime decisionDate,\n            MeetingAttendeeRole role,\n            int guestsNumber,\n            MoneyValue eventFee)\n        {\n            this.AttendeeId = attendeeId;\n            this.MeetingId = meetingId;\n            this._decisionDate = decisionDate;\n            this._role = role;\n            _guestsNumber = guestsNumber;\n            _decisionChanged = false;\n            _isFeePaid = false;\n\n            if (eventFee != MoneyValue.Undefined)\n            {\n                _fee = (1 + guestsNumber) * eventFee;\n            }\n            else\n            {\n                _fee = MoneyValue.Undefined;\n            }\n\n            this.AddDomainEvent(new MeetingAttendeeAddedDomainEvent(\n                this.MeetingId,\n                AttendeeId,\n                decisionDate,\n                role.Value,\n                guestsNumber,\n                _fee.Value,\n                _fee.Currency));\n        }\n\n        internal void ChangeDecision()\n        {\n            _decisionChanged = true;\n            _decisionChangeDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MeetingAttendeeChangedDecisionDomainEvent(this.AttendeeId, this.MeetingId));\n        }\n\n        internal bool IsActiveAttendee(MemberId attendeeId)\n        {\n            return this.AttendeeId == attendeeId && !_decisionChanged;\n        }\n\n        internal bool IsActive()\n        {\n            return !_decisionChangeDate.HasValue && !_isRemoved;\n        }\n\n        internal bool IsActiveHost()\n        {\n            return this.IsActive() && _role == MeetingAttendeeRole.Host;\n        }\n\n        internal int GetAttendeeWithGuestsNumber()\n        {\n            return 1 + _guestsNumber;\n        }\n\n        internal void SetAsHost()\n        {\n            _role = MeetingAttendeeRole.Host;\n\n            this.AddDomainEvent(new NewMeetingHostSetDomainEvent(this.MeetingId, this.AttendeeId));\n        }\n\n        internal void SetAsAttendee()\n        {\n            this.CheckRule(new MemberCannotHaveSetAttendeeRoleMoreThanOnceRule(_role));\n            _role = MeetingAttendeeRole.Attendee;\n\n            this.AddDomainEvent(new MemberSetAsAttendeeDomainEvent(this.MeetingId, this.AttendeeId));\n        }\n\n        internal void Remove(MemberId removingMemberId, string reason)\n        {\n            this.CheckRule(new ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule(reason));\n\n            _isRemoved = true;\n            _removedDate = SystemClock.Now;\n            _removingReason = reason;\n            _removingMemberId = removingMemberId;\n\n            this.AddDomainEvent(new MeetingAttendeeRemovedDomainEvent(this.AttendeeId, this.MeetingId, reason));\n        }\n\n        internal void MarkFeeAsPayed()\n        {\n            _isFeePaid = true;\n\n            this.AddDomainEvent(new MeetingAttendeeFeePaidDomainEvent(this.MeetingId, this.AttendeeId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingAttendeeRole.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingAttendeeRole : ValueObject\n    {\n        public static MeetingAttendeeRole Host => new MeetingAttendeeRole(\"Host\");\n\n        public static MeetingAttendeeRole Attendee => new MeetingAttendeeRole(\"Attendee\");\n\n        public string Value { get; }\n\n        private MeetingAttendeeRole(string value)\n        {\n            this.Value = value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingId : TypedIdValueBase\n    {\n        public MeetingId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingLimits.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingLimits : ValueObject\n    {\n        public int? AttendeesLimit { get; }\n\n        public int GuestsLimit { get; }\n\n        private MeetingLimits(int? attendeesLimit, int guestsLimit)\n        {\n            AttendeesLimit = attendeesLimit;\n            GuestsLimit = guestsLimit;\n        }\n\n        public static MeetingLimits Create(int? attendeesLimit, int guestsLimit)\n        {\n            CheckRule(new MeetingAttendeesLimitCannotBeNegativeRule(attendeesLimit));\n\n            CheckRule(new MeetingGuestsLimitCannotBeNegativeRule(guestsLimit));\n\n            CheckRule(new MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule(attendeesLimit, guestsLimit));\n\n            return new MeetingLimits(attendeesLimit, guestsLimit);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingLocation.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingLocation : ValueObject\n    {\n        public static MeetingLocation CreateNew(string name, string address, string postalCode, string city)\n        {\n            return new MeetingLocation(name, address, postalCode, city);\n        }\n\n        private MeetingLocation(string name, string address, string postalCode, string city)\n        {\n            Name = name;\n            Address = address;\n            PostalCode = postalCode;\n            City = city;\n        }\n\n        public string Name { get; }\n\n        public string Address { get; }\n\n        public string PostalCode { get; }\n\n        public string City { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingNotAttendee.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingNotAttendee : Entity\n    {\n        internal MemberId MemberId { get; private set; }\n\n        internal MeetingId MeetingId { get; private set; }\n\n        private DateTime _decisionDate;\n\n        private bool _decisionChanged;\n\n        private DateTime? _decisionChangeDate;\n\n        private MeetingNotAttendee()\n        {\n        }\n\n        private MeetingNotAttendee(MeetingId meetingId, MemberId memberId)\n        {\n            this.MemberId = memberId;\n            this.MeetingId = meetingId;\n            _decisionDate = DateTime.UtcNow;\n\n            this.AddDomainEvent(new MeetingNotAttendeeAddedDomainEvent(this.MeetingId, this.MemberId));\n        }\n\n        internal static MeetingNotAttendee CreateNew(MeetingId meetingId, MemberId memberId)\n        {\n            return new MeetingNotAttendee(meetingId, memberId);\n        }\n\n        internal bool IsActiveNotAttendee(MemberId memberId)\n        {\n            return !this._decisionChanged && this.MemberId == memberId;\n        }\n\n        internal void ChangeDecision()\n        {\n            _decisionChanged = true;\n            _decisionChangeDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MeetingNotAttendeeChangedDecisionDomainEvent(this.MemberId, this.MeetingId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingTerm.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingTerm : ValueObject\n    {\n        public DateTime StartDate { get; }\n\n        public DateTime EndDate { get; }\n\n        public static MeetingTerm CreateNewBetweenDates(DateTime startDate, DateTime endDate)\n        {\n            return new MeetingTerm(startDate, endDate);\n        }\n\n        private MeetingTerm(DateTime startDate, DateTime endDate)\n        {\n            this.StartDate = startDate;\n            this.EndDate = endDate;\n        }\n\n        internal bool IsAfterStart()\n        {\n            return SystemClock.Now > this.StartDate;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MeetingWaitlistMember.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MeetingWaitlistMember : Entity\n    {\n        internal MemberId MemberId { get; private set; }\n\n        internal MeetingId MeetingId { get; private set; }\n\n        internal DateTime SignUpDate { get; private set; }\n\n        private bool _isSignedOff;\n\n        private DateTime? _signOffDate;\n\n        private bool _isMovedToAttendees;\n\n        private DateTime? _movedToAttendeesDate;\n\n        private MeetingWaitlistMember()\n        {\n        }\n\n        private MeetingWaitlistMember(MeetingId meetingId, MemberId memberId)\n        {\n            this.MemberId = memberId;\n            this.MeetingId = meetingId;\n            this.SignUpDate = SystemClock.Now;\n            _isMovedToAttendees = false;\n\n            this.AddDomainEvent(new MeetingWaitlistMemberAddedDomainEvent(this.MeetingId, this.MemberId));\n        }\n\n        internal static MeetingWaitlistMember CreateNew(MeetingId meetingId, MemberId memberId)\n        {\n            return new MeetingWaitlistMember(meetingId, memberId);\n        }\n\n        internal void MarkIsMovedToAttendees()\n        {\n            _isMovedToAttendees = true;\n            _movedToAttendeesDate = SystemClock.Now;\n        }\n\n        internal bool IsActiveOnWaitList(MemberId memberId)\n        {\n            return this.MemberId == memberId && this.IsActive();\n        }\n\n        internal bool IsActive()\n        {\n            return !_isSignedOff && !_isMovedToAttendees;\n        }\n\n        internal void SignOff()\n        {\n            _isSignedOff = true;\n            _signOffDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MemberSignedOffFromMeetingWaitlistDomainEvent(this.MeetingId, this.MemberId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/MoneyValue.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class MoneyValue : ValueObject\n    {\n        public static MoneyValue Undefined => new MoneyValue(null, null);\n\n        public decimal? Value { get; }\n\n        public string Currency { get; }\n\n        public static MoneyValue Of(decimal value, string currency)\n        {\n            return new MoneyValue(value, currency);\n        }\n\n        private MoneyValue(decimal? value, string currency)\n        {\n            this.Value = value;\n            this.Currency = currency;\n        }\n\n        public static MoneyValue operator *(int left, MoneyValue right)\n        {\n            return new MoneyValue(right.Value * left, right.Currency);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/AttendeeCanBeAddedOnlyInRsvpTermRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class AttendeeCanBeAddedOnlyInRsvpTermRule : IBusinessRule\n    {\n        private readonly Term _rsvpTerm;\n\n        internal AttendeeCanBeAddedOnlyInRsvpTermRule(Term rsvpTerm)\n        {\n            _rsvpTerm = rsvpTerm;\n        }\n\n        public bool IsBroken() => !_rsvpTerm.IsInTerm(SystemClock.Now);\n\n        public string Message => \"Attendee can be added only in RSVP term\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    internal class AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule : IBusinessRule\n    {\n        private readonly int? _attendeesLimit;\n\n        private readonly int _allActiveAttendeesWithGuestsNumber;\n\n        internal AttendeesLimitCannotBeChangedToSmallerThanActiveAttendeesRule(\n            MeetingLimits meetingLimits,\n            int allActiveAttendeesWithGuestsNumber)\n        {\n            this._attendeesLimit = meetingLimits.AttendeesLimit;\n            this._allActiveAttendeesWithGuestsNumber = allActiveAttendeesWithGuestsNumber;\n        }\n\n        public bool IsBroken() => _attendeesLimit.HasValue && _attendeesLimit.Value < _allActiveAttendeesWithGuestsNumber;\n\n        public string Message => \"Attendees limit cannot be change to smaller than active attendees number\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingAttendeeMustBeAMemberOfGroupRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingAttendeeMustBeAMemberOfGroupRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n\n        private readonly MemberId _attendeeId;\n\n        internal MeetingAttendeeMustBeAMemberOfGroupRule(MemberId attendeeId, MeetingGroup meetingGroup)\n        {\n            _attendeeId = attendeeId;\n            _meetingGroup = meetingGroup;\n        }\n\n        public bool IsBroken()\n        {\n            return !_meetingGroup.IsMemberOfGroup(_attendeeId);\n        }\n\n        public string Message => \"Meeting attendee must be a member of group\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingAttendeesLimitCannotBeNegativeRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingAttendeesLimitCannotBeNegativeRule : IBusinessRule\n    {\n        private readonly int? _attendeesLimit;\n\n        public MeetingAttendeesLimitCannotBeNegativeRule(int? attendeesLimit)\n        {\n            _attendeesLimit = attendeesLimit;\n        }\n\n        public bool IsBroken() => _attendeesLimit.HasValue && _attendeesLimit.Value < 0;\n\n        public string Message => \"Attendees limit cannot be negative\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule : IBusinessRule\n    {\n        private readonly int? _attendeesLimit;\n\n        private readonly int _guestsLimit;\n\n        public MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule(int? attendeesLimit, int guestsLimit)\n        {\n            _attendeesLimit = attendeesLimit;\n            _guestsLimit = guestsLimit;\n        }\n\n        public bool IsBroken() => _attendeesLimit.HasValue && _attendeesLimit.Value <= _guestsLimit;\n\n        public string Message => \"Attendees limit must be greater than guests limit\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingAttendeesNumberIsAboveLimitRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingAttendeesNumberIsAboveLimitRule : IBusinessRule\n    {\n        private readonly int? _attendeesLimit;\n\n        private readonly int _allActiveAttendeesWithGuestsNumber;\n\n        private readonly int _guestsNumber;\n\n        internal MeetingAttendeesNumberIsAboveLimitRule(\n            int? attendeesLimit,\n            int allActiveAttendeesWithGuestsNumber,\n            int guestsNumber)\n        {\n            _attendeesLimit = attendeesLimit;\n            _allActiveAttendeesWithGuestsNumber = allActiveAttendeesWithGuestsNumber;\n            _guestsNumber = guestsNumber;\n        }\n\n        public bool IsBroken() => this._attendeesLimit.HasValue &&\n                                  this._attendeesLimit.Value < _allActiveAttendeesWithGuestsNumber + 1 + _guestsNumber;\n\n        public string Message => \"Meeting attendees number is above limit\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingCannotBeChangedAfterStartRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingCannotBeChangedAfterStartRule : IBusinessRule\n    {\n        private readonly MeetingTerm _meetingTerm;\n\n        public MeetingCannotBeChangedAfterStartRule(MeetingTerm meetingTerm)\n        {\n            _meetingTerm = meetingTerm;\n        }\n\n        public bool IsBroken() => _meetingTerm.IsAfterStart();\n\n        public string Message => \"Meeting cannot be changed after start\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingGuestsLimitCannotBeNegativeRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingGuestsLimitCannotBeNegativeRule : IBusinessRule\n    {\n        private readonly int _guestsLimit;\n\n        public MeetingGuestsLimitCannotBeNegativeRule(int guestsLimit)\n        {\n            _guestsLimit = guestsLimit;\n        }\n\n        public bool IsBroken() => _guestsLimit < 0;\n\n        public string Message => \"Guests limit cannot be negative\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingGuestsNumberIsAboveLimitRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingGuestsNumberIsAboveLimitRule : IBusinessRule\n    {\n        private readonly int _guestsNumber;\n\n        private readonly int _guestsLimit;\n\n        public MeetingGuestsNumberIsAboveLimitRule(int guestsLimit, int guestsNumber)\n        {\n            _guestsNumber = guestsNumber;\n            _guestsLimit = guestsLimit;\n        }\n\n        public bool IsBroken() => this._guestsLimit > 0 && this._guestsLimit < _guestsNumber;\n\n        public string Message => \"Meeting guests number is above limit\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MeetingMustHaveAtLeastOneHostRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MeetingMustHaveAtLeastOneHostRule : IBusinessRule\n    {\n        private readonly int _meetingHostNumber;\n\n        public MeetingMustHaveAtLeastOneHostRule(int meetingHostNumber)\n        {\n            _meetingHostNumber = meetingHostNumber;\n        }\n\n        public bool IsBroken() => _meetingHostNumber == 0;\n\n        public string Message => \"Meeting must have at least one host\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule : IBusinessRule\n    {\n        private readonly MemberId _attendeeId;\n\n        private readonly List<MeetingAttendee> _attendees;\n\n        public MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule(MemberId attendeeId, List<MeetingAttendee> attendees)\n        {\n            this._attendeeId = attendeeId;\n            _attendees = attendees;\n        }\n\n        public bool IsBroken() => _attendees.SingleOrDefault(x => x.IsActiveAttendee(_attendeeId)) != null;\n\n        public string Message => \"Member is already an attendee of this meeting\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MemberCannotBeMoreThanOnceOnMeetingWaitlistRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MemberCannotBeMoreThanOnceOnMeetingWaitlistRule : IBusinessRule\n    {\n        private readonly List<MeetingWaitlistMember> _waitListMembers;\n\n        private readonly MemberId _memberId;\n\n        internal MemberCannotBeMoreThanOnceOnMeetingWaitlistRule(List<MeetingWaitlistMember> waitListMembers, MemberId memberId)\n        {\n            _waitListMembers = waitListMembers;\n            _memberId = memberId;\n        }\n\n        public bool IsBroken() => _waitListMembers.SingleOrDefault(x => x.IsActiveOnWaitList(_memberId)) != null;\n\n        public string Message => \"Member cannot be more than once on the meeting waitlist\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MemberCannotBeNotAttendeeTwiceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MemberCannotBeNotAttendeeTwiceRule : IBusinessRule\n    {\n        private readonly List<MeetingNotAttendee> _notAttendees;\n\n        private readonly MemberId _memberId;\n\n        public MemberCannotBeNotAttendeeTwiceRule(List<MeetingNotAttendee> notAttendees, MemberId memberId)\n        {\n            _notAttendees = notAttendees;\n            _memberId = memberId;\n        }\n\n        public bool IsBroken() => _notAttendees.SingleOrDefault(x => x.IsActiveNotAttendee(_memberId)) != null;\n\n        public string Message => \"Member cannot be active not attendee twice\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MemberCannotHaveSetAttendeeRoleMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MemberCannotHaveSetAttendeeRoleMoreThanOnceRule : IBusinessRule\n    {\n        private readonly MeetingAttendeeRole _meetingAttendeeRole;\n\n        internal MemberCannotHaveSetAttendeeRoleMoreThanOnceRule(MeetingAttendeeRole meetingAttendeeRole)\n        {\n            _meetingAttendeeRole = meetingAttendeeRole;\n        }\n\n        public bool IsBroken() => _meetingAttendeeRole == MeetingAttendeeRole.Attendee;\n\n        public string Message => \"Member cannot be attendee of meeting more than once\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/MemberOnWaitlistMustBeAMemberOfGroupRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class MemberOnWaitlistMustBeAMemberOfGroupRule : IBusinessRule\n    {\n        private readonly MeetingGroup _meetingGroup;\n\n        private readonly MemberId _memberId;\n\n        private readonly List<MeetingAttendee> _attendees;\n\n        internal MemberOnWaitlistMustBeAMemberOfGroupRule(MeetingGroup meetingGroup, MemberId memberId, List<MeetingAttendee> attendees)\n            : base()\n        {\n            _meetingGroup = meetingGroup;\n            _memberId = memberId;\n            _attendees = attendees;\n        }\n\n        public bool IsBroken() => !_meetingGroup.IsMemberOfGroup(_memberId);\n\n        public string Message => \"Member on waitlist must be a member of group\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/NotActiveMemberOfWaitlistCannotBeSignedOffRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class NotActiveMemberOfWaitlistCannotBeSignedOffRule : IBusinessRule\n    {\n        private readonly List<MeetingWaitlistMember> _waitlistMembers;\n\n        private readonly MemberId _memberId;\n\n        public NotActiveMemberOfWaitlistCannotBeSignedOffRule(List<MeetingWaitlistMember> waitlistMembers, MemberId memberId)\n        {\n            _waitlistMembers = waitlistMembers;\n            _memberId = memberId;\n        }\n\n        public bool IsBroken() => _waitlistMembers.SingleOrDefault(x => x.IsActiveOnWaitList(_memberId)) == null;\n\n        public string Message => \"Not active member of waitlist cannot be signed off\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/NotActiveNotAttendeeCannotChangeDecisionRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class NotActiveNotAttendeeCannotChangeDecisionRule : IBusinessRule\n    {\n        private readonly List<MeetingNotAttendee> _notAttendees;\n\n        private readonly MemberId _memberId;\n\n        internal NotActiveNotAttendeeCannotChangeDecisionRule(List<MeetingNotAttendee> notAttendees, MemberId memberId)\n        {\n            _notAttendees = notAttendees;\n            _memberId = memberId;\n        }\n\n        public bool IsBroken() => _notAttendees.SingleOrDefault(x => x.IsActiveNotAttendee(_memberId)) == null;\n\n        public string Message => \"Member is not active not attendee\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/OnlyActiveAttendeeCanBeRemovedFromMeetingRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class OnlyActiveAttendeeCanBeRemovedFromMeetingRule : IBusinessRule\n    {\n        private readonly List<MeetingAttendee> _attendees;\n        private readonly MemberId _attendeeId;\n\n        internal OnlyActiveAttendeeCanBeRemovedFromMeetingRule(\n            List<MeetingAttendee> attendees,\n            MemberId attendeeId)\n        {\n            _attendees = attendees;\n            _attendeeId = attendeeId;\n        }\n\n        public bool IsBroken() => _attendees.SingleOrDefault(x => x.IsActiveAttendee(_attendeeId)) == null;\n\n        public string Message => \"Only active attendee can be removed from meeting\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/OnlyMeetingAttendeeCanHaveChangedRoleRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    internal class OnlyMeetingAttendeeCanHaveChangedRoleRule : IBusinessRule\n    {\n        private readonly List<MeetingAttendee> _attendees;\n\n        private readonly MemberId _newOrganizerId;\n\n        internal OnlyMeetingAttendeeCanHaveChangedRoleRule(List<MeetingAttendee> attendees, MemberId newOrganizerId)\n        {\n            _attendees = attendees;\n            _newOrganizerId = newOrganizerId;\n        }\n\n        public bool IsBroken() => _attendees.SingleOrDefault(x => x.IsActiveAttendee(_newOrganizerId)) == null;\n\n        public string Message => \"Only meeting attendee can be se as organizer of meeting\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule : IBusinessRule\n    {\n        private readonly MemberId _settingMemberId;\n        private readonly MeetingGroup _meetingGroup;\n        private readonly List<MeetingAttendee> _attendees;\n\n        public OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule(MemberId settingMemberId, MeetingGroup meetingGroup, List<MeetingAttendee> attendees)\n        {\n            _settingMemberId = settingMemberId;\n            _meetingGroup = meetingGroup;\n            _attendees = attendees;\n        }\n\n        public bool IsBroken()\n        {\n            var settingMember = _attendees.SingleOrDefault(x => x.IsActiveAttendee(_settingMemberId));\n\n            var isHost = settingMember != null && settingMember.IsActiveHost();\n            var isOrganizer = _meetingGroup.IsOrganizer(_settingMemberId);\n\n            return !isHost && !isOrganizer;\n        }\n\n        public string Message => \"Only meeting host or group organizer can set meeting member roles\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Rules/ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules\n{\n    public class ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule : IBusinessRule\n    {\n        private readonly string _reason;\n\n        internal ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule(string reason)\n        {\n            _reason = reason;\n        }\n\n        public bool IsBroken() => string.IsNullOrEmpty(_reason);\n\n        public string Message => \"Reason of removing attendee from meeting must be provided\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Meetings/Term.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings\n{\n    public class Term : ValueObject\n    {\n        public static Term NoTerm => new Term(null, null);\n\n        public DateTime? StartDate { get; }\n\n        public DateTime? EndDate { get; }\n\n        public static Term CreateNewBetweenDates(DateTime? startDate, DateTime? endDate)\n        {\n            return new Term(startDate, endDate);\n        }\n\n        private Term(DateTime? startDate, DateTime? endDate)\n        {\n            this.StartDate = startDate;\n            this.EndDate = endDate;\n        }\n\n        internal bool IsInTerm(DateTime date)\n        {\n            var left = !this.StartDate.HasValue || this.StartDate.Value <= date;\n\n            var right = !this.EndDate.HasValue || this.EndDate.Value >= date;\n\n            return left && right;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/Events/MemberCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.Events\n{\n    public class MemberCreatedDomainEvent : DomainEventBase\n    {\n        public MemberId MemberId { get; }\n\n        public MemberCreatedDomainEvent(MemberId memberId)\n        {\n            MemberId = memberId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/IMemberContext.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\n{\n    public interface IMemberContext\n    {\n        MemberId MemberId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/IMemberRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\n{\n    public interface IMemberRepository\n    {\n        Task AddAsync(Member member);\n\n        Task<Member> GetByIdAsync(MemberId memberId);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MeetingGroupMemberData.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\n{\n    public class MeetingGroupMemberData\n    {\n        public MeetingGroupId MeetingGroupId { get; }\n\n        public MemberId MemberId { get; }\n\n        public MeetingGroupMemberData(MeetingGroupId meetingGroupId, MemberId memberId)\n        {\n            MemberId = memberId;\n            MeetingGroupId = meetingGroupId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/Member.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\n{\n    public class Member : Entity, IAggregateRoot\n    {\n        public MemberId Id { get; private set; }\n\n        private string _login;\n\n        private string _email;\n\n        private string _firstName;\n\n        private string _lastName;\n\n        private string _name;\n\n        private DateTime _createDate;\n\n        private Member()\n        {\n            // Only for EF.\n        }\n\n        public static Member Create(Guid id, string login, string email, string firstName, string lastName, string name)\n        {\n            return new Member(id, login, email, firstName, lastName, name);\n        }\n\n        private Member(Guid id, string login, string email, string firstName, string lastName, string name)\n        {\n            this.Id = new MemberId(id);\n            _login = login;\n            _email = email;\n            _firstName = firstName;\n            _lastName = lastName;\n            _name = name;\n            _createDate = SystemClock.Now;\n\n            this.AddDomainEvent(new MemberCreatedDomainEvent(this.Id));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MemberId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members\n{\n    public class MemberId : TypedIdValueBase\n    {\n        public MemberId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MemberSubscriptions/Events/MemberSubscriptionExpirationDateChangedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions.Events\n{\n    public class MemberSubscriptionExpirationDateChangedDomainEvent : DomainEventBase\n    {\n        public MemberSubscriptionExpirationDateChangedDomainEvent(MemberId memberId, DateTime expirationDate)\n        {\n            MemberId = memberId;\n            ExpirationDate = expirationDate;\n        }\n\n        public MemberId MemberId { get; }\n\n        public DateTime ExpirationDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MemberSubscriptions/IMemberSubscriptionRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\n{\n    public interface IMemberSubscriptionRepository\n    {\n        Task<MemberSubscription> GetByIdOptionalAsync(MemberSubscriptionId memberSubscriptionId);\n\n        Task AddAsync(MemberSubscription memberSubscription);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MemberSubscriptions/MemberSubscription.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\n{\n    public class MemberSubscription : Entity, IAggregateRoot\n    {\n        public MemberSubscriptionId Id { get; private set; }\n\n        private DateTime _expirationDate;\n\n        private MemberSubscription()\n        {\n            // Only for EF.\n        }\n\n        private MemberSubscription(MemberId memberId, DateTime expirationDate)\n        {\n            this.Id = new MemberSubscriptionId(memberId.Value);\n            _expirationDate = expirationDate;\n\n            this.AddDomainEvent(new MemberSubscriptionExpirationDateChangedDomainEvent(memberId, _expirationDate));\n        }\n\n        public static MemberSubscription CreateForMember(MemberId memberId, DateTime expirationDate)\n        {\n            return new MemberSubscription(memberId, expirationDate);\n        }\n\n        public void ChangeExpirationDate(DateTime expirationDate)\n        {\n            _expirationDate = expirationDate;\n\n            this.AddDomainEvent(new MemberSubscriptionExpirationDateChangedDomainEvent(\n                new MemberId(this.Id.Value),\n                _expirationDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/Members/MemberSubscriptions/MemberSubscriptionId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions\n{\n    public class MemberSubscriptionId : TypedIdValueBase\n    {\n        public MemberSubscriptionId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Domain/SharedKernel/SystemClock.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel\n{\n    public static class SystemClock\n    {\n        private static DateTime? _customDate;\n\n        public static DateTime Now\n        {\n            get\n            {\n                if (_customDate.HasValue)\n                {\n                    return _customDate.Value;\n                }\n\n                return DateTime.UtcNow;\n            }\n        }\n\n        public static void Set(DateTime customDate) => _customDate = customDate;\n\n        public static void Reset() => _customDate = null;\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/CompanyName.MyMeetings.Modules.Meetings.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/AllConstructorFinder.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing Autofac.Core.Activators.Reflection;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration\n{\n    internal class AllConstructorFinder : IConstructorFinder\n    {\n        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =\n            new ConcurrentDictionary<Type, ConstructorInfo[]>();\n\n        public ConstructorInfo[] FindConstructors(Type targetType)\n        {\n            var result = Cache.GetOrAdd(\n                targetType,\n                t => t.GetTypeInfo().DeclaredConstructors.ToArray());\n\n            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType, this);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Assemblies.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration\n{\n    internal static class Assemblies\n    {\n        public static readonly Assembly Application = typeof(IMeetingsModule).Assembly;\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Authentication/AuthenticationModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Authentication\n{\n    internal class AuthenticationModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<MemberContext>()\n                .As<IMemberContext>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/DataAccess/DataAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.DataAccess\n{\n    internal class DataAccessModule : Autofac.Module\n    {\n        private readonly string _databaseConnectionString;\n        private readonly ILoggerFactory _loggerFactory;\n\n        internal DataAccessModule(string databaseConnectionString, ILoggerFactory loggerFactory)\n        {\n            _databaseConnectionString = databaseConnectionString;\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlConnectionFactory>()\n                .As<ISqlConnectionFactory>()\n                .WithParameter(\"connectionString\", _databaseConnectionString)\n                .InstancePerLifetimeScope();\n\n            builder\n                .Register(c =>\n                {\n                    var dbContextOptionsBuilder = new DbContextOptionsBuilder<MeetingsContext>();\n                    dbContextOptionsBuilder.UseSqlServer(_databaseConnectionString);\n\n                    dbContextOptionsBuilder\n                        .ReplaceService<IValueConverterSelector, StronglyTypedIdValueConverterSelector>();\n\n                    return new MeetingsContext(dbContextOptionsBuilder.Options, _loggerFactory);\n                })\n                .AsSelf()\n                .As<DbContext>()\n                .InstancePerLifetimeScope();\n\n            var infrastructureAssembly = typeof(MeetingsContext).Assembly;\n\n            builder.RegisterAssemblyTypes(infrastructureAssembly)\n                .Where(type => type.Name.EndsWith(\"Repository\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Email/EmailModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Email\n{\n    internal class EmailModule : Module\n    {\n        private readonly EmailsConfiguration _configuration;\n\n        public EmailModule(EmailsConfiguration configuration)\n        {\n            _configuration = configuration;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<EmailSender>()\n                .As<IEmailSender>()\n                .WithParameter(\"configuration\", _configuration)\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/EventsBus/EventsBusModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.EventsBus\n{\n    internal class EventsBusModule : Autofac.Module\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public EventsBusModule(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_eventsBus != null)\n            {\n                builder.RegisterInstance(_eventsBus).SingleInstance();\n            }\n            else\n            {\n                builder.RegisterType<InMemoryEventBusClient>()\n                .As<IEventsBus>()\n                .SingleInstance();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/EventsBus/EventsBusStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.EventsBus\n{\n    public static class EventsBusStartup\n    {\n        public static void Initialize(\n            ILogger logger)\n        {\n            SubscribeToIntegrationEvents(logger);\n        }\n\n        private static void SubscribeToIntegrationEvents(ILogger logger)\n        {\n            var eventBus = MeetingsCompositionRoot.BeginLifetimeScope().Resolve<IEventsBus>();\n\n            SubscribeToIntegrationEvent<MeetingGroupProposalAcceptedIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<SubscriptionExpirationDateChangedIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<NewUserRegisteredIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<MeetingFeePaidIntegrationEvent>(eventBus, logger);\n        }\n\n        private static void SubscribeToIntegrationEvent<T>(IEventsBus eventBus, ILogger logger)\n            where T : IntegrationEvent\n        {\n            logger.Information(\"Subscribe to {@IntegrationEvent}\", typeof(T).FullName);\n            eventBus.Subscribe(\n                new IntegrationEventGenericHandler<T>());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/EventsBus/IntegrationEventGenericHandler.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.EventsBus\n{\n    internal class IntegrationEventGenericHandler<T> : IIntegrationEventHandler<T>\n        where T : IntegrationEvent\n    {\n        public async Task Handle(T @event)\n        {\n            using (var scope = MeetingsCompositionRoot.BeginLifetimeScope())\n            {\n                using (var connection = scope.Resolve<ISqlConnectionFactory>().GetOpenConnection())\n                {\n                    string type = @event.GetType().FullName;\n                    var data = JsonConvert.SerializeObject(@event, new JsonSerializerSettings\n                    {\n                        ContractResolver = new AllPropertiesContractResolver()\n                    });\n\n                    var sql = \"INSERT INTO [meetings].[InboxMessages] (Id, OccurredOn, Type, Data) \" +\n                              \"VALUES (@Id, @OccurredOn, @Type, @Data)\";\n\n                    await connection.ExecuteScalarAsync(sql, new\n                    {\n                        @event.Id,\n                        @event.OccurredOn,\n                        type,\n                        data\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Logging/LoggingModule.cs",
    "content": "﻿using Autofac;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Logging\n{\n    internal class LoggingModule : Autofac.Module\n    {\n        private readonly ILogger _logger;\n\n        internal LoggingModule(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterInstance(_logger)\n                .As<ILogger>()\n                .SingleInstance();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Mediation/MediatorModule.cs",
    "content": "﻿using System.Reflection;\nusing Autofac;\nusing Autofac.Core;\nusing Autofac.Features.Variance;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing FluentValidation;\nusing MediatR;\nusing MediatR.Pipeline;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Mediation\n{\n    public class MediatorModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<ServiceProviderWrapper>()\n            .As<IServiceProvider>()\n            .InstancePerDependency()\n            .IfNotRegistered(typeof(IServiceProvider));\n\n            builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope();\n\n            var mediatorOpenTypes = new[]\n            {\n                typeof(IRequestHandler<,>),\n                typeof(INotificationHandler<>),\n                typeof(IValidator<>),\n                typeof(IRequestPreProcessor<>),\n                typeof(IRequestHandler<>),\n                typeof(IStreamRequestHandler<,>),\n                typeof(IRequestPostProcessor<,>),\n                typeof(IRequestExceptionHandler<,,>),\n                typeof(IRequestExceptionAction<,>),\n                typeof(ICommandHandler<>),\n                typeof(ICommandHandler<,>),\n            };\n            builder.RegisterSource(new ScopedContravariantRegistrationSource(\n                mediatorOpenTypes));\n            foreach (var mediatorOpenType in mediatorOpenTypes)\n            {\n                builder\n                    .RegisterAssemblyTypes(Assemblies.Application, ThisAssembly)\n                    .AsClosedTypesOf(mediatorOpenType)\n                    .AsImplementedInterfaces()\n                    .FindConstructorsWith(new AllConstructorFinder());\n            }\n\n            builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n            builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n        }\n\n        private class ScopedContravariantRegistrationSource : IRegistrationSource\n        {\n            private readonly ContravariantRegistrationSource _source = new();\n            private readonly List<Type> _types = new();\n\n            public ScopedContravariantRegistrationSource(params Type[] types)\n            {\n                ArgumentNullException.ThrowIfNull(types);\n\n                if (!types.All(x => x.IsGenericTypeDefinition))\n                {\n                    throw new ArgumentException(\"Supplied types should be generic type definitions\");\n                }\n\n                _types.AddRange(types);\n            }\n\n            public IEnumerable<IComponentRegistration> RegistrationsFor(\n                Service service,\n                Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)\n            {\n                var components = _source.RegistrationsFor(service, registrationAccessor);\n                foreach (var c in components)\n                {\n                    var defs = c.Target.Services\n                        .OfType<TypedService>()\n                        .Select(x => x.ServiceType.GetGenericTypeDefinition());\n\n                    if (defs.Any(_types.Contains))\n                    {\n                        yield return c;\n                    }\n                }\n            }\n\n            public bool IsAdapterForIndividualComponents => _source.IsAdapterForIndividualComponents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/MeetingsCompositionRoot.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration\n{\n    internal static class MeetingsCompositionRoot\n    {\n        private static IContainer _container;\n\n        internal static void SetContainer(IContainer container)\n        {\n            _container = container;\n        }\n\n        internal static ILifetimeScope BeginLifetimeScope()\n        {\n            return _container.BeginLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/MeetingsStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.SendMeetingAttendeeAddedEmail;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MemberSubscriptions;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Authentication;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.DataAccess;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Email;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.EventsBus;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Logging;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Mediation;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Quartz;\nusing Serilog.Extensions.Logging;\nusing ILogger = Serilog.ILogger;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration\n{\n    public class MeetingsStartup\n    {\n        private static IContainer _container;\n\n        public static void Initialize(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            IEventsBus eventsBus,\n            long? internalProcessingPoolingInterval = null)\n        {\n            var moduleLogger = logger.ForContext(\"Module\", \"Meetings\");\n\n            ConfigureCompositionRoot(\n                connectionString,\n                executionContextAccessor,\n                moduleLogger,\n                emailsConfiguration,\n                eventsBus);\n\n            QuartzStartup.Initialize(moduleLogger, internalProcessingPoolingInterval);\n\n            EventsBusStartup.Initialize(moduleLogger);\n        }\n\n        public static void Stop()\n        {\n            QuartzStartup.StopQuartz();\n        }\n\n        private static void ConfigureCompositionRoot(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            IEventsBus eventsBus)\n        {\n            var containerBuilder = new ContainerBuilder();\n\n            containerBuilder.RegisterModule(new LoggingModule(logger.ForContext(\"Module\", \"Meetings\")));\n\n            var loggerFactory = new SerilogLoggerFactory(logger);\n            containerBuilder.RegisterModule(new DataAccessModule(connectionString, loggerFactory));\n            containerBuilder.RegisterModule(new ProcessingModule());\n            containerBuilder.RegisterModule(new EventsBusModule(eventsBus));\n            containerBuilder.RegisterModule(new MediatorModule());\n            containerBuilder.RegisterModule(new AuthenticationModule());\n\n            var domainNotificationsMap = new BiDictionary<string, Type>();\n            domainNotificationsMap.Add(\"MeetingGroupProposalAcceptedNotification\", typeof(MeetingGroupProposalAcceptedNotification));\n            domainNotificationsMap.Add(\"MeetingGroupProposedNotification\", typeof(MeetingGroupProposedNotification));\n            domainNotificationsMap.Add(\"MeetingGroupCreatedNotification\", typeof(MeetingGroupCreatedNotification));\n            domainNotificationsMap.Add(\"MeetingAttendeeAddedNotification\", typeof(MeetingAttendeeAddedNotification));\n            domainNotificationsMap.Add(\"MemberCreatedNotification\", typeof(MemberCreatedNotification));\n            domainNotificationsMap.Add(\"MemberSubscriptionExpirationDateChangedNotification\", typeof(MemberSubscriptionExpirationDateChangedNotification));\n            domainNotificationsMap.Add(\"MeetingCommentLikedNotification\", typeof(MeetingCommentLikedNotification));\n            domainNotificationsMap.Add(\"MeetingCommentUnlikedNotification\", typeof(MeetingCommentUnlikedNotification));\n            containerBuilder.RegisterModule(new OutboxModule(domainNotificationsMap));\n\n            containerBuilder.RegisterModule(new EmailModule(emailsConfiguration));\n            containerBuilder.RegisterModule(new QuartzModule());\n\n            containerBuilder.RegisterInstance(executionContextAccessor);\n\n            _container = containerBuilder.Build();\n\n            MeetingsCompositionRoot.SetContainer(_container);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/CommandsExecutor.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal static class CommandsExecutor\n    {\n        internal static async Task Execute(ICommand command)\n        {\n            using (var scope = MeetingsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                await mediator.Send(command);\n            }\n        }\n\n        internal static async Task<TResult> Execute<TResult>(ICommand<TResult> command)\n        {\n            using (var scope = MeetingsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                return await mediator.Send(command);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Inbox/InboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Inbox\n{\n    public class InboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Inbox\n{\n    public class ProcessInboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Inbox\r\n{\r\n    internal class ProcessInboxCommandHandler : ICommandHandler<ProcessInboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInboxCommandHandler(IMediator mediator, ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                               SELECT [InboxMessage].[Id] AS [{nameof(InboxMessageDto.Id)}], \r\n                                      [InboxMessage].[Type] AS [{nameof(InboxMessageDto.Type)}], \r\n                                      [InboxMessage].[Data] AS [{nameof(InboxMessageDto.Data)}] \r\n                               FROM [meetings].[InboxMessages] AS [InboxMessage] \r\n                               WHERE [InboxMessage].[ProcessedDate] IS NULL \r\n                               ORDER BY [InboxMessage].[OccurredOn]\r\n                               \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<InboxMessageDto>(sql);\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [meetings].[InboxMessages] \r\n                                                  SET [ProcessedDate] = @Date\r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n\r\n            foreach (var message in messages)\r\n            {\r\n                var messageAssembly = AppDomain.CurrentDomain.GetAssemblies()\r\n                    .SingleOrDefault(assembly => message.Type.Contains(assembly.GetName().Name));\r\n\r\n                Type type = messageAssembly.GetType(message.Type);\r\n                var request = JsonConvert.DeserializeObject(message.Data, type);\r\n\r\n                try\r\n                {\r\n                    await _mediator.Publish((INotification)request, cancellationToken);\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    Console.WriteLine(e);\r\n                    throw;\r\n                }\r\n\r\n                await connection.ExecuteScalarAsync(sqlUpdateProcessedDate, new\r\n                {\r\n                    Date = DateTime.UtcNow,\r\n                    message.Id\r\n                });\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Inbox/ProcessInboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Inbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/InternalCommands/CommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands\n{\n    public class CommandsScheduler : ICommandsScheduler\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public CommandsScheduler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task EnqueueAsync(ICommand command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [meetings].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n\n        public Task EnqueueAsync<T>(ICommand<T> command)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing Newtonsoft.Json;\r\nusing Polly;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands\r\n{\r\n    internal class ProcessInternalCommandsCommandHandler : ICommandHandler<ProcessInternalCommandsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInternalCommandsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInternalCommandsCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n\r\n            const string sql = $\"\"\"\r\n                                SELECT \r\n                                    [Command].[Id] AS [{nameof(InternalCommandDto.Id)}], \r\n                                    [Command].[Type] AS [{nameof(InternalCommandDto.Type)}], \r\n                                    [Command].[Data] AS [{nameof(InternalCommandDto.Data)}] \r\n                                FROM [meetings].[InternalCommands] AS [Command] \r\n                                WHERE [Command].[ProcessedDate] IS NULL \r\n                                ORDER BY [Command].[EnqueueDate]\r\n                                \"\"\";\r\n            var commands = await connection.QueryAsync<InternalCommandDto>(sql);\r\n\r\n            var internalCommandsList = commands.AsList();\r\n\r\n            var policy = Policy\r\n                .Handle<Exception>()\r\n                .WaitAndRetryAsync(new[]\r\n                {\r\n                    TimeSpan.FromSeconds(1),\r\n                    TimeSpan.FromSeconds(2),\r\n                    TimeSpan.FromSeconds(3)\r\n                });\r\n            foreach (var internalCommand in internalCommandsList)\r\n            {\r\n                var result = await policy.ExecuteAndCaptureAsync(() => ProcessCommand(\r\n                    internalCommand));\r\n\r\n                if (result.Outcome == OutcomeType.Failure)\r\n                {\r\n                    await connection.ExecuteScalarAsync(\r\n                        \"\"\"\r\n                        UPDATE [meetings].[InternalCommands] \r\n                        SET ProcessedDate = @NowDate, Error = @Error \r\n                        WHERE [Id] = @Id\r\n                        \"\"\",\r\n                        new\r\n                        {\r\n                            NowDate = DateTime.UtcNow,\r\n                            Error = result.FinalException.ToString(),\r\n                            internalCommand.Id\r\n                        });\r\n                }\r\n            }\r\n        }\r\n\r\n        private async Task ProcessCommand(\r\n            InternalCommandDto internalCommand)\r\n        {\r\n            Type type = Assemblies.Application.GetType(internalCommand.Type);\r\n            dynamic commandToProcess = JsonConvert.DeserializeObject(internalCommand.Data, type);\r\n\r\n            await CommandsExecutor.Execute(commandToProcess);\r\n        }\r\n\r\n        private class InternalCommandDto\r\n        {\r\n            public Guid Id { get; set; }\r\n\r\n            public string Type { get; set; }\r\n\r\n            public string Data { get; set; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInternalCommandsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInternalCommandsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/LoggingCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\r\nusing Serilog;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\r\n{\r\n    internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ILogger _logger;\r\n        private readonly IExecutionContextAccessor _executionContextAccessor;\r\n        private readonly ICommandHandler<T> _decorated;\r\n\r\n        public LoggingCommandHandlerDecorator(\r\n            ILogger logger,\r\n            IExecutionContextAccessor executionContextAccessor,\r\n            ICommandHandler<T> decorated)\r\n        {\r\n            _logger = logger;\r\n            _executionContextAccessor = executionContextAccessor;\r\n            _decorated = decorated;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            if (command is IRecurringCommand)\r\n            {\r\n                await _decorated.Handle(command, cancellationToken);\r\n\r\n                return;\r\n            }\r\n\r\n            using (\r\n                LogContext.Push(\r\n                    new RequestLogEnricher(_executionContextAccessor),\r\n                    new CommandLogEnricher(command)))\r\n            {\r\n                try\r\n                {\r\n                    this._logger.Information(\r\n                        \"Executing command {Command}\",\r\n                        command.GetType().Name);\r\n\r\n                    await _decorated.Handle(command, cancellationToken);\r\n\r\n                    this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\r\n                }\r\n                catch (Exception exception)\r\n                {\r\n                    this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\r\n                    throw;\r\n                }\r\n            }\r\n        }\r\n\r\n        private class CommandLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly ICommand _command;\r\n\r\n            public CommandLogEnricher(ICommand command)\r\n            {\r\n                _command = command;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\r\n                    \"Context\",\r\n                    new ScalarValue($\"Command:{_command.Id.ToString()}\")));\r\n            }\r\n        }\r\n\r\n        private class RequestLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IExecutionContextAccessor _executionContextAccessor;\r\n\r\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\r\n            {\r\n                _executionContextAccessor = executionContextAccessor;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                if (_executionContextAccessor.IsAvailable)\r\n                {\r\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\r\n                        \"CorrelationId\",\r\n                        new ScalarValue(_executionContextAccessor.CorrelationId)));\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/LoggingCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public LoggingCommandHandlerWithResultDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T, TResult> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                return await _decorated.Handle(command, cancellationToken);\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {@Command}\",\n                        command);\n\n                    var result = await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command processed successful, result {Result}\", result);\n\n                    return result;\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command processing failed\");\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand<TResult> _command;\n\n            public CommandLogEnricher(ICommand<TResult> command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\n                    \"Context\",\n                    new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\n                        \"CorrelationId\",\n                        new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Outbox/OutboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox\n{\n    public class OutboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Outbox/OutboxModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Outbox;\nusing Module = Autofac.Module;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class OutboxModule : Module\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public OutboxModule(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<OutboxAccessor>()\n                .As<IOutbox>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .InstancePerLifetimeScope();\n\n            this.CheckMappings();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"domainNotificationsMap\", _domainNotificationsMap)\n                .SingleInstance();\n        }\n\n        private void CheckMappings()\n        {\n            var domainEventNotifications = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.GetInterfaces().Contains(typeof(IDomainEventNotification)))\n                .ToList();\n\n            List<Type> notMappedNotifications = [];\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                _domainNotificationsMap.TryGetBySecond(domainEventNotification, out var name);\n\n                if (name == null)\n                {\n                    notMappedNotifications.Add(domainEventNotification);\n                }\n            }\n\n            if (notMappedNotifications.Any())\n            {\n                throw new ApplicationException($\"Domain Event Notifications {notMappedNotifications.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox\n{\n    public class ProcessOutboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox\r\n{\r\n    internal class ProcessOutboxCommandHandler : ICommandHandler<ProcessOutboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\r\n\r\n        public ProcessOutboxCommandHandler(\r\n            IMediator mediator,\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IDomainNotificationsMapper domainNotificationsMapper)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _domainNotificationsMapper = domainNotificationsMapper;\r\n        }\r\n\r\n        public async Task Handle(ProcessOutboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                                SELECT \r\n                                    [OutboxMessage].[Id] AS [{nameof(OutboxMessageDto.Id)}], \r\n                                    [OutboxMessage].[Type] AS [{nameof(OutboxMessageDto.Type)}], \r\n                                    [OutboxMessage].[Data] AS [{nameof(OutboxMessageDto.Data)}] \r\n                                FROM [meetings].[OutboxMessages] AS [OutboxMessage] \r\n                                WHERE [OutboxMessage].[ProcessedDate] IS NULL \r\n                                ORDER BY [OutboxMessage].[OccurredOn]\r\n                                \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\r\n            var messagesList = messages.AsList();\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [meetings].[OutboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n            if (messagesList.Count > 0)\r\n            {\r\n                foreach (var message in messagesList)\r\n                {\r\n                    var type = _domainNotificationsMapper.GetType(message.Type);\r\n                    var @event = JsonConvert.DeserializeObject(message.Data, type) as IDomainEventNotification;\r\n\r\n                    using (LogContext.Push(new OutboxMessageContextEnricher(@event)))\r\n                    {\r\n                        await this._mediator.Publish(@event, cancellationToken);\r\n\r\n                        await connection.ExecuteAsync(sqlUpdateProcessedDate, new\r\n                        {\r\n                            Date = DateTime.UtcNow,\r\n                            message.Id\r\n                        });\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private class OutboxMessageContextEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IDomainEventNotification _notification;\r\n\r\n            public OutboxMessageContextEnricher(IDomainEventNotification notification)\r\n            {\r\n                _notification = notification;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"OutboxMessage:{_notification.Id.ToString()}\")));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessOutboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessOutboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/ProcessingModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal class ProcessingModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<DomainEventsDispatcher>()\n                .As<IDomainEventsDispatcher>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainEventsAccessor>()\n                .As<IDomainEventsAccessor>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<UnitOfWork>()\n                .As<IUnitOfWork>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<CommandsScheduler>()\n                .As<ICommandsScheduler>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerDecorator<>),\n                typeof(IRequestHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerWithResultDecorator<,>),\n                typeof(IRequestHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(DomainEventsDispatcherNotificationHandlerDecorator<>),\n                typeof(INotificationHandler<>));\n\n            builder.RegisterAssemblyTypes(Assemblies.Application)\n                .AsClosedTypesOf(typeof(IDomainEventNotification<>))\n                .InstancePerDependency()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\r\nusing Microsoft.EntityFrameworkCore;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\r\n{\r\n    internal class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ICommandHandler<T> _decorated;\r\n        private readonly IUnitOfWork _unitOfWork;\r\n        private readonly MeetingsContext _meetingContext;\r\n\r\n        public UnitOfWorkCommandHandlerDecorator(\r\n            ICommandHandler<T> decorated,\r\n            IUnitOfWork unitOfWork,\r\n            MeetingsContext meetingContext)\r\n        {\r\n            _decorated = decorated;\r\n            _unitOfWork = unitOfWork;\r\n            _meetingContext = meetingContext;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            await this._decorated.Handle(command, cancellationToken);\r\n\r\n            if (command is InternalCommandBase)\r\n            {\r\n                var internalCommand =\r\n                    await _meetingContext.InternalCommands.FirstOrDefaultAsync(\r\n                        x => x.Id == command.Id,\r\n                        cancellationToken: cancellationToken);\r\n\r\n                if (internalCommand != null)\r\n                {\r\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\r\n                }\r\n            }\r\n\r\n            await this._unitOfWork.CommitAsync(cancellationToken);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ICommandHandler<T, TResult> _decorated;\n        private readonly IUnitOfWork _unitOfWork;\n        private readonly MeetingsContext _meetingsContext;\n\n        public UnitOfWorkCommandHandlerWithResultDecorator(\n            ICommandHandler<T, TResult> decorated,\n            IUnitOfWork unitOfWork,\n            MeetingsContext meetingsContext)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var result = await this._decorated.Handle(command, cancellationToken);\n\n            if (command is InternalCommandBase<TResult>)\n            {\n                var internalCommand = await _meetingsContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\n\n                if (internalCommand != null)\n                {\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\n                }\n            }\n\n            await this._unitOfWork.CommitAsync(cancellationToken);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T> _decorated;\n\n        public ValidationCommandHandlerDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            await _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Quartz/QuartzModule.cs",
    "content": "﻿using Autofac;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Quartz\n{\n    public class QuartzModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterAssemblyTypes(ThisAssembly)\n                .Where(x => typeof(IJob).IsAssignableFrom(x)).InstancePerDependency();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Quartz/QuartzStartup.cs",
    "content": "﻿using System.Collections.Specialized;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Inbox;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox;\nusing Quartz;\nusing Quartz.Impl;\nusing Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Quartz\n{\n    internal static class QuartzStartup\n    {\n        private static IScheduler _scheduler;\n\n        internal static void Initialize(ILogger logger, long? internalProcessingPoolingInterval)\n        {\n            logger.Information(\"Quartz starting...\");\n\n            var schedulerConfiguration = new NameValueCollection();\n            schedulerConfiguration.Add(\"quartz.scheduler.instanceName\", \"Meetings\");\n\n            ISchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerConfiguration);\n            _scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult();\n\n            LogProvider.SetCurrentLogProvider(new SerilogLogProvider(logger));\n\n            _scheduler.Start().GetAwaiter().GetResult();\n\n            var processOutboxJob = JobBuilder.Create<ProcessOutboxJob>().Build();\n\n            ITrigger trigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            _scheduler\n                .ScheduleJob(processOutboxJob, trigger)\n                .GetAwaiter().GetResult();\n\n            var processInboxJob = JobBuilder.Create<ProcessInboxJob>().Build();\n\n            ITrigger processInboxTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            _scheduler\n                .ScheduleJob(processInboxJob, processInboxTrigger)\n                .GetAwaiter().GetResult();\n\n            var processInternalCommandsJob = JobBuilder.Create<ProcessInternalCommandsJob>().Build();\n\n            ITrigger triggerCommandsProcessing;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                triggerCommandsProcessing =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                triggerCommandsProcessing =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            _scheduler.ScheduleJob(processInternalCommandsJob, triggerCommandsProcessing).GetAwaiter().GetResult();\n\n            logger.Information(\"Quartz started.\");\n        }\n\n        internal static void StopQuartz()\n        {\n            _scheduler?.Shutdown();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Configuration/Quartz/SerilogLogProvider.cs",
    "content": "﻿using Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Quartz\n{\n    internal class SerilogLogProvider : ILogProvider\n    {\n        private readonly ILogger _logger;\n\n        internal SerilogLogProvider(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public Logger GetLogger(string name)\n        {\n            return (level, func, exception, parameters) =>\n            {\n                if (func == null)\n                {\n                    return true;\n                }\n\n                if (level == LogLevel.Debug || level == LogLevel.Trace)\n                {\n                    _logger.Debug(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Info)\n                {\n                    _logger.Information(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Warn)\n                {\n                    _logger.Warning(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Error)\n                {\n                    _logger.Error(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Fatal)\n                {\n                    _logger.Fatal(exception, func(), parameters);\n                }\n\n                return true;\n            };\n        }\n\n        public IDisposable OpenNestedContext(string message)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, string value)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, object value, bool destructure = false)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingCommentingConfigurations/MeetingCommentingConfigurationEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingCommentingConfigurations\n{\n    public class MeetingCommentingConfigurationEntityTypeConfiguration : IEntityTypeConfiguration<MeetingCommentingConfiguration>\n    {\n        public void Configure(EntityTypeBuilder<Modules.Meetings.Domain.MeetingCommentingConfigurations.MeetingCommentingConfiguration> builder)\n        {\n            builder.ToTable(\"MeetingCommentingConfigurations\", \"meetings\");\n\n            builder.HasKey(c => c.Id);\n            builder.HasOne<Meeting>()\n                .WithOne()\n                .HasForeignKey(nameof(MeetingCommentingConfiguration), \"_meetingId\")\n                .OnDelete(DeleteBehavior.Restrict);\n\n            builder.Property<MeetingId>(\"_meetingId\").HasColumnName(\"MeetingId\");\n            builder.Property<bool>(\"_isCommentingEnabled\").HasColumnName(\"IsCommentingEnabled\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingCommentingConfigurations/MeetingCommentingConfigurationRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingCommentingConfigurations\n{\n    public class MeetingCommentingConfigurationRepository : IMeetingCommentingConfigurationRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        public MeetingCommentingConfigurationRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(MeetingCommentingConfiguration meetingCommentingConfiguration)\n        {\n            await _meetingsContext.MeetingCommentingConfigurations.AddAsync(meetingCommentingConfiguration);\n        }\n\n        public async Task<MeetingCommentingConfiguration> GetByMeetingIdAsync(MeetingId meetingId)\n        {\n            return await _meetingsContext.MeetingCommentingConfigurations.SingleOrDefaultAsync(c =>\n                EF.Property<MeetingId>(c, \"_meetingId\") == meetingId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingComments/MeetingCommentEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingComments\n{\n    public class MeetingCommentEntityTypeConfiguration : IEntityTypeConfiguration<MeetingComment>\n    {\n        public void Configure(EntityTypeBuilder<MeetingComment> builder)\n        {\n            builder.ToTable(\"MeetingComments\", \"meetings\");\n\n            builder.HasKey(c => c.Id);\n\n            builder.Property<string>(\"_comment\").HasColumnName(\"Comment\");\n            builder.Property<MeetingId>(\"_meetingId\").HasColumnName(\"MeetingId\");\n            builder.Property<MemberId>(\"_authorId\").HasColumnName(\"AuthorId\");\n            builder.Property<MeetingCommentId>(\"_inReplyToCommentId\").HasColumnName(\"InReplyToCommentId\");\n            builder.Property<bool>(\"_isRemoved\").HasColumnName(\"IsRemoved\");\n            builder.Property<string>(\"_removedByReason\").HasColumnName(\"RemovedByReason\");\n            builder.Property<DateTime>(\"_createDate\").HasColumnName(\"CreateDate\");\n            builder.Property<DateTime?>(\"_editDate\").HasColumnName(\"EditDate\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingComments/MeetingCommentRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingComments\n{\n    public class MeetingCommentRepository : IMeetingCommentRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        public MeetingCommentRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(MeetingComment meetingComment)\n        {\n            await _meetingsContext.MeetingComments.AddAsync(meetingComment);\n        }\n\n        public async Task<MeetingComment> GetByIdAsync(MeetingCommentId meetingCommentId)\n        {\n            return await _meetingsContext.MeetingComments.FindAsync(meetingCommentId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingGroupProposals/MeetingGroupProposalEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingGroupProposals\n{\n    internal class MeetingGroupProposalEntityTypeConfiguration : IEntityTypeConfiguration<MeetingGroupProposal>\n    {\n        public void Configure(EntityTypeBuilder<MeetingGroupProposal> builder)\n        {\n            builder.ToTable(\"MeetingGroupProposals\", \"meetings\");\n\n            builder.HasKey(x => x.Id);\n            builder.Property(x => x.Id);\n\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n            builder.Property<string>(\"_description\").HasColumnName(\"Description\");\n            builder.Property<MemberId>(\"_proposalUserId\").HasColumnName(\"ProposalUserId\");\n            builder.Property<DateTime>(\"_proposalDate\").HasColumnName(\"ProposalDate\");\n\n            builder.OwnsOne<MeetingGroupLocation>(\"_location\", b =>\n            {\n                b.Property(p => p.City).HasColumnName(\"LocationCity\");\n                b.Property(p => p.CountryCode).HasColumnName(\"LocationCountryCode\");\n            });\n\n            builder.OwnsOne<MeetingGroupProposalStatus>(\"_status\", b =>\n            {\n                b.Property(p => p.Value).HasColumnName(\"StatusCode\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingGroupProposals/MeetingGroupProposalRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingGroupProposals\n{\n    internal class MeetingGroupProposalRepository : IMeetingGroupProposalRepository\n    {\n        private readonly MeetingsContext _context;\n\n        internal MeetingGroupProposalRepository(MeetingsContext context)\n        {\n            _context = context;\n        }\n\n        public async Task AddAsync(MeetingGroupProposal meetingGroupProposal)\n        {\n            await _context.MeetingGroupProposals.AddAsync(meetingGroupProposal);\n        }\n\n        public async Task<MeetingGroupProposal> GetByIdAsync(MeetingGroupProposalId meetingGroupProposalId)\n        {\n            return await _context.MeetingGroupProposals.FirstOrDefaultAsync(x => x.Id == meetingGroupProposalId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingGroups/MeetingGroupRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingGroups\n{\n    internal class MeetingGroupRepository : IMeetingGroupRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        internal MeetingGroupRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(MeetingGroup meetingGroup)\n        {\n            await _meetingsContext.MeetingGroups.AddAsync(meetingGroup);\n        }\n\n        public async Task<int> Commit()\n        {\n            return await _meetingsContext.SaveChangesAsync();\n        }\n\n        public async Task<MeetingGroup> GetByIdAsync(MeetingGroupId id)\n        {\n            return await _meetingsContext.MeetingGroups.FirstOrDefaultAsync(x => x.Id == id);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingGroups/MeetingGroupsEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingGroups\n{\n    internal class MeetingGroupsEntityTypeConfiguration : IEntityTypeConfiguration<MeetingGroup>\n    {\n        public void Configure(EntityTypeBuilder<MeetingGroup> builder)\n        {\n            builder.ToTable(\"MeetingGroups\", \"meetings\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n            builder.Property<string>(\"_description\").HasColumnName(\"Description\");\n            builder.Property<MemberId>(\"_creatorId\").HasColumnName(\"CreatorId\");\n            builder.Property<DateTime>(\"_createDate\").HasColumnName(\"CreateDate\");\n            builder.Property<DateTime?>(\"_paymentDateTo\").HasColumnName(\"PaymentDateTo\");\n\n            builder.OwnsOne<MeetingGroupLocation>(\"_location\", b =>\n            {\n                b.Property(p => p.City).HasColumnName(\"LocationCity\");\n                b.Property(p => p.CountryCode).HasColumnName(\"LocationCountryCode\");\n            });\n\n            builder.OwnsMany<MeetingGroupMember>(\"_members\", y =>\n            {\n                y.WithOwner().HasForeignKey(\"MeetingGroupId\");\n                y.ToTable(\"MeetingGroupMembers\", \"meetings\");\n                y.Property<MemberId>(\"MemberId\");\n                y.Property<MeetingGroupId>(\"MeetingGroupId\");\n                y.Property<DateTime>(\"JoinedDate\").HasColumnName(\"JoinedDate\");\n                y.HasKey(\"MemberId\", \"MeetingGroupId\", \"JoinedDate\");\n\n                y.Property<DateTime?>(\"_leaveDate\").HasColumnName(\"LeaveDate\");\n\n                y.Property<bool>(\"_isActive\").HasColumnName(\"IsActive\");\n\n                y.OwnsOne<MeetingGroupMemberRole>(\"_role\", b =>\n                {\n                    b.Property<string>(x => x.Value).HasColumnName(\"RoleCode\");\n                });\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingMemberCommentLikes/MeetingMemberCommentLikeEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingMemberCommentLikes\n{\n    public class MeetingMemberCommentLikeEntityTypeConfiguration : IEntityTypeConfiguration<MeetingMemberCommentLike>\n    {\n        public void Configure(EntityTypeBuilder<MeetingMemberCommentLike> builder)\n        {\n            builder.ToTable(\"MeetingMemberCommentLikes\", \"meetings\");\n\n            builder.HasKey(c => c.Id);\n\n            builder.Property<MeetingCommentId>(\"_meetingCommentId\").HasColumnName(\"MeetingCommentId\");\n            builder.Property<MemberId>(\"_memberId\").HasColumnName(\"MemberId\");\n\n            builder.HasOne<Member>()\n                .WithMany()\n                .HasForeignKey(\"_memberId\")\n                .OnDelete(DeleteBehavior.Restrict);\n\n            builder.HasOne<MeetingComment>()\n                .WithMany()\n                .HasForeignKey(\"_meetingCommentId\")\n                .OnDelete(DeleteBehavior.Restrict);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/MeetingMemberCommentLikes/MeetingMemberCommentLikeRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Dapper;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.MeetingMemberCommentLikes\n{\n    public class MeetingMemberCommentLikeRepository : IMeetingMemberCommentLikesRepository\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n        private readonly MeetingsContext _meetingsContext;\n\n        public MeetingMemberCommentLikeRepository(ISqlConnectionFactory sqlConnectionFactory, MeetingsContext meetingsContext)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(MeetingMemberCommentLike meetingMemberCommentLike)\n        {\n            await _meetingsContext.MeetingMemberCommentLikes.AddAsync(meetingMemberCommentLike);\n        }\n\n        public async Task<MeetingMemberCommentLike> GetAsync(MemberId memberId, MeetingCommentId meetingCommentId)\n        {\n            return await _meetingsContext.MeetingMemberCommentLikes.SingleOrDefaultAsync(l =>\n                EF.Property<MemberId>(l, \"_memberId\") == memberId\n                && EF.Property<MeetingCommentId>(l, \"_meetingCommentId\") == meetingCommentId);\n        }\n\n        public Task<int> CountMemberCommentLikesAsync(MemberId memberId, MeetingCommentId meetingCommentId)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = \"\"\"\n                               SELECT COUNT(*) \n                               FROM [meetings].[MeetingMemberCommentLikes] AS [Likes]\n                               WHERE [Likes].[MemberId] = @MemberId AND [Likes].[MeetingCommentId] = @MeetingCommentId\n                               \"\"\";\n\n            return connection.QuerySingleAsync<int>(\n                sql,\n                new\n                {\n                    memberId = memberId.Value,\n                    meetingCommentId = meetingCommentId.Value\n                });\n        }\n\n        public void Remove(MeetingMemberCommentLike meetingMemberCommentLike)\n        {\n            _meetingsContext.MeetingMemberCommentLikes.Remove(meetingMemberCommentLike);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Meetings/MeetingEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Meetings\n{\n    internal class MeetingEntityTypeConfiguration : IEntityTypeConfiguration<Meeting>\n    {\n        public void Configure(EntityTypeBuilder<Meeting> builder)\n        {\n            builder.ToTable(\"Meetings\", \"meetings\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<MeetingGroupId>(\"_meetingGroupId\").HasColumnName(\"MeetingGroupId\");\n            builder.Property<string>(\"_title\").HasColumnName(\"Title\");\n            builder.Property<string>(\"_description\").HasColumnName(\"Description\");\n            builder.Property<MemberId>(\"_creatorId\").HasColumnName(\"CreatorId\");\n            builder.Property<MemberId>(\"_changeMemberId\").HasColumnName(\"ChangeMemberId\");\n            builder.Property<DateTime>(\"_createDate\").HasColumnName(\"CreateDate\");\n            builder.Property<DateTime?>(\"_changeDate\").HasColumnName(\"ChangeDate\");\n            builder.Property<DateTime?>(\"_cancelDate\").HasColumnName(\"CancelDate\");\n            builder.Property<bool>(\"_isCanceled\").HasColumnName(\"IsCanceled\");\n            builder.Property<MemberId>(\"_cancelMemberId\").HasColumnName(\"CancelMemberId\");\n\n            builder.OwnsOne<MeetingTerm>(\"_term\", b =>\n            {\n                b.Property(p => p.StartDate).HasColumnName(\"TermStartDate\");\n                b.Property(p => p.EndDate).HasColumnName(\"TermEndDate\");\n            });\n\n            builder.OwnsOne<Term>(\"_rsvpTerm\", b =>\n            {\n                b.Property(p => p.StartDate).HasColumnName(\"RSVPTermStartDate\");\n                b.Property(p => p.EndDate).HasColumnName(\"RSVPTermEndDate\");\n            });\n\n            builder.OwnsOne<MoneyValue>(\"_eventFee\", b =>\n            {\n                b.Property(p => p.Value).HasColumnName(\"EventFeeValue\");\n                b.Property(p => p.Currency).HasColumnName(\"EventFeeCurrency\");\n            });\n\n            builder.OwnsOne<MeetingLocation>(\"_location\", b =>\n            {\n                b.Property(p => p.Name).HasColumnName(\"LocationName\");\n                b.Property(p => p.Address).HasColumnName(\"LocationAddress\");\n                b.Property(p => p.PostalCode).HasColumnName(\"LocationPostalCode\");\n                b.Property(p => p.City).HasColumnName(\"LocationCity\");\n            });\n\n            builder.OwnsMany<MeetingAttendee>(\"_attendees\", y =>\n            {\n                y.WithOwner().HasForeignKey(\"MeetingId\");\n                y.ToTable(\"MeetingAttendees\", \"meetings\");\n                y.Property<MemberId>(\"AttendeeId\");\n                y.Property<MeetingId>(\"MeetingId\");\n                y.Property<DateTime>(\"_decisionDate\").HasColumnName(\"DecisionDate\");\n                y.HasKey(\"AttendeeId\", \"MeetingId\", \"_decisionDate\");\n                y.Property<bool>(\"_decisionChanged\").HasColumnName(\"DecisionChanged\");\n                y.Property<int>(\"_guestsNumber\").HasColumnName(\"GuestsNumber\");\n                y.Property<DateTime?>(\"_decisionChangeDate\").HasColumnName(\"DecisionChangeDate\");\n                y.Property<bool>(\"_isRemoved\").HasColumnName(\"IsRemoved\");\n                y.Property<string>(\"_removingReason\").HasColumnName(\"RemovingReason\");\n                y.Property<MemberId>(\"_removingMemberId\").HasColumnName(\"RemovingMemberId\");\n                y.Property<DateTime?>(\"_removedDate\").HasColumnName(\"RemovedDate\");\n                y.Property<bool>(\"_isFeePaid\").HasColumnName(\"IsFeePaid\");\n\n                y.OwnsOne<MeetingAttendeeRole>(\"_role\", b =>\n                {\n                    b.Property(x => x.Value).HasColumnName(\"RoleCode\");\n                });\n\n                y.OwnsOne<MoneyValue>(\"_fee\", b =>\n                {\n                    b.Property(p => p.Value).HasColumnName(\"FeeValue\");\n                    b.Property(p => p.Currency).HasColumnName(\"FeeCurrency\");\n                });\n            });\n\n            builder.OwnsMany<MeetingNotAttendee>(\"_notAttendees\", y =>\n            {\n                y.WithOwner().HasForeignKey(\"MeetingId\");\n                y.ToTable(\"MeetingNotAttendees\", \"meetings\");\n                y.Property<MemberId>(\"MemberId\");\n                y.Property<MeetingId>(\"MeetingId\");\n                y.Property<DateTime>(\"_decisionDate\").HasColumnName(\"DecisionDate\");\n                y.HasKey(\"MemberId\", \"MeetingId\", \"_decisionDate\");\n                y.Property<bool>(\"_decisionChanged\").HasColumnName(\"DecisionChanged\");\n                y.Property<DateTime?>(\"_decisionChangeDate\").HasColumnName(\"DecisionChangeDate\");\n            });\n\n            builder.OwnsMany<MeetingWaitlistMember>(\"_waitlistMembers\", y =>\n            {\n                y.WithOwner().HasForeignKey(\"MeetingId\");\n                y.ToTable(\"MeetingWaitlistMembers\", \"meetings\");\n                y.Property<MemberId>(\"MemberId\");\n                y.Property<MeetingId>(\"MeetingId\");\n                y.Property<DateTime>(\"SignUpDate\").HasColumnName(\"SignUpDate\");\n                y.HasKey(\"MemberId\", \"MeetingId\", \"SignUpDate\");\n                y.Property<bool>(\"_isSignedOff\").HasColumnName(\"IsSignedOff\");\n                y.Property<DateTime?>(\"_signOffDate\").HasColumnName(\"SignOffDate\");\n\n                y.Property<bool>(\"_isMovedToAttendees\").HasColumnName(\"IsMovedToAttendees\");\n                y.Property<DateTime?>(\"_movedToAttendeesDate\").HasColumnName(\"MovedToAttendeesDate\");\n            });\n\n            builder.OwnsOne<MeetingLimits>(\"_meetingLimits\", meetingLimits =>\n            {\n                meetingLimits.Property(x => x.AttendeesLimit).HasColumnName(\"AttendeesLimit\");\n                meetingLimits.Property(x => x.GuestsLimit).HasColumnName(\"GuestsLimit\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Meetings/MeetingRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Meetings\n{\n    internal class MeetingRepository : IMeetingRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        internal MeetingRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(Meeting meeting)\n        {\n            await _meetingsContext.Meetings.AddAsync(meeting);\n        }\n\n        public async Task<Meeting> GetByIdAsync(MeetingId id)\n        {\n            return await _meetingsContext.Meetings.FindAsync(id);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Members/MemberEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Members\n{\n    internal class MemberEntityTypeConfiguration : IEntityTypeConfiguration<Member>\n    {\n        public void Configure(EntityTypeBuilder<Member> builder)\n        {\n            builder.ToTable(\"Members\", \"meetings\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_login\").HasColumnName(\"Login\");\n            builder.Property<string>(\"_email\").HasColumnName(\"Email\");\n            builder.Property<string>(\"_firstName\").HasColumnName(\"FirstName\");\n            builder.Property<string>(\"_lastName\").HasColumnName(\"LastName\");\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Members/MemberRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Members\n{\n    internal class MemberRepository : IMemberRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        internal MemberRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(Member member)\n        {\n            await _meetingsContext.Members.AddAsync(member);\n        }\n\n        public async Task<Member> GetByIdAsync(MemberId memberId)\n        {\n            return await _meetingsContext.Members.FirstOrDefaultAsync(x => x.Id == memberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Members/MemberSubscriptions/MemberSubscriptionEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Members.MemberSubscriptions\n{\n    internal class MemberSubscriptionEntityTypeConfiguration : IEntityTypeConfiguration<MemberSubscription>\n    {\n        public void Configure(EntityTypeBuilder<MemberSubscription> builder)\n        {\n            builder.ToTable(\"MemberSubscriptions\", \"meetings\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property(\"_expirationDate\").HasColumnName(\"ExpirationDate\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Domain/Members/MemberSubscriptions/MemberSubscriptionRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Domain.Members.MemberSubscriptions\n{\n    internal class MemberSubscriptionRepository : IMemberSubscriptionRepository\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        internal MemberSubscriptionRepository(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public async Task AddAsync(MemberSubscription member)\n        {\n            await _meetingsContext.MemberSubscriptions.AddAsync(member);\n        }\n\n        public async Task<MemberSubscription> GetByIdOptionalAsync(MemberSubscriptionId memberSubscriptionId)\n        {\n            return await _meetingsContext.MemberSubscriptions.FirstOrDefaultAsync(x => x.Id == memberSubscriptionId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/InternalCommands/InternalCommandEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.InternalCommands\n{\n    internal class InternalCommandEntityTypeConfiguration : IEntityTypeConfiguration<InternalCommand>\n    {\n        public void Configure(EntityTypeBuilder<InternalCommand> builder)\n        {\n            builder.ToTable(\"InternalCommands\", \"meetings\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/MeetingsContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.MemberSubscriptions;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure\n{\n    public class MeetingsContext : DbContext\n    {\n        public DbSet<MeetingGroup> MeetingGroups { get; set; }\n\n        public DbSet<Meeting> Meetings { get; set; }\n\n        public DbSet<MeetingGroupProposal> MeetingGroupProposals { get; set; }\n\n        public DbSet<OutboxMessage> OutboxMessages { get; set; }\n\n        public DbSet<InternalCommand> InternalCommands { get; set; }\n\n        public DbSet<Member> Members { get; set; }\n\n        public DbSet<MemberSubscription> MemberSubscriptions { get; set; }\n\n        public DbSet<MeetingComment> MeetingComments { get; set; }\n\n        public DbSet<MeetingCommentingConfiguration> MeetingCommentingConfigurations { get; set; }\n\n        public DbSet<MeetingMemberCommentLike> MeetingMemberCommentLikes { get; set; }\n\n        private readonly ILoggerFactory _loggerFactory;\n\n        public MeetingsContext(DbContextOptions options, ILoggerFactory loggerFactory)\n            : base(options)\n        {\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            // optionsBuilder.UseLoggerFactory(_loggerFactory).EnableSensitiveDataLogging();\n        }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n            => modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/MeetingsModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure\n{\n    public class MeetingsModule : IMeetingsModule\n    {\n        public async Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command)\n        {\n            return await CommandsExecutor.Execute(command);\n        }\n\n        public async Task ExecuteCommandAsync(ICommand command)\n        {\n            await CommandsExecutor.Execute(command);\n        }\n\n        public async Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)\n        {\n            using (var scope = MeetingsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n\n                return await mediator.Send(query);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Outbox/OutboxAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Outbox\n{\n    public class OutboxAccessor : IOutbox\n    {\n        private readonly MeetingsContext _meetingsContext;\n\n        internal OutboxAccessor(MeetingsContext meetingsContext)\n        {\n            _meetingsContext = meetingsContext;\n        }\n\n        public void Add(OutboxMessage message)\n        {\n            _meetingsContext.OutboxMessages.Add(message);\n        }\n\n        public Task Save()\n        {\n            return Task.CompletedTask; // Save is done automatically using EF Core Change Tracking mechanism during SaveChanges.\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Infrastructure/Outbox/OutboxMessageEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Outbox\n{\n    internal class OutboxMessageEntityTypeConfiguration : IEntityTypeConfiguration<OutboxMessage>\n    {\n        public void Configure(EntityTypeBuilder<OutboxMessage> builder)\n        {\n            builder.ToTable(\"OutboxMessages\", \"meetings\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/IntegrationEvents/CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Meetings/IntegrationEvents/MeetingAttendeeAddedIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents\n{\n    public class MeetingAttendeeAddedIntegrationEvent : IntegrationEvent\n    {\n        public Guid MeetingId { get; }\n\n        public Guid AttendeeId { get; }\n\n        public decimal? FeeValue { get; }\n\n        public string FeeCurrency { get; }\n\n        public MeetingAttendeeAddedIntegrationEvent(\n            Guid id,\n            DateTime occurredOn,\n            Guid meetingId,\n            Guid attendeeId,\n            decimal? feeValue,\n            string feeCurrency)\n            : base(id, occurredOn)\n        {\n            MeetingId = meetingId;\n            AttendeeId = attendeeId;\n            FeeValue = feeValue;\n            FeeCurrency = feeCurrency;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/IntegrationEvents/MeetingGroupProposedIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents\n{\n    public class MeetingGroupProposedIntegrationEvent : IntegrationEvent\n    {\n        public Guid MeetingGroupProposalId { get; }\n\n        public string Name { get; }\n\n        public string Description { get; }\n\n        public string LocationCity { get; }\n\n        public string LocationCountryCode { get; }\n\n        public Guid ProposalUserId { get; }\n\n        public DateTime ProposalDate { get; }\n\n        public MeetingGroupProposedIntegrationEvent(\n            Guid id,\n            DateTime occurredOn,\n            Guid meetingGroupProposalId,\n            string name,\n            string description,\n            string locationCity,\n            string locationCountryCode,\n            Guid proposalUserId,\n            DateTime proposalDate)\n            : base(id, occurredOn)\n        {\n            this.MeetingGroupProposalId = meetingGroupProposalId;\n            this.Name = name;\n            this.Description = description;\n            this.LocationCity = locationCity;\n            this.LocationCountryCode = locationCountryCode;\n            this.ProposalUserId = proposalUserId;\n            this.ProposalDate = proposalDate;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/IntegrationEvents/MemberCreatedIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents\n{\n    public class MemberCreatedIntegrationEvent : IntegrationEvent\n    {\n        public Guid MemberId { get; }\n\n        public MemberCreatedIntegrationEvent(Guid id, DateTime occurredOn, Guid memberId)\n            : base(id, occurredOn)\n        {\n            MemberId = memberId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/ArchTests/Application/ApplicationTests.cs",
    "content": "using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.ArchTests.SeedWork;\nusing FluentValidation;\nusing MediatR;\nusing NetArchTest.Rules;\nusing Newtonsoft.Json;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.ArchTests.Application\n{\n    [TestFixture]\n    public class ApplicationTests : TestBase\n    {\n        [Test]\n        public void Command_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(CommandBase))\n                .Or()\n                .Inherit(typeof(CommandBase<>))\n                .Or()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .Or()\n                .ImplementInterface(typeof(ICommand))\n                .Or()\n                .ImplementInterface(typeof(ICommand<>))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Query_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(typeof(IQuery<>)).GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void CommandHandler_Should_Have_Name_EndingWith_CommandHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(ICommandHandler<>))\n                    .Or()\n                .ImplementInterface(typeof(ICommandHandler<,>))\n                .And()\n                .DoNotHaveNameMatching(\".*Decorator.*\").Should()\n                .HaveNameEndingWith(\"CommandHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void QueryHandler_Should_Have_Name_EndingWith_QueryHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(IQueryHandler<,>))\n                .Should()\n                .HaveNameEndingWith(\"QueryHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Command_And_Query_Handlers_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                    .ImplementInterface(typeof(IQueryHandler<,>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<,>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void Validator_Should_Have_Name_EndingWith_Validator()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should()\n                .HaveNameEndingWith(\"Validator\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Validators_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void InternalCommand_Should_Have_Constructor_With_JsonConstructorAttribute()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n\n            foreach (var type in types)\n            {\n                bool hasJsonConstructorDefined = false;\n                var constructors = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var jsonConstructorAttribute = constructorInfo.GetCustomAttributes(typeof(JsonConstructorAttribute), false);\n                    if (jsonConstructorAttribute.Length > 0)\n                    {\n                        hasJsonConstructorDefined = true;\n                        break;\n                    }\n                }\n\n                if (!hasJsonConstructorDefined)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void MediatR_RequestHandler_Should_NotBe_Used_Directly()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().DoNotHaveName(\"ICommandHandler`1\")\n                .Should().ImplementInterface(typeof(IRequestHandler<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                bool isCommandHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));\n                bool isCommandWithResultHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<,>));\n                bool isQueryHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(IQueryHandler<,>));\n                if (!isCommandHandler && !isCommandWithResultHandler && !isQueryHandler)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Command_With_Result_Should_Not_Return_Unit()\n        {\n            Type commandWithResultHandlerType = typeof(ICommandHandler<,>);\n            IEnumerable<Type> types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(commandWithResultHandlerType)\n                .GetTypes().ToList();\n\n            List<Type> failingTypes = [];\n            foreach (Type type in types)\n            {\n                Type interfaceType = type.GetInterface(commandWithResultHandlerType.Name);\n                if (interfaceType?.GenericTypeArguments[1] == typeof(Unit))\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/ArchTests/CompanyName.MyMeetings.Modules.Meetings.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Meetings/Tests/ArchTests/Domain/DomainTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.ArchTests.Domain\n{\n    public class DomainTests : TestBase\n    {\n        [Test]\n        public void DomainEvent_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                    .Inherit(typeof(DomainEventBase))\n                        .Or()\n                    .ImplementInterface(typeof(IDomainEvent))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void ValueObject_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Entity_Which_Is_Not_Aggregate_Root_Cannot_Have_Public_Members()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity))\n                .And().DoNotImplementInterface(typeof(IAggregateRoot)).GetTypes();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.Public |\n                                              BindingFlags.Instance |\n                                              BindingFlags.Static;\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                var publicFields = type.GetFields(bindingFlags);\n                var publicProperties = type.GetProperties(bindingFlags);\n                var publicMethods = type.GetMethods(bindingFlags);\n\n                if (publicFields.Any() || publicProperties.Any() || publicMethods.Any())\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Cannot_Have_Reference_To_Other_AggregateRoot()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            var aggregateRoots = Types.InAssembly(DomainAssembly)\n                .That().ImplementInterface(typeof(IAggregateRoot)).GetTypes().ToList();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.NonPublic |\n                                              BindingFlags.Instance;\n\n            List<Type> failingTypes = [];\n            foreach (var type in entityTypes)\n            {\n                var fields = type.GetFields(bindingFlags);\n\n                foreach (var field in fields)\n                {\n                    if (aggregateRoots.Contains(field.FieldType) ||\n                        field.FieldType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n\n                var properties = type.GetProperties(bindingFlags);\n                foreach (var property in properties)\n                {\n                    if (aggregateRoots.Contains(property.PropertyType) ||\n                        property.PropertyType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Should_Have_Parameterless_Private_Constructor()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in entityTypes)\n            {\n                bool hasPrivateParameterlessConstructor = false;\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (constructorInfo.IsPrivate && constructorInfo.GetParameters().Length == 0)\n                    {\n                        hasPrivateParameterlessConstructor = true;\n                    }\n                }\n\n                if (!hasPrivateParameterlessConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Domain_Object_Should_Have_Only_Private_Constructors()\n        {\n            var domainObjectTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                        .Inherit(typeof(Entity))\n                    .Or()\n                        .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var domainObjectType in domainObjectTypes)\n            {\n                var constructors = domainObjectType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (!constructorInfo.IsPrivate)\n                    {\n                        failingTypes.Add(domainObjectType);\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void ValueObject_Should_Have_Private_Constructor_With_Parameters_For_His_State()\n        {\n            var valueObjects = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in valueObjects)\n            {\n                bool hasExpectedConstructor = false;\n\n                const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                                  BindingFlags.Public |\n                                                  BindingFlags.Instance;\n                var names = entityType.GetFields(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                var propertyNames = entityType.GetProperties(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                names.AddRange(propertyNames);\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var parameters = constructorInfo.GetParameters().Select(x => x.Name.ToLower()).ToList();\n\n                    if (names.Intersect(parameters).Count() == names.Count)\n                    {\n                        hasExpectedConstructor = true;\n                        break;\n                    }\n                }\n\n                if (!hasExpectedConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void DomainEvent_Should_Have_DomainEventPostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(DomainEventBase))\n                .Or()\n                .ImplementInterface(typeof(IDomainEvent))\n                .Should().HaveNameEndingWith(\"DomainEvent\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void BusinessRule_Should_Have_RulePostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .ImplementInterface(typeof(IBusinessRule))\n                .Should().HaveNameEndingWith(\"Rule\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/ArchTests/Module/LayersTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.ArchTests.Module\n{\n    [TestFixture]\n    public class LayersTests : TestBase\n    {\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToApplicationLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void ApplicationLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .Should()\n                .NotHaveDependencyOn(InfrastructureAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApplicationAssembly => typeof(CommandBase).Assembly;\n\n        protected static Assembly DomainAssembly => typeof(MeetingGroupProposal).Assembly;\n\n        protected static Assembly InfrastructureAssembly => typeof(MeetingsContext).Assembly;\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/Countries/0001_SeedCountries.sql",
    "content": "﻿INSERT INTO [meetings].[Countries] VALUES ('AD', 'Andorra')\nINSERT INTO [meetings].[Countries] VALUES ('AE', 'United Arab Emirates')\nINSERT INTO [meetings].[Countries] VALUES ('AF', 'Afghanistan')\nINSERT INTO [meetings].[Countries] VALUES ('AG', 'Antigua and Barbuda')\nINSERT INTO [meetings].[Countries] VALUES ('AI', 'Anguilla')\nINSERT INTO [meetings].[Countries] VALUES ('AL', 'Albania')\nINSERT INTO [meetings].[Countries] VALUES ('AM', 'Armenia')\nINSERT INTO [meetings].[Countries] VALUES ('AN', 'Netherlands Antilles')\nINSERT INTO [meetings].[Countries] VALUES ('AO', 'Angola')\nINSERT INTO [meetings].[Countries] VALUES ('AQ', 'Antarctica')\nINSERT INTO [meetings].[Countries] VALUES ('AR', 'Argentina')\nINSERT INTO [meetings].[Countries] VALUES ('AS', 'American Samoa')\nINSERT INTO [meetings].[Countries] VALUES ('AT', 'Austria')\nINSERT INTO [meetings].[Countries] VALUES ('AU', 'Australia')\nINSERT INTO [meetings].[Countries] VALUES ('AW', 'Aruba')\nINSERT INTO [meetings].[Countries] VALUES ('AX', 'Aland Islands')\nINSERT INTO [meetings].[Countries] VALUES ('AZ', 'Azerbaijan')\nINSERT INTO [meetings].[Countries] VALUES ('BA', 'Bosnia and Herzegovina')\nINSERT INTO [meetings].[Countries] VALUES ('BB', 'Barbados')\nINSERT INTO [meetings].[Countries] VALUES ('BD', 'Bangladesh')\nINSERT INTO [meetings].[Countries] VALUES ('BE', 'Belgium')\nINSERT INTO [meetings].[Countries] VALUES ('BF', 'Burkina Faso')\nINSERT INTO [meetings].[Countries] VALUES ('BG', 'Bulgaria')\nINSERT INTO [meetings].[Countries] VALUES ('BH', 'Bahrain')\nINSERT INTO [meetings].[Countries] VALUES ('BI', 'Burundi')\nINSERT INTO [meetings].[Countries] VALUES ('BJ', 'Benin')\nINSERT INTO [meetings].[Countries] VALUES ('BM', 'Bermuda')\nINSERT INTO [meetings].[Countries] VALUES ('BN', 'Brunei Darussalam')\nINSERT INTO [meetings].[Countries] VALUES ('BO', 'Bolivia')\nINSERT INTO [meetings].[Countries] VALUES ('BR', 'Brazil')\nINSERT INTO [meetings].[Countries] VALUES ('BS', 'Bahamas')\nINSERT INTO [meetings].[Countries] VALUES ('BT', 'Bhutan')\nINSERT INTO [meetings].[Countries] VALUES ('BV', 'Bouvet Island')\nINSERT INTO [meetings].[Countries] VALUES ('BW', 'Botswana')\nINSERT INTO [meetings].[Countries] VALUES ('BY', 'Belarus')\nINSERT INTO [meetings].[Countries] VALUES ('BZ', 'Belize')\nINSERT INTO [meetings].[Countries] VALUES ('CA', 'Canada')\nINSERT INTO [meetings].[Countries] VALUES ('CC', 'Cocos (Keeling) Islands')\nINSERT INTO [meetings].[Countries] VALUES ('CD', 'Congo, The Democratic Republic of the')\nINSERT INTO [meetings].[Countries] VALUES ('CF', 'Central African Republic')\nINSERT INTO [meetings].[Countries] VALUES ('CG', 'Congo')\nINSERT INTO [meetings].[Countries] VALUES ('CH', 'Switzerland')\nINSERT INTO [meetings].[Countries] VALUES ('CI', 'Cote DIvoire')\nINSERT INTO [meetings].[Countries] VALUES ('CK', 'Cook Islands')\nINSERT INTO [meetings].[Countries] VALUES ('CL', 'Chile')\nINSERT INTO [meetings].[Countries] VALUES ('CM', 'Cameroon')\nINSERT INTO [meetings].[Countries] VALUES ('CN', 'China')\nINSERT INTO [meetings].[Countries] VALUES ('CO', 'Colombia')\nINSERT INTO [meetings].[Countries] VALUES ('CR', 'Costa Rica')\nINSERT INTO [meetings].[Countries] VALUES ('CU', 'Cuba')\nINSERT INTO [meetings].[Countries] VALUES ('CV', 'Cape Verde')\nINSERT INTO [meetings].[Countries] VALUES ('CX', 'Christmas Island')\nINSERT INTO [meetings].[Countries] VALUES ('CY', 'Cyprus')\nINSERT INTO [meetings].[Countries] VALUES ('CZ', 'Czech Republic')\nINSERT INTO [meetings].[Countries] VALUES ('DE', 'Germany')\nINSERT INTO [meetings].[Countries] VALUES ('DJ', 'Djibouti')\nINSERT INTO [meetings].[Countries] VALUES ('DK', 'Denmark')\nINSERT INTO [meetings].[Countries] VALUES ('DM', 'Dominica')\nINSERT INTO [meetings].[Countries] VALUES ('DO', 'Dominican Republic')\nINSERT INTO [meetings].[Countries] VALUES ('DZ', 'Algeria')\nINSERT INTO [meetings].[Countries] VALUES ('EC', 'Ecuador')\nINSERT INTO [meetings].[Countries] VALUES ('EE', 'Estonia')\nINSERT INTO [meetings].[Countries] VALUES ('EG', 'Egypt')\nINSERT INTO [meetings].[Countries] VALUES ('EH', 'Western Sahara')\nINSERT INTO [meetings].[Countries] VALUES ('ER', 'Eritrea')\nINSERT INTO [meetings].[Countries] VALUES ('ES', 'Spain')\nINSERT INTO [meetings].[Countries] VALUES ('ET', 'Ethiopia')\nINSERT INTO [meetings].[Countries] VALUES ('FI', 'Finland')\nINSERT INTO [meetings].[Countries] VALUES ('FJ', 'Fiji')\nINSERT INTO [meetings].[Countries] VALUES ('FK', 'Falkland Islands (Malvinas)')\nINSERT INTO [meetings].[Countries] VALUES ('FM', 'Micronesia, Federated States of')\nINSERT INTO [meetings].[Countries] VALUES ('FO', 'Faroe Islands')\nINSERT INTO [meetings].[Countries] VALUES ('FR', 'France')\nINSERT INTO [meetings].[Countries] VALUES ('GA', 'Gabon')\nINSERT INTO [meetings].[Countries] VALUES ('GB', 'United Kingdom')\nINSERT INTO [meetings].[Countries] VALUES ('GD', 'Grenada')\nINSERT INTO [meetings].[Countries] VALUES ('GE', 'Georgia')\nINSERT INTO [meetings].[Countries] VALUES ('GF', 'French Guiana')\nINSERT INTO [meetings].[Countries] VALUES ('GG', 'Guernsey')\nINSERT INTO [meetings].[Countries] VALUES ('GH', 'Ghana')\nINSERT INTO [meetings].[Countries] VALUES ('GI', 'Gibraltar')\nINSERT INTO [meetings].[Countries] VALUES ('GL', 'Greenland')\nINSERT INTO [meetings].[Countries] VALUES ('GM', 'Gambia')\nINSERT INTO [meetings].[Countries] VALUES ('GN', 'Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('GP', 'Guadeloupe')\nINSERT INTO [meetings].[Countries] VALUES ('GQ', 'Equatorial Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('GR', 'Greece')\nINSERT INTO [meetings].[Countries] VALUES ('GS', 'South Georgia and the South Sandwich Islands')\nINSERT INTO [meetings].[Countries] VALUES ('GT', 'Guatemala')\nINSERT INTO [meetings].[Countries] VALUES ('GU', 'Guam')\nINSERT INTO [meetings].[Countries] VALUES ('GW', 'Guinea-Bissau')\nINSERT INTO [meetings].[Countries] VALUES ('GY', 'Guyana')\nINSERT INTO [meetings].[Countries] VALUES ('HK', 'Hong Kong')\nINSERT INTO [meetings].[Countries] VALUES ('HM', 'Heard Island and Mcdonald Islands')\nINSERT INTO [meetings].[Countries] VALUES ('HN', 'Honduras')\nINSERT INTO [meetings].[Countries] VALUES ('HR', 'Croatia')\nINSERT INTO [meetings].[Countries] VALUES ('HT', 'Haiti')\nINSERT INTO [meetings].[Countries] VALUES ('HU', 'Hungary')\nINSERT INTO [meetings].[Countries] VALUES ('ID', 'Indonesia')\nINSERT INTO [meetings].[Countries] VALUES ('IE', 'Ireland')\nINSERT INTO [meetings].[Countries] VALUES ('IL', 'Israel')\nINSERT INTO [meetings].[Countries] VALUES ('IM', 'Isle of Man')\nINSERT INTO [meetings].[Countries] VALUES ('IN', 'India')\nINSERT INTO [meetings].[Countries] VALUES ('IO', 'British Indian Ocean Territory')\nINSERT INTO [meetings].[Countries] VALUES ('IQ', 'Iraq')\nINSERT INTO [meetings].[Countries] VALUES ('IR', 'Iran, Islamic Republic Of')\nINSERT INTO [meetings].[Countries] VALUES ('IS', 'Iceland')\nINSERT INTO [meetings].[Countries] VALUES ('IT', 'Italy')\nINSERT INTO [meetings].[Countries] VALUES ('JE', 'Jersey')\nINSERT INTO [meetings].[Countries] VALUES ('JM', 'Jamaica')\nINSERT INTO [meetings].[Countries] VALUES ('JO', 'Jordan')\nINSERT INTO [meetings].[Countries] VALUES ('JP', 'Japan')\nINSERT INTO [meetings].[Countries] VALUES ('KE', 'Kenya')\nINSERT INTO [meetings].[Countries] VALUES ('KG', 'Kyrgyzstan')\nINSERT INTO [meetings].[Countries] VALUES ('KH', 'Cambodia')\nINSERT INTO [meetings].[Countries] VALUES ('KI', 'Kiribati')\nINSERT INTO [meetings].[Countries] VALUES ('KM', 'Comoros')\nINSERT INTO [meetings].[Countries] VALUES ('KN', 'Saint Kitts and Nevis')\nINSERT INTO [meetings].[Countries] VALUES ('KP', 'Korea, Democratic PeopleS Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('KR', 'Korea, Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('KW', 'Kuwait')\nINSERT INTO [meetings].[Countries] VALUES ('KY', 'Cayman Islands')\nINSERT INTO [meetings].[Countries] VALUES ('KZ', 'Kazakhstan')\nINSERT INTO [meetings].[Countries] VALUES ('LA', 'Lao PeopleS Democratic Republic')\nINSERT INTO [meetings].[Countries] VALUES ('LB', 'Lebanon')\nINSERT INTO [meetings].[Countries] VALUES ('LC', 'Saint Lucia')\nINSERT INTO [meetings].[Countries] VALUES ('LI', 'Liechtenstein')\nINSERT INTO [meetings].[Countries] VALUES ('LK', 'Sri Lanka')\nINSERT INTO [meetings].[Countries] VALUES ('LR', 'Liberia')\nINSERT INTO [meetings].[Countries] VALUES ('LS', 'Lesotho')\nINSERT INTO [meetings].[Countries] VALUES ('LT', 'Lithuania')\nINSERT INTO [meetings].[Countries] VALUES ('LU', 'Luxembourg')\nINSERT INTO [meetings].[Countries] VALUES ('LV', 'Latvia')\nINSERT INTO [meetings].[Countries] VALUES ('LY', 'Libyan Arab Jamahiriya')\nINSERT INTO [meetings].[Countries] VALUES ('MA', 'Morocco')\nINSERT INTO [meetings].[Countries] VALUES ('MC', 'Monaco')\nINSERT INTO [meetings].[Countries] VALUES ('MD', 'Moldova, Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('ME', 'Montenegro')\nINSERT INTO [meetings].[Countries] VALUES ('MG', 'Madagascar')\nINSERT INTO [meetings].[Countries] VALUES ('MH', 'Marshall Islands')\nINSERT INTO [meetings].[Countries] VALUES ('MK', 'Macedonia, The Former Yugoslav Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('ML', 'Mali')\nINSERT INTO [meetings].[Countries] VALUES ('MM', 'Myanmar')\nINSERT INTO [meetings].[Countries] VALUES ('MN', 'Mongolia')\nINSERT INTO [meetings].[Countries] VALUES ('MO', 'Macao')\nINSERT INTO [meetings].[Countries] VALUES ('MP', 'Northern Mariana Islands')\nINSERT INTO [meetings].[Countries] VALUES ('MQ', 'Martinique')\nINSERT INTO [meetings].[Countries] VALUES ('MR', 'Mauritania')\nINSERT INTO [meetings].[Countries] VALUES ('MS', 'Montserrat')\nINSERT INTO [meetings].[Countries] VALUES ('MT', 'Malta')\nINSERT INTO [meetings].[Countries] VALUES ('MU', 'Mauritius')\nINSERT INTO [meetings].[Countries] VALUES ('MV', 'Maldives')\nINSERT INTO [meetings].[Countries] VALUES ('MW', 'Malawi')\nINSERT INTO [meetings].[Countries] VALUES ('MX', 'Mexico')\nINSERT INTO [meetings].[Countries] VALUES ('MY', 'Malaysia')\nINSERT INTO [meetings].[Countries] VALUES ('MZ', 'Mozambique')\nINSERT INTO [meetings].[Countries] VALUES ('NA', 'Namibia')\nINSERT INTO [meetings].[Countries] VALUES ('NC', 'New Caledonia')\nINSERT INTO [meetings].[Countries] VALUES ('NE', 'Niger')\nINSERT INTO [meetings].[Countries] VALUES ('NF', 'Norfolk Island')\nINSERT INTO [meetings].[Countries] VALUES ('NG', 'Nigeria')\nINSERT INTO [meetings].[Countries] VALUES ('NI', 'Nicaragua')\nINSERT INTO [meetings].[Countries] VALUES ('NL', 'Netherlands')\nINSERT INTO [meetings].[Countries] VALUES ('NO', 'Norway')\nINSERT INTO [meetings].[Countries] VALUES ('NP', 'Nepal')\nINSERT INTO [meetings].[Countries] VALUES ('NR', 'Nauru')\nINSERT INTO [meetings].[Countries] VALUES ('NU', 'Niue')\nINSERT INTO [meetings].[Countries] VALUES ('NZ', 'New Zealand')\nINSERT INTO [meetings].[Countries] VALUES ('OM', 'Oman')\nINSERT INTO [meetings].[Countries] VALUES ('PA', 'Panama')\nINSERT INTO [meetings].[Countries] VALUES ('PE', 'Peru')\nINSERT INTO [meetings].[Countries] VALUES ('PF', 'French Polynesia')\nINSERT INTO [meetings].[Countries] VALUES ('PG', 'Papua New Guinea')\nINSERT INTO [meetings].[Countries] VALUES ('PH', 'Philippines')\nINSERT INTO [meetings].[Countries] VALUES ('PK', 'Pakistan')\nINSERT INTO [meetings].[Countries] VALUES ('PL', 'Poland')\nINSERT INTO [meetings].[Countries] VALUES ('PM', 'Saint Pierre and Miquelon')\nINSERT INTO [meetings].[Countries] VALUES ('PN', 'Pitcairn')\nINSERT INTO [meetings].[Countries] VALUES ('PR', 'Puerto Rico')\nINSERT INTO [meetings].[Countries] VALUES ('PS', 'Palestinian Territory, Occupied')\nINSERT INTO [meetings].[Countries] VALUES ('PT', 'Portugal')\nINSERT INTO [meetings].[Countries] VALUES ('PW', 'Palau')\nINSERT INTO [meetings].[Countries] VALUES ('PY', 'Paraguay')\nINSERT INTO [meetings].[Countries] VALUES ('QA', 'Qatar')\nINSERT INTO [meetings].[Countries] VALUES ('RE', 'Reunion')\nINSERT INTO [meetings].[Countries] VALUES ('RO', 'Romania')\nINSERT INTO [meetings].[Countries] VALUES ('RS', 'Serbia')\nINSERT INTO [meetings].[Countries] VALUES ('RU', 'Russian Federation')\nINSERT INTO [meetings].[Countries] VALUES ('RW', 'RWANDA')\nINSERT INTO [meetings].[Countries] VALUES ('SA', 'Saudi Arabia')\nINSERT INTO [meetings].[Countries] VALUES ('SB', 'Solomon Islands')\nINSERT INTO [meetings].[Countries] VALUES ('SC', 'Seychelles')\nINSERT INTO [meetings].[Countries] VALUES ('SD', 'Sudan')\nINSERT INTO [meetings].[Countries] VALUES ('SE', 'Sweden')\nINSERT INTO [meetings].[Countries] VALUES ('SG', 'Singapore')\nINSERT INTO [meetings].[Countries] VALUES ('SH', 'Saint Helena')\nINSERT INTO [meetings].[Countries] VALUES ('SI', 'Slovenia')\nINSERT INTO [meetings].[Countries] VALUES ('SJ', 'Svalbard and Jan Mayen')\nINSERT INTO [meetings].[Countries] VALUES ('SK', 'Slovakia')\nINSERT INTO [meetings].[Countries] VALUES ('SL', 'Sierra Leone')\nINSERT INTO [meetings].[Countries] VALUES ('SM', 'San Marino')\nINSERT INTO [meetings].[Countries] VALUES ('SN', 'Senegal')\nINSERT INTO [meetings].[Countries] VALUES ('SO', 'Somalia')\nINSERT INTO [meetings].[Countries] VALUES ('SR', 'Suriname')\nINSERT INTO [meetings].[Countries] VALUES ('ST', 'Sao Tome and Principe')\nINSERT INTO [meetings].[Countries] VALUES ('SV', 'El Salvador')\nINSERT INTO [meetings].[Countries] VALUES ('SY', 'Syrian Arab Republic')\nINSERT INTO [meetings].[Countries] VALUES ('SZ', 'Swaziland')\nINSERT INTO [meetings].[Countries] VALUES ('TC', 'Turks and Caicos Islands')\nINSERT INTO [meetings].[Countries] VALUES ('TD', 'Chad')\nINSERT INTO [meetings].[Countries] VALUES ('TF', 'French Southern Territories')\nINSERT INTO [meetings].[Countries] VALUES ('TG', 'Togo')\nINSERT INTO [meetings].[Countries] VALUES ('TH', 'Thailand')\nINSERT INTO [meetings].[Countries] VALUES ('TJ', 'Tajikistan')\nINSERT INTO [meetings].[Countries] VALUES ('TK', 'Tokelau')\nINSERT INTO [meetings].[Countries] VALUES ('TL', 'Timor-Leste')\nINSERT INTO [meetings].[Countries] VALUES ('TM', 'Turkmenistan')\nINSERT INTO [meetings].[Countries] VALUES ('TN', 'Tunisia')\nINSERT INTO [meetings].[Countries] VALUES ('TO', 'Tonga')\nINSERT INTO [meetings].[Countries] VALUES ('TR', 'Turkey')\nINSERT INTO [meetings].[Countries] VALUES ('TT', 'Trinidad and Tobago')\nINSERT INTO [meetings].[Countries] VALUES ('TV', 'Tuvalu')\nINSERT INTO [meetings].[Countries] VALUES ('TW', 'Taiwan, Province of China')\nINSERT INTO [meetings].[Countries] VALUES ('TZ', 'Tanzania, United Republic of')\nINSERT INTO [meetings].[Countries] VALUES ('UA', 'Ukraine')\nINSERT INTO [meetings].[Countries] VALUES ('UG', 'Uganda')\nINSERT INTO [meetings].[Countries] VALUES ('UM', 'United States Minor Outlying Islands')\nINSERT INTO [meetings].[Countries] VALUES ('US', 'United States')\nINSERT INTO [meetings].[Countries] VALUES ('UY', 'Uruguay')\nINSERT INTO [meetings].[Countries] VALUES ('UZ', 'Uzbekistan')\nINSERT INTO [meetings].[Countries] VALUES ('VA', 'Holy See (Vatican City State)')\nINSERT INTO [meetings].[Countries] VALUES ('VC', 'Saint Vincent and the Grenadines')\nINSERT INTO [meetings].[Countries] VALUES ('VE', 'Venezuela')\nINSERT INTO [meetings].[Countries] VALUES ('VG', 'Virgin Islands, British')\nINSERT INTO [meetings].[Countries] VALUES ('VI', 'Virgin Islands, U.S.')\nINSERT INTO [meetings].[Countries] VALUES ('VN', 'Viet Nam')\nINSERT INTO [meetings].[Countries] VALUES ('VU', 'Vanuatu')\nINSERT INTO [meetings].[Countries] VALUES ('WF', 'Wallis and Futuna')\nINSERT INTO [meetings].[Countries] VALUES ('WS', 'Samoa')\nINSERT INTO [meetings].[Countries] VALUES ('YE', 'Yemen')\nINSERT INTO [meetings].[Countries] VALUES ('YT', 'Mayotte')\nINSERT INTO [meetings].[Countries] VALUES ('ZA', 'South Africa')\nINSERT INTO [meetings].[Countries] VALUES ('ZM', 'Zambia')\nINSERT INTO [meetings].[Countries] VALUES ('ZW', 'Zimbabwe')\n"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/Countries/GetCountriesTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Countries;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Countries\n{\n    [TestFixture]\n    public class GetCountriesTests : TestBase\n    {\n        [Test]\n        public async Task GetCountriesTest()\n        {\n            // Arrange\n            await ExecuteScript(\"Countries/0001_SeedCountries.sql\");\n\n            // Act\n            var countries = await MeetingsModule.ExecuteQueryAsync(new GetAllCountriesQuery());\n\n            // Assert\n            Assert.That(countries, Is.Not.Empty);\n            Assert.That(countries.Any(x => x.Code == \"PL\"));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentLikes/AddMeetingCommentLikeTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentLike;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingCommentLikers;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentLikes\n{\n    [TestFixture]\n    public class AddMeetingCommentLikeTests : TestBase\n    {\n        [Test]\n        public async Task AddMeetingCommentLike_WhenDataIsValid_IsSuccess()\n        {\n            // Arrange\n            await MeetingsModule.ExecuteCommandAsync(\n                new CreateMemberCommand(\n                    Guid.NewGuid(),\n                    ExecutionContext.UserId,\n                    \"ivan_petrov\",\n                    \"ivan@mail.com\",\n                    \"Ivan\",\n                    \"Petrov\",\n                    \"Ivan Petrov\"));\n\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n            var meetingCommentId = await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(meetingId, \"The meeting was awesome.\"));\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentLikeCommand(meetingCommentId));\n\n            // Assert\n            var meetingCommentLikers = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentLikersQuery(meetingCommentId));\n            Assert.That(meetingCommentLikers.Count, Is.EqualTo(1));\n            Assert.That(meetingCommentLikers.Single().Id, Is.EqualTo(ExecutionContext.UserId));\n\n            await AssertEventually(\n                new GetMeetingCommentsProbe(MeetingsModule, meetingId, meetingCommentId, expectedCommentLikesCount: 1),\n                10000);\n        }\n\n        [Test]\n        public void AddMeetingCommentLike_WhenCommentNotExists_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentLikeCommand(meetingCommentId: Guid.NewGuid()));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentLikes/GetLikedMeetingCommentProbe.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentLikes\n{\n    public class GetLikedMeetingCommentProbe : IProbe\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        private readonly Guid _meetingId;\n\n        private readonly Guid _likedMeetingCommentId;\n\n        private List<MeetingCommentDto> _meetingComments;\n\n        public GetLikedMeetingCommentProbe(IMeetingsModule meetingsModule, Guid meetingId, Guid likedMeetingCommentId)\n        {\n            _meetingsModule = meetingsModule;\n            _meetingId = meetingId;\n            _likedMeetingCommentId = likedMeetingCommentId;\n        }\n\n        public bool IsSatisfied() => _meetingComments != null &&\n                                     _meetingComments.Any(c => c.Id == _likedMeetingCommentId && c.LikesCount == 1);\n\n        public async Task SampleAsync()\n        {\n            _meetingComments = await _meetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(_meetingId));\n        }\n\n        public string DescribeFailureTo() => \"MeetingComment read model is not in expected state\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentLikes/GetMeetingCommentsProbe.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentLikes\n{\n    public class GetMeetingCommentsProbe : IProbe\n    {\n        private readonly IMeetingsModule _meetingsModule;\n\n        private readonly Guid _meetingId;\n\n        private readonly Guid _likedMeetingCommentId;\n\n        private readonly int _expectedCommentLikesCount;\n\n        private List<MeetingCommentDto> _meetingComments;\n\n        public GetMeetingCommentsProbe(\n            IMeetingsModule meetingsModule,\n            Guid meetingId,\n            Guid likedMeetingCommentId,\n            int expectedCommentLikesCount)\n        {\n            _meetingsModule = meetingsModule;\n            _meetingId = meetingId;\n            _likedMeetingCommentId = likedMeetingCommentId;\n            _expectedCommentLikesCount = expectedCommentLikesCount;\n        }\n\n        public bool IsSatisfied() => _meetingComments != null &&\n                                     _meetingComments.Any(c => c.Id == _likedMeetingCommentId\n                                                               && c.LikesCount == _expectedCommentLikesCount);\n\n        public async Task SampleAsync()\n        {\n            _meetingComments = await _meetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(_meetingId));\n        }\n\n        public string DescribeFailureTo() => \"MeetingComment read model is not in expected state\";\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentLikes/RemoveMeetingCommentLikeTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentLike;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingCommentLikers;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingCommentLike;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentLikes\n{\n    [TestFixture]\n    public class RemoveMeetingCommentLikeTests : TestBase\n    {\n        [Test]\n        public async Task UnlikeMeetingComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            await MeetingsModule.ExecuteCommandAsync(\n                new CreateMemberCommand(\n                    Guid.NewGuid(),\n                    ExecutionContext.UserId,\n                    \"ivan_petrov\",\n                    \"ivan@mail.com\",\n                    \"Ivan\",\n                    \"Petrov\",\n                    \"Ivan Petrov\"));\n\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n\n            var meetingCommentId = await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(meetingId, \"The meeting was awesome.\"));\n\n            await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentLikeCommand(meetingCommentId));\n\n            await AssertEventually(\n                new GetMeetingCommentsProbe(MeetingsModule, meetingId, meetingCommentId, expectedCommentLikesCount: 1),\n                10000);\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new RemoveMeetingCommentLikeCommand(meetingCommentId));\n\n            // Assert\n            var meetingCommentLikers = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentLikersQuery(meetingCommentId));\n            Assert.That(meetingCommentLikers.Count, Is.EqualTo(0));\n\n            await AssertEventually(\n                new GetMeetingCommentsProbe(MeetingsModule, meetingId, meetingCommentId, expectedCommentLikesCount: 0),\n                10000);\n        }\n\n        [Test]\n        public void UnlikeMeetingComment_WhenCommentNotExists_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new RemoveMeetingCommentLikeCommand(meetingCommentId: Guid.NewGuid()));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentingConfigurations/CreateMeetingCommentingConfigurationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentingConfigurations\n{\n    [TestFixture]\n    public class CreateMeetingCommentingConfigurationTests : TestBase\n    {\n        [Test]\n        public async Task CreateMeetingCommentingCofiguration_WhenDataIsValid_IsSuccessful()\n        {\n            // Act\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n\n            // Assert\n            var meetingCommentingConfiguration = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentingConfigurationQuery(meetingId));\n            Assert.That(meetingCommentingConfiguration, Is.Not.Null);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentingConfigurations/DisableMeetingCommentingConfigurationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.DisableMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentingConfigurations\n{\n    [TestFixture]\n    public class DisableMeetingCommentingConfigurationTests : TestBase\n    {\n        [Test]\n        public async Task DisableMeetingCommenting_WhenDataIsValid_IsSuccess()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new DisableMeetingCommentingConfigurationCommand(meetingId));\n\n            // Assert\n            var meetingConfiguration = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentingConfigurationQuery(meetingId));\n            Assert.That(meetingConfiguration, Is.Not.Null);\n            Assert.That(meetingConfiguration.IsCommentingEnabled, Is.False);\n        }\n\n        [Test]\n        public void DisableMeetingCommenting_WhenConfigurationNotExist_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new DisableMeetingCommentingConfigurationCommand(Guid.NewGuid()));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingCommentingConfigurations/EnableMeetingCommentingConfigurationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.DisableMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.EnableMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingCommentingConfigurations.GetMeetingCommentingConfiguration;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingCommentingConfigurations\n{\n    [TestFixture]\n    public class EnableMeetingCommentingConfigurationTests : TestBase\n    {\n        [Test]\n        public async Task EnableMeetingCommenting_WhenDataIsValid_IsSuccess()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n            await MeetingsModule.ExecuteCommandAsync(new DisableMeetingCommentingConfigurationCommand(meetingId));\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new EnableMeetingCommentingConfigurationCommand(meetingId));\n\n            // Assert\n            var meetingConfiguration = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentingConfigurationQuery(meetingId));\n            Assert.That(meetingConfiguration, Is.Not.Null);\n            Assert.That(meetingConfiguration.IsCommentingEnabled, Is.True);\n        }\n\n        [Test]\n        public void EnableMeetingCommenting_WhenConfigurationNotExist_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new EnableMeetingCommentingConfigurationCommand(Guid.NewGuid()));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingComments/AddMeetingCommentTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingComments\n{\n    [TestFixture]\n    public class AddMeetingCommentTests : TestBase\n    {\n        [Test]\n        public async Task AddMeetingComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n\n            var date = new DateTime(2020, 1, 1, 01, 00, 00);\n            SystemClock.Set(date);\n            var comment = \"The meeting was great.\";\n\n            // Act\n            var meetingCommentId =\n                await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(meetingId, comment));\n\n            // Assert\n            var meetingComments = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n\n            Assert.That(meetingComments.Count, Is.EqualTo(1));\n            var meetingComment = meetingComments.Single();\n            Assert.That(meetingComment.Id, Is.EqualTo(meetingCommentId));\n            Assert.That(meetingComment.Comment, Is.EqualTo(comment));\n            Assert.That(meetingComment.AuthorId, Is.EqualTo(ExecutionContext.UserId));\n            Assert.That(meetingComment.CreateDate, Is.EqualTo(date));\n            Assert.That(meetingComment.EditDate, Is.Null);\n        }\n\n        [Test]\n        public void AddMeetingComment_WhenMeetingIsNonexistent_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(\n                    meetingId: Guid.NewGuid(),\n                    \"Comment for a nonexistent meeting.\"));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingComments/AddReplyToMeetingCommentTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingCommentReply;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingComments\n{\n    [TestFixture]\n    public class AddReplyToMeetingCommentTests : TestBase\n    {\n        [Test]\n        public async Task AddReply_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n            var meetingCommentId = await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(meetingId, \"The meeting was great.\"));\n\n            var date = new DateTime(2020, 1, 1, 01, 00, 00);\n            SystemClock.Set(date);\n            var reply = \"Absolutely!\";\n\n            // Act\n            var replyId = await MeetingsModule.ExecuteCommandAsync(new AddReplyToMeetingCommentCommand(meetingCommentId, reply));\n\n            // Assert\n            var meetingComments = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n\n            Assert.That(meetingComments.Count, Is.EqualTo(2));\n            var commentReply = meetingComments.Single(c => c.Id == replyId);\n            Assert.That(commentReply.InReplyToCommentId, Is.EqualTo(meetingCommentId));\n            Assert.That(commentReply.Comment, Is.EqualTo(reply));\n            Assert.That(commentReply.AuthorId, Is.EqualTo(ExecutionContext.UserId));\n            Assert.That(commentReply.CreateDate, Is.EqualTo(date));\n            Assert.That(commentReply.EditDate, Is.Null);\n        }\n\n        [Test]\n        public void AddReply_WhenParentCommentNotExists_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new AddReplyToMeetingCommentCommand(\n                    inReplyToCommentId: Guid.NewGuid(),\n                    \"Reply for a nonexistent comment.\"));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingComments/EditMeetingCommentTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.EditMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\nusing static CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings.MeetingHelper;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingComments\n{\n    [TestFixture]\n    public class EditMeetingCommentTests : TestBase\n    {\n        [Test]\n        public async Task EditMeetingComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var meetingId = await CreateMeetingAsync(MeetingsModule, ExecutionContext);\n            var meetingCommentId =\n                await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(\n                    meetingId,\n                    \"The meeting was great.\"));\n            var editedComment = \"It was very interesting!\";\n\n            var meetingCommentsBefore = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n            var originalMeetingComment = meetingCommentsBefore.Single();\n\n            var date = new DateTime(2020, 1, 1, 01, 00, 00);\n            SystemClock.Set(date);\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new EditMeetingCommentCommand(meetingCommentId, editedComment));\n\n            // Assert\n            var meetingCommentsAfter = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n\n            Assert.That(meetingCommentsAfter.Count, Is.EqualTo(1));\n            var editedMeetingComment = meetingCommentsAfter.Single();\n            Assert.That(editedMeetingComment.Comment, Is.EqualTo(editedComment));\n            Assert.That(editedMeetingComment.EditDate, Is.EqualTo(date));\n            Assert.That(editedMeetingComment.AuthorId, Is.EqualTo(originalMeetingComment.AuthorId));\n            Assert.That(editedMeetingComment.CreateDate, Is.EqualTo(originalMeetingComment.CreateDate));\n        }\n\n        [Test]\n        public void EditMeetingComment_WhenItIsNonexistent_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new EditMeetingCommentCommand(\n                    meetingCommentId: Guid.NewGuid(),\n                    \"Edit a nonexistent comment.\"));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingComments/GetMeetingCommentsTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingComments\n{\n    [TestFixture]\n    public class GetMeetingCommentsTests : TestBase\n    {\n        [Test]\n        public async Task GetMeetingComments_Test()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n\n            await MeetingsModule.ExecuteCommandAsync(\n                new AddMeetingCommentCommand(meetingId, \"The meeting was great.\"));\n            await MeetingsModule.ExecuteCommandAsync(\n                new AddMeetingCommentCommand(meetingId, \"The meeting was wonderful.\"));\n            await MeetingsModule.ExecuteCommandAsync(\n                new AddMeetingCommentCommand(meetingId, \"The meeting was amazing.\"));\n\n            // Act\n            var meetingComments = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n\n            // Assert\n            Assert.That(meetingComments.Count, Is.EqualTo(3));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingComments/RemoveMeetingCommentTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.AddMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.GetMeetingComments;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingComments.RemoveMeetingComment;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingComments\n{\n    public class RemoveMeetingCommentTests : TestBase\n    {\n        [Test]\n        public async Task RemoveMeetingComment_ByAuthor_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var meetingId = await MeetingHelper.CreateMeetingAsync(MeetingsModule, ExecutionContext);\n            var meetingCommentId =\n                await MeetingsModule.ExecuteCommandAsync(new AddMeetingCommentCommand(\n                    meetingId,\n                    \"The meeting was great.\"));\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(new RemoveMeetingCommentCommand(\n                meetingCommentId,\n                reason: string.Empty));\n\n            // Assert\n            var meetingComments = await MeetingsModule.ExecuteQueryAsync(new GetMeetingCommentsQuery(meetingId));\n            Assert.That(meetingComments, Is.Empty);\n        }\n\n        [Test]\n        public void RemoveMeetingComment_WhenItIsNonexistent_ThrowsInvalidCommandException()\n        {\n            // Assert\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                // Act\n                await MeetingsModule.ExecuteCommandAsync(new RemoveMeetingCommentCommand(\n                    meetingCommentId: Guid.NewGuid(),\n                    reason: string.Empty));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingGroupProposals/GetMeetingGroupProposalsTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetAllMeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingGroupProposals\n{\n    [TestFixture]\n    public class GetMeetingGroupProposalsTests : TestBase\n    {\n        [Test]\n        public async Task GetMeetingGroupProposals_Test()\n        {\n            await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                \"Name 1\",\n                \"Desc 1\",\n                \"Warsaw\",\n                \"PL\"));\n\n            await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                \"Name 2\",\n                \"Desc 2\",\n                \"London\",\n                \"GB\"));\n\n            await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                \"Name 3\",\n                \"Desc 3\",\n                \"Rome\",\n                \"IT\"));\n\n            await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                \"Name 4\",\n                \"Desc 4\",\n                \"Madrid\",\n                \"ES\"));\n\n            await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                \"Name 5\",\n                \"Desc 5\",\n                \"Berlin\",\n                \"DE\"));\n\n            var allProposals = await MeetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupProposalsQuery(null, null));\n\n            Assert.That(allProposals.Count, Is.EqualTo(5));\n\n            var proposalsPaged = await MeetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupProposalsQuery(2, 2));\n\n            Assert.That(proposalsPaged.Count, Is.EqualTo(2));\n            Assert.That(proposalsPaged[0].Name, Is.EqualTo(\"Name 3\"));\n            Assert.That(proposalsPaged[1].Name, Is.EqualTo(\"Name 4\"));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingGroupProposals/MeetingGroupProposalSampleData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingGroupProposals\n{\n    public struct MeetingGroupProposalSampleData\n    {\n        public static Guid MeetingGroupProposalId = Guid.NewGuid();\n\n        public static string Name = \"Great Meeting\";\n\n        public static string Description = \"Great Meeting description\";\n\n        public static string LocationCity = \"Warsaw\";\n\n        public static string LocationCountryCode = \"PL\";\n\n        public static Guid ProposalUserId = Guid.NewGuid();\n\n        public static DateTime ProposalDate = new DateTime(2020, 1, 1, 10, 20, 00);\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingGroupProposals/ProposeMeetingGroupTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingGroupProposals\n{\n    [TestFixture]\n    public class ProposeMeetingGroupTests : TestBase\n    {\n        [Test]\n        public async Task ProposeAndAcceptMeetingGroup_WhenDataIsValid_IsSuccessful()\n        {\n            var proposalId = await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                MeetingGroupProposalSampleData.Name,\n                MeetingGroupProposalSampleData.Description,\n                MeetingGroupProposalSampleData.LocationCity,\n                MeetingGroupProposalSampleData.LocationCountryCode));\n\n            await MeetingsModule.ExecuteCommandAsync(new AcceptMeetingGroupProposalCommand(Guid.NewGuid(), proposalId));\n\n            var meetingGroupProposal =\n                await MeetingsModule.ExecuteQueryAsync(new GetMeetingGroupProposalQuery(proposalId));\n\n            Assert.That(meetingGroupProposal.Id, Is.EqualTo(proposalId));\n            Assert.That(meetingGroupProposal.Name, Is.EqualTo(MeetingGroupProposalSampleData.Name));\n            Assert.That(meetingGroupProposal.Description, Is.EqualTo(MeetingGroupProposalSampleData.Description));\n            Assert.That(meetingGroupProposal.LocationCity, Is.EqualTo(MeetingGroupProposalSampleData.LocationCity));\n            Assert.That(meetingGroupProposal.LocationCountryCode, Is.EqualTo(MeetingGroupProposalSampleData.LocationCountryCode));\n            Assert.That(meetingGroupProposal.StatusCode, Is.EqualTo(\"Accepted\"));\n        }\n\n        [Test]\n        public void ProposeMeetingGroup_WhenNoLocationProvided_ThrowsInvalidCommandException()\n        {\n            Assert.CatchAsync<InvalidCommandException>(async () =>\n            {\n                await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                    MeetingGroupProposalSampleData.Name,\n                    MeetingGroupProposalSampleData.Description,\n                    null,\n                    null));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/MeetingGroups/CreateNewMeetingGroupTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.CreateNewMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAuthenticationMemberMeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetMeetingGroupDetails;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.MeetingGroups\n{\n    [TestFixture]\n    public class CreateNewMeetingGroupTests : TestBase\n    {\n        [Test]\n        public async Task CreateNewMeetingGroup_Test()\n        {\n            // Arrange\n            var proposalId = await MeetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                MeetingGroupProposalSampleData.Name,\n                MeetingGroupProposalSampleData.Description,\n                MeetingGroupProposalSampleData.LocationCity,\n                MeetingGroupProposalSampleData.LocationCountryCode));\n\n            await MeetingsModule.ExecuteCommandAsync(new AcceptMeetingGroupProposalCommand(Guid.NewGuid(), proposalId));\n\n            // Act\n            await MeetingsModule.ExecuteCommandAsync(\n                new CreateNewMeetingGroupCommand(\n                    Guid.NewGuid(),\n                    new MeetingGroupProposalId(proposalId)));\n\n            // Assert\n            var meetingGroups = await MeetingsModule.ExecuteQueryAsync(new GetAuthenticationMemberMeetingGroupsQuery());\n            Assert.That(meetingGroups, Is.Not.Empty);\n\n            var meetingGroupDetails =\n                await MeetingsModule.ExecuteQueryAsync(new GetMeetingGroupDetailsQuery(proposalId));\n            Assert.That(meetingGroupDetails.MembersCount, Is.EqualTo(1));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/Meetings/MeetingCreateTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingAttendees;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.GetMeetingDetails;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Members.CreateMember;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings\n{\n    [TestFixture]\n    public class MeetingCreateTests : TestBase\n    {\n        [Test]\n        public async Task CreateMeeting_Test()\n        {\n            // Arrange\n            await MeetingsModule.ExecuteCommandAsync(new CreateMemberCommand(\n                Guid.NewGuid(),\n                ExecutionContext.UserId,\n                \"johndoe\",\n                \"johndoe@mail.com\",\n                \"John\",\n                \"Doe\",\n                \"John Doe\"));\n\n            // Act\n            var meetingId = await MeetingHelper.CreateMeetingAsync(\n                MeetingsModule,\n                ExecutionContext);\n\n            // Assert\n            var meetingDetails = await MeetingsModule.ExecuteQueryAsync(new GetMeetingDetailsQuery(meetingId));\n            Assert.That(meetingDetails, Is.Not.Null);\n\n            var meetingAttendees =\n                await MeetingsModule.ExecuteQueryAsync(new GetMeetingAttendeesQuery(meetingId));\n\n            Assert.That(meetingAttendees.Count, Is.EqualTo(1));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/Meetings/MeetingHelper.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.CreateNewMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.SetMeetingGroupExpirationDate;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CreateMeeting;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.Meetings\n{\n    internal static class MeetingHelper\n    {\n        public static async Task<Guid> CreateMeetingAsync(\n            IMeetingsModule meetingsModule,\n            ExecutionContextMock executionContext)\n        {\n            var proposalId = await meetingsModule.ExecuteCommandAsync(\n                new ProposeMeetingGroupCommand(\n                    \"Amazing group\",\n                    \"Absolutely amazing meeting group.\",\n                    \"London\",\n                    \"UK\"));\n\n            await meetingsModule.ExecuteCommandAsync(\n                new CreateNewMeetingGroupCommand(\n                    Guid.NewGuid(),\n                    new MeetingGroupProposalId(proposalId)));\n\n            var meetingGroups = await meetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupsQuery());\n            var meetingGroup = meetingGroups.Single();\n\n            await meetingsModule.ExecuteCommandAsync(\n                new SetMeetingGroupExpirationDateCommand(\n                    Guid.NewGuid(),\n                    meetingGroup.Id,\n                    SystemClock.Now.AddMonths(1)));\n\n            var meetingId = await meetingsModule.ExecuteCommandAsync(\n                new CreateMeetingCommand(\n                    meetingGroup.Id,\n                    \"Some meeting\",\n                    DateTime.UtcNow.AddDays(1),\n                    DateTime.UtcNow.AddDays(10),\n                    \"Some very nice meeting.\",\n                    \"UK\",\n                    \"Baker street\",\n                    \"W2 2SZ\",\n                    \"London\",\n                    25,\n                    1,\n                    null,\n                    null,\n                    null,\n                    null,\n                    [executionContext.UserId]));\n\n            return meetingId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/SeedWork/EventsBusMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork\n{\n    public class EventsBusMock : IEventsBus\n    {\n        private readonly IList<IntegrationEvent> _publishedEvents;\n\n        public EventsBusMock()\n        {\n            _publishedEvents = new List<IntegrationEvent>();\n        }\n\n        public void Dispose()\n        {\n        }\n\n        public Task Publish<T>(T @event)\n            where T : IntegrationEvent\n        {\n            _publishedEvents.Add(@event);\n            return Task.CompletedTask;\n        }\n\n        public T GetLastPublishedEvent<T>()\n            where T : IntegrationEvent\n        {\n            return _publishedEvents.OfType<T>().Last();\n        }\n\n        public void Subscribe<T>(IIntegrationEventHandler<T> handler)\n            where T : IntegrationEvent\n        {\n        }\n\n        public void StartConsuming()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/SeedWork/OutboxMessagesHelper.cs",
    "content": "﻿using System.Data;\nusing System.Reflection;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration.Processing.Outbox;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork\n{\n    public class OutboxMessagesHelper\n    {\n        public static async Task<List<OutboxMessageDto>> GetOutboxMessages(IDbConnection connection)\n        {\n            const string sql = $\"\"\"\n                                SELECT [OutboxMessage].[Id] as [{nameof(OutboxMessageDto.Id)}], \n                                       [OutboxMessage].[Type] as [{nameof(OutboxMessageDto.Type)}],\n                                       [OutboxMessage].[Data] as [{nameof(OutboxMessageDto.Data)}] \n                                FROM [meetings].[OutboxMessages] AS [OutboxMessage] \n                                ORDER BY [OutboxMessage].[OccurredOn]\n                                \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            return messages.AsList();\n        }\n\n        public static T Deserialize<T>(OutboxMessageDto message)\n            where T : class, INotification\n        {\n            Type type = Assembly.GetAssembly(typeof(MeetingGroupProposalAcceptedNotification)).GetType(message.Type);\n            return JsonConvert.DeserializeObject(message.Data, type) as T;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration;\nusing Dapper;\nusing MediatR;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IMeetingsModule MeetingsModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        protected ExecutionContextMock ExecutionContext { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = new LoggerConfiguration()\n                .Enrich.FromLogContext()\n                .WriteTo.Console(\n                    outputTemplate:\n                    \"[{Timestamp:HH:mm:ss} {Level:u3}] [{Module}] [{Context}] {Message:lj}{NewLine}{Exception}\")\n                .CreateLogger();\n            EmailSender = Substitute.For<IEmailSender>();\n            ExecutionContext = new ExecutionContextMock(Guid.NewGuid());\n\n            MeetingsStartup.Initialize(\n                ConnectionString,\n                ExecutionContext,\n                Logger,\n                new EmailsConfiguration(\"from@email.com\"),\n                new EventsBusMock());\n\n            MeetingsModule = new MeetingsModule();\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            MeetingsStartup.Stop();\n            SystemClock.Reset();\n        }\n\n        protected async Task ExecuteScript(string scriptPath)\n        {\n            var sql = await File.ReadAllTextAsync(scriptPath);\n\n            await using var sqlConnection = new SqlConnection(ConnectionString);\n            await sqlConnection.ExecuteScalarAsync(sql);\n        }\n\n        protected async Task<T> GetLastOutboxMessage<T>()\n            where T : class, INotification\n        {\n            using (var connection = new SqlConnection(ConnectionString))\n            {\n                var messages = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n                return OutboxMessagesHelper.Deserialize<T>(messages.Last());\n            }\n        }\n\n        protected static void AssertBrokenRule<TRule>(AsyncTestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.CatchAsync<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n\n        protected static async Task AssertEventually(IProbe probe, int timeout)\n        {\n            await new Poller(timeout).CheckAsync(probe);\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [meetings].[InboxMessages] \" +\n                               \"DELETE FROM [meetings].[InternalCommands] \" +\n                               \"DELETE FROM [meetings].[OutboxMessages] \" +\n                               \"DELETE FROM [meetings].[MeetingAttendees] \" +\n                               \"DELETE FROM [meetings].[MeetingGroupMembers] \" +\n                               \"DELETE FROM [meetings].[MeetingGroupProposals] \" +\n                               \"DELETE FROM [meetings].[MeetingGroups] \" +\n                               \"DELETE FROM [meetings].[MeetingNotAttendees] \" +\n                               \"DELETE FROM [meetings].[MeetingCommentingConfigurations] \" +\n                               \"DELETE FROM [meetings].[Meetings] \" +\n                               \"DELETE FROM [meetings].[MeetingWaitlistMembers] \" +\n                               \"DELETE FROM [meetings].[MeetingMemberCommentLikes] \" +\n                               \"DELETE FROM [meetings].[MeetingComments] \" +\n                               \"DELETE FROM [meetings].[Countries] \" +\n                               \"DELETE FROM [meetings].[Members] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/MeetingGroupProposals/MeetingGroupProposalTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.MeetingGroupProposals\n{\n    [TestFixture]\n    public class MeetingGroupProposalTests : TestBase\n    {\n        [Test]\n        public void ProposeNewMeetingGroup_IsSuccessful()\n        {\n            var proposalMemberId = new MemberId(Guid.NewGuid());\n\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                \"name\",\n                \"description\",\n                MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\"),\n                proposalMemberId);\n\n            var meetingGroupProposed = AssertPublishedDomainEvent<MeetingGroupProposedDomainEvent>(meetingProposal);\n\n            meetingGroupProposed.MeetingGroupProposalId.Should().Be(meetingProposal.Id);\n        }\n\n        [Test]\n        public void AcceptProposal_WhenIsNotAccepted_IsSuccessful()\n        {\n            var proposalMemberId = new MemberId(Guid.NewGuid());\n\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                \"name\",\n                \"description\",\n                MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\"),\n                proposalMemberId);\n\n            meetingProposal.Accept();\n\n            var meetingGroupProposalAccepted =\n                AssertPublishedDomainEvent<MeetingGroupProposalAcceptedDomainEvent>(meetingProposal);\n\n            meetingGroupProposalAccepted.MeetingGroupProposalId.Should().Be(meetingProposal.Id);\n        }\n\n        [Test]\n        public void AcceptProposal_WhenIsAlreadyAccepted_BreaksProposalCannotBeAcceptedMoreThanOnceRule()\n        {\n            var proposalMemberId = new MemberId(Guid.NewGuid());\n\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                \"name\",\n                \"description\",\n                MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\"),\n                proposalMemberId);\n\n            meetingProposal.Accept();\n\n            AssertBrokenRule<MeetingGroupProposalCannotBeAcceptedMoreThanOnceRule>(() => { meetingProposal.Accept(); });\n        }\n\n        [Test]\n        public void CreateMeetingGroup_IsSuccessful_And_CreatorIsAHost()\n        {\n            var proposalMemberId = new MemberId(Guid.NewGuid());\n            var name = \"name\";\n            var description = \"description\";\n            var meetingGroupLocation = MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\");\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                name,\n                description,\n                meetingGroupLocation,\n                proposalMemberId);\n\n            var meetingGroup = meetingProposal.CreateMeetingGroup();\n\n            var meetingGroupCreated = AssertPublishedDomainEvent<MeetingGroupCreatedDomainEvent>(meetingGroup);\n            var newMeetingGroupMemberJoined =\n                AssertPublishedDomainEvent<NewMeetingGroupMemberJoinedDomainEvent>(meetingGroup);\n\n            meetingGroupCreated.MeetingGroupId.Should().Be(meetingProposal.Id);\n            newMeetingGroupMemberJoined.MemberId.Should().Be(proposalMemberId);\n            newMeetingGroupMemberJoined.Role.Should().Be(MeetingGroupMemberRole.Organizer);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/MeetingGroups/MeetingGroupTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.MeetingGroups\n{\n    [TestFixture]\n    public class MeetingGroupTests : TestBase\n    {\n        [Test]\n        public void EditGeneralAttributes_IsSuccessful()\n        {\n            var meetingGroup = CreateMeetingGroup();\n\n            var meetingGroupLocation = MeetingGroupLocation.CreateNew(\"London\", \"GB\");\n            meetingGroup.EditGeneralAttributes(\"newName\", \"newDescription\", meetingGroupLocation);\n\n            var meetingGroupGeneralAttributesEdited =\n                AssertPublishedDomainEvent<MeetingGroupGeneralAttributesEditedDomainEvent>(meetingGroup);\n\n            meetingGroupGeneralAttributesEdited.NewName.Should().Be(\"newName\");\n            meetingGroupGeneralAttributesEdited.NewDescription.Should().Be(\"newDescription\");\n            meetingGroupGeneralAttributesEdited.NewLocation.Should().Be(meetingGroupLocation);\n        }\n\n        [Test]\n        public void JoinToGroup_WhenMemberHasNotJoinedYet_IsSuccessful()\n        {\n            var meetingGroup = CreateMeetingGroup();\n\n            MemberId newMemberId = new MemberId(Guid.NewGuid());\n            meetingGroup.JoinToGroupMember(newMemberId);\n\n            var newMeetingGroupMemberJoined = AssertPublishedDomainEvent<NewMeetingGroupMemberJoinedDomainEvent>(meetingGroup);\n\n            newMeetingGroupMemberJoined.MeetingGroupId.Should().Be(meetingGroup.Id);\n            newMeetingGroupMemberJoined.MemberId.Should().Be(newMemberId);\n            newMeetingGroupMemberJoined.Role.Should().Be(MeetingGroupMemberRole.Member);\n        }\n\n        [Test]\n        public void JoinToGroup_WhenMemberHasAlreadyJoined_BreaksMeetingGroupMemberCannotBeAddedTwiceRule()\n        {\n            var meetingGroup = CreateMeetingGroup();\n\n            MemberId newMemberId = new MemberId(Guid.NewGuid());\n            meetingGroup.JoinToGroupMember(newMemberId);\n\n            AssertBrokenRule<MeetingGroupMemberCannotBeAddedTwiceRule>(() =>\n            {\n                meetingGroup.JoinToGroupMember(newMemberId);\n            });\n        }\n\n        [Test]\n        public void LeaveGroup_WhenMemberIsActiveMemberOfGroup_IsSuccessful()\n        {\n            var meetingGroup = CreateMeetingGroup();\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingGroup.JoinToGroupMember(newMemberId);\n\n            meetingGroup.LeaveGroup(newMemberId);\n\n            var meetingGroupMemberLeft = AssertPublishedDomainEvent<MeetingGroupMemberLeftGroupDomainEvent>(meetingGroup);\n\n            meetingGroupMemberLeft.MemberId.Should().Be(newMemberId);\n        }\n\n        [Test]\n        public void LeaveGroup_WhenMemberIsNotActiveMemberOfGroup_BreaksNotActualGroupMemberCannotLeaveGroupRule()\n        {\n            var meetingGroup = CreateMeetingGroup();\n            var newMemberId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<NotActualGroupMemberCannotLeaveGroupRule>(() =>\n            {\n                meetingGroup.LeaveGroup(newMemberId);\n            });\n        }\n\n        [Test]\n        public void UpdatePaymentDateTo_IsSuccessful()\n        {\n            var meetingGroup = CreateMeetingGroup();\n            var dateTo = DateTime.UtcNow;\n\n            meetingGroup.SetExpirationDate(dateTo);\n\n            var meetingGroupPaymentInfoUpdated = AssertPublishedDomainEvent<MeetingGroupPaymentInfoUpdatedDomainEvent>(meetingGroup);\n\n            meetingGroupPaymentInfoUpdated.MeetingGroupId.Should().Be(meetingGroup.Id);\n            meetingGroupPaymentInfoUpdated.PaymentDateTo.Should().Be(dateTo);\n        }\n\n        [Test]\n        public void CreateMeeting_WhenGroupIsNotPayed_IsNotPossible()\n        {\n            var meetingGroup = CreateMeetingGroup();\n\n            MemberId creatorId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<MeetingCanBeOrganizedOnlyByPayedGroupRule>(() =>\n            {\n                meetingGroup.CreateMeeting(\n                    \"title\",\n                    MeetingTerm.CreateNewBetweenDates(\n                        new DateTime(2019, 1, 1, 10, 0, 0),\n                        new DateTime(2019, 1, 1, 12, 0, 0)),\n                    \"description\",\n                    MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                    null,\n                    0,\n                    Term.NoTerm,\n                    MoneyValue.Undefined,\n                    [],\n                    creatorId);\n            });\n        }\n\n        [Test]\n        public void CreateMeeting_WhenCreatorIsMemberOfGroupAndHostsAreNotDefined_IsSuccessful()\n        {\n            var definedProposalMemberId = new MemberId(Guid.NewGuid());\n            var meetingGroup = CreateMeetingGroup(definedProposalMemberId);\n            meetingGroup.SetExpirationDate(DateTime.UtcNow.AddDays(1));\n\n            var meeting = meetingGroup.CreateMeeting(\n                \"title\",\n                MeetingTerm.CreateNewBetweenDates(\n                    new DateTime(2019, 1, 1, 10, 0, 0),\n                    new DateTime(2019, 1, 1, 12, 0, 0)),\n                \"description\",\n                MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                null,\n                0,\n                Term.NoTerm,\n                MoneyValue.Undefined,\n                [],\n                definedProposalMemberId);\n\n            AssertPublishedDomainEvent<MeetingCreatedDomainEvent>(meeting);\n        }\n\n        [Test]\n        public void CreateMeeting_WhenHostsAreDefinedAndTheyAreGroupMembers_DefinedHostsAreHostsOfMeeting()\n        {\n            var definedProposalMemberId = new MemberId(Guid.NewGuid());\n            var meetingGroup = CreateMeetingGroup(definedProposalMemberId);\n            meetingGroup.SetExpirationDate(DateTime.UtcNow.AddDays(1));\n            var hostOne = new MemberId(Guid.NewGuid());\n            var hostTwo = new MemberId(Guid.NewGuid());\n            List<MemberId> hosts =\n            [\n                hostOne,\n                hostTwo\n            ];\n            meetingGroup.JoinToGroupMember(hostOne);\n            meetingGroup.JoinToGroupMember(hostTwo);\n\n            var meeting = meetingGroup.CreateMeeting(\n                \"title\",\n                MeetingTerm.CreateNewBetweenDates(\n                    new DateTime(2019, 1, 1, 10, 0, 0),\n                    new DateTime(2019, 1, 1, 12, 0, 0)),\n                \"description\",\n                MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                null,\n                0,\n                Term.NoTerm,\n                MoneyValue.Undefined,\n                hosts,\n                definedProposalMemberId);\n\n            var meetingAttendeeAddedEvents = AssertPublishedDomainEvents<MeetingAttendeeAddedDomainEvent>(meeting);\n\n            meetingAttendeeAddedEvents.Should().HaveCount(2);\n            meetingAttendeeAddedEvents[0].AttendeeId.Should().Be(hostOne);\n            meetingAttendeeAddedEvents[0].Role.Should().Be(MeetingAttendeeRole.Host.Value);\n            meetingAttendeeAddedEvents[1].AttendeeId.Should().Be(hostTwo);\n            meetingAttendeeAddedEvents[1].Role.Should().Be(MeetingAttendeeRole.Host.Value);\n        }\n\n        [Test]\n        public void CreateMeeting_WhenHostsAreDefinedAndTheyAreNotGroupMembers_BreaksMeetingHostMustBeAMeetingGroupMemberRule()\n        {\n            var definedProposalMemberId = new MemberId(Guid.NewGuid());\n            var meetingGroup = CreateMeetingGroup(definedProposalMemberId);\n            meetingGroup.SetExpirationDate(DateTime.UtcNow.AddDays(1));\n            var hostOne = new MemberId(Guid.NewGuid());\n            var hostTwo = new MemberId(Guid.NewGuid());\n            List<MemberId> hosts =\n            [\n                hostOne,\n                hostTwo\n            ];\n\n            AssertBrokenRule<MeetingHostMustBeAMeetingGroupMemberRule>(() =>\n            {\n                meetingGroup.CreateMeeting(\n                    \"title\",\n                    MeetingTerm.CreateNewBetweenDates(\n                        new DateTime(2019, 1, 1, 10, 0, 0),\n                        new DateTime(2019, 1, 1, 12, 0, 0)),\n                    \"description\",\n                    MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                    null,\n                    0,\n                    Term.NoTerm,\n                    MoneyValue.Undefined,\n                    hosts,\n                    definedProposalMemberId);\n            });\n        }\n\n        [Test]\n        public void CreateMeeting_WhenCreatorIsNotMemberOfGroup_BreaksMeetingHostMustBeAMeetingGroupMemberRule()\n        {\n            var definedProposalMemberId = new MemberId(Guid.NewGuid());\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingGroup = CreateMeetingGroup(definedProposalMemberId);\n            meetingGroup.SetExpirationDate(DateTime.UtcNow.AddDays(1));\n\n            AssertBrokenRule<MeetingHostMustBeAMeetingGroupMemberRule>(() =>\n            {\n                meetingGroup.CreateMeeting(\n                    \"title\",\n                    MeetingTerm.CreateNewBetweenDates(\n                        new DateTime(2019, 1, 1, 10, 0, 0),\n                        new DateTime(2019, 1, 1, 12, 0, 0)),\n                    \"description\",\n                    MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                    null,\n                    0,\n                    Term.NoTerm,\n                    MoneyValue.Undefined,\n                    [],\n                    creatorId);\n            });\n        }\n\n        private static MeetingGroup CreateMeetingGroup(MemberId definedProposalMemberId = null)\n        {\n            var proposalMemberId = definedProposalMemberId ?? new MemberId(Guid.NewGuid());\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                \"name\",\n                \"description\",\n                MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\"),\n                proposalMemberId);\n\n            meetingProposal.Accept();\n\n            var meetingGroup = meetingProposal.CreateMeetingGroup();\n\n            DomainEventsTestHelper.ClearAllDomainEvents(meetingGroup);\n\n            return meetingGroup;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingAddAttendeeTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingAddAttendeeTests : MeetingTestsBase\n    {\n        [Test]\n        public void AddAttendee_WhenMeetingHasStared_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, creatorId, 0);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenRsvpTermEnded_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                RvspTerm = Term.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<AttendeeCanBeAddedOnlyInRsvpTermRule>(() =>\n            {\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, creatorId, 0);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenAttendeeIsNotAMemberOfMeetingGroup_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n\n            AssertBrokenRule<MeetingAttendeeMustBeAMemberOfGroupRule>(() =>\n            {\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, new MemberId(Guid.NewGuid()), 0);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenMemberIsAlreadyAttendeeOfMeeting_IsNotPossible()\n        {\n            // Arrange\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n\n            // Assert\n            AssertBrokenRule<MemberCannotBeAnAttendeeOfMeetingMoreThanOnceRule>(() =>\n            {\n                // Act\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenGuestsNumberIsAboveTheLimit_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                GuestsLimit = 5\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n\n            AssertBrokenRule<MeetingGuestsNumberIsAboveLimitRule>(() =>\n            {\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 6);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenAttendeeLimitIsReached_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                AttendeesLimit = 5\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n            var aboveLimitMember = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(aboveLimitMember);\n\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 3);\n\n            // for now: creator or meeting (automatically) and newMember with 3 guests = 5\n            AssertBrokenRule<MeetingAttendeesNumberIsAboveLimitRule>(() =>\n            {\n                meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, aboveLimitMember, 0);\n            });\n        }\n\n        [Test]\n        public void AddAttendee_WhenAllConditionsAllowsNewAttendee_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 3);\n\n            var meetingAttendeesAddedEvents =\n                AssertPublishedDomainEvents<MeetingAttendeeAddedDomainEvent>(meetingTestData.Meeting);\n\n            meetingAttendeesAddedEvents.Should().HaveCount(2);\n            meetingAttendeesAddedEvents[0].AttendeeId.Should().Be(creatorId);\n            meetingAttendeesAddedEvents[0].Role.Should().Be(MeetingAttendeeRole.Host.Value);\n            meetingAttendeesAddedEvents[1].AttendeeId.Should().Be(newMemberId);\n            meetingAttendeesAddedEvents[1].Role.Should().Be(MeetingAttendeeRole.Attendee.Value);\n        }\n\n        [Test]\n        public void AddAttendee_WhenMemberIsNotAttendeeAndChangedDecision_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n            meetingTestData.Meeting.AddNotAttendee(newMemberId);\n\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n\n            var meetingNotAttendeeChangedDecision = AssertPublishedDomainEvent<MeetingNotAttendeeChangedDecisionDomainEvent>(meetingTestData.Meeting);\n            meetingNotAttendeeChangedDecision.MemberId.Should().Be(newMemberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingAddNotAttendeeTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingAddNotAttendeeTests : MeetingTestsBase\n    {\n        [Test]\n        public void AddNotAttendee_WhenMeetingHasStarted_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.AddNotAttendee(creatorId);\n            });\n        }\n\n        [Test]\n        public void AddNotAttendee_WhenMemberIsAlreadyNotAttendee_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n\n            meetingTestData.Meeting.AddNotAttendee(creatorId);\n\n            AssertBrokenRule<MemberCannotBeNotAttendeeTwiceRule>(() =>\n            {\n                meetingTestData.Meeting.AddNotAttendee(creatorId);\n            });\n        }\n\n        [Test]\n        public void AddNotAttendee_WhenMemberIsNotNotAttendee_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n\n            meetingTestData.Meeting.AddNotAttendee(memberId);\n\n            var meetingNotAttendeeAdded = AssertPublishedDomainEvent<MeetingNotAttendeeAddedDomainEvent>(meetingTestData.Meeting);\n            meetingNotAttendeeAdded.MemberId.Should().Be(memberId);\n        }\n\n        [Test]\n        public void AddNotAttendee_WhenMemberIsAttendeeAndChangedDecision_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0);\n\n            meetingTestData.Meeting.AddNotAttendee(newMemberId);\n\n            var meetingAttendeeChangedDecision = AssertPublishedDomainEvent<MeetingAttendeeChangedDecisionDomainEvent>(meetingTestData.Meeting);\n            meetingAttendeeChangedDecision.MemberId.Should().Be(newMemberId);\n        }\n\n        [Test]\n        public void ChangeNotAttendeeDecision_WhenMeetingHasStared_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.ChangeNotAttendeeDecision(newMemberId);\n            });\n        }\n\n        [Test]\n        public void ChangeNotAttendeeDecision_WhenMemberIsNotActiveNotAttendee_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n\n            AssertBrokenRule<NotActiveNotAttendeeCannotChangeDecisionRule>(() =>\n            {\n                meetingTestData.Meeting.ChangeNotAttendeeDecision(newMemberId);\n            });\n        }\n\n        [Test]\n        public void ChangeNotAttendeeDecision_WhenMemberIsNotAttendee_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId);\n            meetingTestData.Meeting.AddNotAttendee(newMemberId);\n\n            meetingTestData.Meeting.ChangeNotAttendeeDecision(newMemberId);\n\n            var meetingNotAttendeeChangedDecision = AssertPublishedDomainEvent<MeetingNotAttendeeChangedDecisionDomainEvent>(meetingTestData.Meeting);\n            meetingNotAttendeeChangedDecision.MemberId.Should().Be(newMemberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingCommentTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingComments.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingMemberCommentLikes.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingCommentTests : MeetingTestsBase\n    {\n        [Test]\n        public void AddComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n            var comment = \"Great meeting!\";\n\n            // Act\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, comment, meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            var meetingCommentCreatedEvent = AssertPublishedDomainEvent<MeetingCommentAddedDomainEvent>(meetingComment);\n            meetingCommentCreatedEvent.MeetingCommentId.Should().Be(meetingComment.Id);\n            meetingCommentCreatedEvent.MeetingId.Should().Be(meetingTestData.Meeting.Id);\n            meetingCommentCreatedEvent.Comment.Should().Be(comment);\n        }\n\n        [Test]\n        public void AddComment_WhenAuthorIsNotMeetingGroupMember_BreaksCommentCanBeAddedOnlyByMeetingGroupMemberRule()\n        {\n            // Arrange\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions());\n\n            // Assert\n            AssertBrokenRule<CommentCanBeAddedOnlyByMeetingGroupMemberRule>(() =>\n            {\n                // Act\n                meetingTestData.Meeting.AddComment(new MemberId(Guid.NewGuid()), \"Bad meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        [TestCase(null)]\n        [TestCase(\"\")]\n        public void AddComment_WhenTextIsEmpty_BreaksCommentTextMustBeProvidedRule(string missingComment)\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            // Assert\n            AssertBrokenRule<CommentTextMustBeProvidedRule>(() =>\n            {\n                // Act\n                meetingTestData.Meeting.AddComment(commentAuthorId, missingComment, meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void AddComment_WhenMeetingCommentingDisabled_BreaksCommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(\n                new MeetingTestDataOptions\n                {\n                    Attendees = new[] { commentAuthorId },\n                    IsMeetingCommentingEnabled = false\n                });\n\n            // Assert\n            AssertBrokenRule<CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule>(() =>\n            {\n                // Act\n                meetingTestData.Meeting.AddComment(commentAuthorId, \"I appreciate your work!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void EditComment_IsSuccessful()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n            var editedComment = \"Wonderful!\";\n\n            // Act\n            meetingComment.Edit(commentAuthorId, editedComment, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            var meetingCommentEditedEvent = AssertPublishedDomainEvent<MeetingCommentEditedDomainEvent>(meetingComment);\n            meetingCommentEditedEvent.MeetingCommentId.Should().Be(meetingComment.Id);\n            meetingCommentEditedEvent.EditedComment.Should().Be(editedComment);\n        }\n\n        [Test]\n        public void EditComment_ByNoAuthor_BreaksMeetingCommentCanBeEditedOnlyByAuthor()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n            var editedComment = \"Wonderful!\";\n\n            // Assert\n            AssertBrokenRule<MeetingCommentCanBeEditedOnlyByAuthorRule>(() =>\n            {\n                // Act\n                meetingComment.Edit(new MemberId(Guid.NewGuid()), editedComment, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        [TestCase(null)]\n        [TestCase(\"\")]\n        public void EditComment_WhenNewTextIsEmpty_BreaksCommentTextMustBeProvidedRule(string missingComment)\n        {\n            // Arrange\n            var authorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { authorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(authorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n\n            // Assert\n            AssertBrokenRule<CommentTextMustBeProvidedRule>(() =>\n            {\n                // Act\n                meetingComment.Edit(new MemberId(Guid.NewGuid()), missingComment, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void EditComment_WhenMeetingCommentingDisabled_BreaksCommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule()\n        {\n            // Arrange\n            var groupOrganizerId = new MemberId(Guid.NewGuid());\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(\n                new MeetingTestDataOptions\n                {\n                    CreatorId = groupOrganizerId,\n                    Attendees = new[] { commentAuthorId }\n                });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"It was good.\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingTestData.MeetingCommentingConfiguration.DisableCommenting(groupOrganizerId, meetingTestData.MeetingGroup);\n\n            // Assert\n            AssertBrokenRule<CommentCanBeEditedOnlyIfCommentingForMeetingEnabledRule>(() =>\n            {\n                // Act\n                meetingComment.Edit(commentAuthorId, \"It was bad.\", meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void RemoveComment_IsSuccessful()\n        {\n            // Arrange\n            var removingMemberId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            { Attendees = new[] { removingMemberId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(removingMemberId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n\n            // Act\n            meetingComment.Remove(removingMemberId, meetingTestData.MeetingGroup);\n\n            // Assert\n            var meetingCommentRemovedEvent = AssertPublishedDomainEvent<MeetingCommentRemovedDomainEvent>(meetingComment);\n            meetingCommentRemovedEvent.MeetingCommentId.Should().Be(meetingComment.Id);\n        }\n\n        [Test]\n        public void RemoveComment_ByNoAuthorNoOrganizer_BreaksMeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var groupCreatorId = new MemberId(Guid.NewGuid());\n\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = groupCreatorId,\n                Attendees = new[] { commentAuthorId }\n            });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n\n            // Assert\n            AssertBrokenRule<MeetingCommentCanBeRemovedOnlyByAuthorOrGroupOrganizerRule>(() =>\n            {\n                // Act\n                meetingComment.Remove(removingMemberId: new MemberId(Guid.NewGuid()), meetingTestData.MeetingGroup);\n            });\n        }\n\n        [Test]\n        public void RemoveComment_ByAuthor_BreaksRemovingReasonCanBeProvidedOnlyByGroupOrganizer()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData =\n                CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            meetingComment.ClearDomainEvents();\n\n            // Assert\n            AssertBrokenRule<RemovingReasonCanBeProvidedOnlyByGroupOrganizerRule>(() =>\n            {\n                // Act\n                meetingComment.Remove(\n                    commentAuthorId,\n                    meetingTestData.MeetingGroup,\n                    \"I don't like the comment.\");\n            });\n        }\n\n        [Test]\n        public void AddReplyToComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var replyAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId, replyAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            var reply = \"Exactly!\";\n\n            // Act\n            var replyToComment = meetingComment.Reply(replyAuthorId, reply, meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            var replyToMeetingCommentAddedEvent = AssertPublishedDomainEvent<ReplyToMeetingCommentAddedDomainEvent>(replyToComment);\n            replyToMeetingCommentAddedEvent.MeetingCommentId.Should().Be(replyToComment.Id);\n            replyToMeetingCommentAddedEvent.InReplyToCommentId.Should().Be(meetingComment.Id);\n            replyToMeetingCommentAddedEvent.Reply.Should().Be(reply);\n        }\n\n        [Test]\n        public void AddReplyToComment_WhenAuthorIsNotMeetingGroupMember_BreaksCommentCanBeAddedOnlyByMeetingGroupMemberRule()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            AssertBrokenRule<CommentCanBeAddedOnlyByMeetingGroupMemberRule>(() =>\n            {\n                // Act\n                meetingComment.Reply(replierId: new MemberId(Guid.NewGuid()), \"Exactly!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        [TestCase(null)]\n        [TestCase(\"\")]\n        public void AddReplyToComment_WhenTextIsEmpty_BreaksCommentTextMustBeProvidedRule(string missingReply)\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var replyAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId, replyAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            AssertBrokenRule<CommentTextMustBeProvidedRule>(() =>\n            {\n                // Act\n                meetingComment.Reply(replyAuthorId, missingReply, meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void AddReplyToComment_WhenMeetingCommentingDisabled_BreaksCommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule()\n        {\n            // Arrange\n            var creatorId = new MemberId(Guid.NewGuid());\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var replyAuthorId = new MemberId(Guid.NewGuid());\n\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = creatorId, Attendees = new[] { commentAuthorId, replyAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            meetingTestData.MeetingCommentingConfiguration.DisableCommenting(creatorId, meetingTestData.MeetingGroup);\n\n            // Assert\n            AssertBrokenRule<CommentCanBeCreatedOnlyIfCommentingForMeetingEnabledRule>(() =>\n            {\n                // Act\n                meetingComment.Reply(replyAuthorId, \"Exactly!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n            });\n        }\n\n        [Test]\n        public void AddLikeToComment_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var likerId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId, likerId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Act\n            var like = meetingComment.Like(\n                likerId,\n                likerMeetingGroupMember: new MeetingGroupMemberData(meetingTestData.MeetingGroup.Id, likerId),\n                meetingMemberCommentLikesCount: 0);\n\n            // Assert\n            var meetingCommentLikedEvent = AssertPublishedDomainEvent<MeetingCommentLikedDomainEvent>(like);\n            meetingCommentLikedEvent.MeetingCommentId.Should().Be(meetingComment.Id);\n            meetingCommentLikedEvent.LikerId.Should().Be(likerId);\n        }\n\n        [Test]\n        public void AddLikeToComment_WhenLikerIsNotGroupMember_BreaksCommentCanBeLikedOnlyByMeetingGroupMemberRule()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            AssertBrokenRule<CommentCanBeLikedOnlyByMeetingGroupMemberRule>(() =>\n            {\n                // Act\n                meetingComment.Like(\n                    likerId: new MemberId(Guid.NewGuid()),\n                    likerMeetingGroupMember: null,\n                    meetingMemberCommentLikesCount: 0);\n            });\n        }\n\n        [Test]\n        public void AddLikeToComment_WhenTheCommentIsAlreadyLikedByTheMember_BreaksCommentCannotBeLikedByTheSameMemberMoreThanOnceRule()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var likerId = new MemberId(Guid.NewGuid());\n\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId, likerId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            // Assert\n            AssertBrokenRule<CommentCannotBeLikedByTheSameMemberMoreThanOnceRule>(() =>\n            {\n                // Act\n                meetingComment.Like(\n                    likerId,\n                    likerMeetingGroupMember: new MeetingGroupMemberData(meetingTestData.MeetingGroup.Id, likerId),\n                    meetingMemberCommentLikesCount: 1);\n            });\n        }\n\n        [Test]\n        public void RemoveLike_WhenDataIsValid_IsSuccessful()\n        {\n            // Arrange\n            var commentAuthorId = new MemberId(Guid.NewGuid());\n            var likerId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { Attendees = new[] { commentAuthorId, likerId } });\n\n            var meetingComment = meetingTestData.Meeting.AddComment(commentAuthorId, \"Great meeting!\", meetingTestData.MeetingGroup, meetingTestData.MeetingCommentingConfiguration);\n\n            var commentLike = meetingComment.Like(\n                likerId,\n                likerMeetingGroupMember: new MeetingGroupMemberData(meetingTestData.MeetingGroup.Id, likerId),\n                meetingMemberCommentLikesCount: 0);\n            commentLike.ClearDomainEvents();\n\n            // Act\n            commentLike.Remove();\n\n            // Assert\n            var meetingCommentUnlikedEvent = AssertPublishedDomainEvent<MeetingCommentUnlikedDomainEvent>(commentLike);\n            meetingCommentUnlikedEvent.MeetingCommentId.Should().Be(meetingComment.Id);\n            meetingCommentUnlikedEvent.LikerId.Should().Be(likerId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingCommentingConfigurationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingCommentingConfigurationTests : MeetingTestsBase\n    {\n        [Test]\n        public void CreateMeetingCommentingConfiguration_IsSuccessful()\n        {\n            // Arrange\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions());\n\n            // Act\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n\n            // Assert\n            var meetingCommentingConfigurationCreatedEvent = AssertPublishedDomainEvent<MeetingCommentingConfigurationCreatedDomainEvent>(meetingCommentingConfiguration);\n            meetingCommentingConfigurationCreatedEvent.MeetingId.Should().Be(meeting.Meeting.Id);\n            meetingCommentingConfigurationCreatedEvent.IsEnabled.Should().BeTrue();\n        }\n\n        [Test]\n        public void DisableCommenting_IsSuccessfull()\n        {\n            // Arrange\n            var organizerId = new MemberId(Guid.NewGuid());\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = organizerId });\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n\n            meetingCommentingConfiguration.ClearDomainEvents();\n\n            // Act\n            meetingCommentingConfiguration.DisableCommenting(organizerId, meeting.MeetingGroup);\n\n            // Assert\n            var meetingCommentingDisabledEvent = AssertPublishedDomainEvent<MeetingCommentingDisabledDomainEvent>(meetingCommentingConfiguration);\n            meetingCommentingDisabledEvent.MeetingId.Should().Be(meeting.Meeting.Id);\n        }\n\n        [Test]\n        public void DisableCommenting_WhenMemberIsNotGroupOrganizer_BreakMeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule()\n        {\n            // Arrange\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions());\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n\n            AssertBrokenRule<MeetingCommentingCanBeDisabledOnlyByGroupOrganizerRule>(() =>\n            {\n                meetingCommentingConfiguration.DisableCommenting(new MemberId(Guid.NewGuid()), meeting.MeetingGroup);\n            });\n        }\n\n        [Test]\n        public void DisableCommenting_WhenCommentingAlreadyDisabled_IsIgnored()\n        {\n            // Arrange\n            var organizerId = new MemberId(Guid.NewGuid());\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = organizerId });\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n            meetingCommentingConfiguration.DisableCommenting(organizerId, meeting.MeetingGroup);\n\n            meetingCommentingConfiguration.ClearDomainEvents();\n\n            // Act\n            meetingCommentingConfiguration.DisableCommenting(organizerId, meeting.MeetingGroup);\n\n            // Assert\n            AssertDomainEventNotPublished<MeetingCommentingDisabledDomainEvent>(meetingCommentingConfiguration);\n        }\n\n        [Test]\n        public void EnableCommenting_IsSuccessfull()\n        {\n            // Arrange\n            var organizerId = new MemberId(Guid.NewGuid());\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = organizerId });\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n            meetingCommentingConfiguration.DisableCommenting(organizerId, meeting.MeetingGroup);\n\n            meetingCommentingConfiguration.ClearDomainEvents();\n\n            // Act\n            meetingCommentingConfiguration.EnableCommenting(organizerId, meeting.MeetingGroup);\n\n            // Assert\n            var meetingCommentingEnabledEvent = AssertPublishedDomainEvent<MeetingCommentingEnabledDomainEvent>(meetingCommentingConfiguration);\n            meetingCommentingEnabledEvent.MeetingId.Should().Be(meeting.Meeting.Id);\n        }\n\n        [Test]\n        public void EnableCommenting_WhenMemberIsNotGroupOrganizer_BreakMeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule()\n        {\n            // Arrange\n            var organizerId = new MemberId(Guid.NewGuid());\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = organizerId });\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n            meetingCommentingConfiguration.DisableCommenting(organizerId, meeting.MeetingGroup);\n\n            meetingCommentingConfiguration.ClearDomainEvents();\n\n            AssertBrokenRule<MeetingCommentingCanBeEnabledOnlyByGroupOrganizerRule>(() =>\n            {\n                meetingCommentingConfiguration.EnableCommenting(new MemberId(Guid.NewGuid()), meeting.MeetingGroup);\n            });\n        }\n\n        [Test]\n        public void EnableCommenting_WhenCommentingAlreadyEnabled_IsIgnored()\n        {\n            // Arrange\n            var organizerId = new MemberId(Guid.NewGuid());\n            var meeting = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = organizerId });\n            var meetingCommentingConfiguration = meeting.Meeting.CreateCommentingConfiguration();\n\n            meetingCommentingConfiguration.ClearDomainEvents();\n\n            // Act\n            meetingCommentingConfiguration.EnableCommenting(organizerId, meeting.MeetingGroup);\n\n            // Assert\n            AssertDomainEventNotPublished<MeetingCommentingDisabledDomainEvent>(meetingCommentingConfiguration);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingLimitsTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingLimitsTests : MeetingTestsBase\n    {\n        [Test]\n        public void CreateMeetingLimits_WhenAttendeesLimitIsGreaterThanGuestsLimit_IsSuccessful()\n        {\n            var meetingLimits = MeetingLimits.Create(15, 5);\n\n            meetingLimits.AttendeesLimit.Should().Be(15);\n            meetingLimits.GuestsLimit.Should().Be(5);\n        }\n\n        [Test]\n        public void CreateMeetingLimits_WhenAttendeesLimitIsLessThanGuestsLimit_BreaksMeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule()\n        {\n            AssertBrokenRule<MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule>(() =>\n            {\n                MeetingLimits.Create(5, 8);\n            });\n        }\n\n        [Test]\n        public void CreateMeetingLimits_WhenAttendeesLimitIsNotDefined_GuestsLimitCanBeAny()\n        {\n            var meetingLimits = MeetingLimits.Create(null, 5);\n\n            meetingLimits.AttendeesLimit.Should().BeNull();\n            meetingLimits.GuestsLimit.Should().Be(5);\n        }\n\n        [Test]\n        public void CreateMeetingLimits_WhenAttendeesLimitIsNegative_BreaksMeetingAttendeesLimitCannotBeNegativeRule()\n        {\n            AssertBrokenRule<MeetingAttendeesLimitCannotBeNegativeRule>(() =>\n            {\n                MeetingLimits.Create(-2, 8);\n            });\n        }\n\n        [Test]\n        public void CreateMeetingLimits_WhenGuestsLimitIsNegative_BreaksMeetingGuestsLimitCannotBeNegativeRule()\n        {\n            AssertBrokenRule<MeetingGuestsLimitCannotBeNegativeRule>(() =>\n            {\n                MeetingLimits.Create(20, -9);\n            });\n        }\n\n        [Test]\n        public void CreateMeetingLimits_WhenAttendeesLimitIsEqualToGuestsLimit_BreaksMeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule()\n        {\n            AssertBrokenRule<MeetingAttendeesLimitMustBeGreaterThanGuestsLimitRule>(() =>\n            {\n                MeetingLimits.Create(5, 5);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingRolesTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingRolesTests : MeetingTestsBase\n    {\n        [Test]\n        public void SetHostRole_WhenMeetingHasStarted_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, creatorId, creatorId);\n            });\n        }\n\n        [Test]\n        public void SetHostRole_WhenSettingMemberIsNotAOrganizerOrHostMeeting_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var settingMemberId = new MemberId(Guid.NewGuid());\n            var newOrganizerId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newOrganizerId);\n            meetingTestData.MeetingGroup.JoinToGroupMember(settingMemberId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newOrganizerId, 0);\n\n            AssertBrokenRule<OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule>(() =>\n            {\n                meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, settingMemberId, newOrganizerId);\n            });\n        }\n\n        [Test]\n        public void SetHostRole_WhenSettingMemberIsGroupOrganizer_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newOrganizerId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newOrganizerId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newOrganizerId, 0);\n\n            meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, creatorId, newOrganizerId);\n\n            var newMeetingHostSet = AssertPublishedDomainEvent<NewMeetingHostSetDomainEvent>(meetingTestData.Meeting);\n            newMeetingHostSet.HostId.Should().Be(newOrganizerId);\n        }\n\n        [Test]\n        public void SetHostRole_WhenSettingMemberIsMeetingHost_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newOrganizerId = new MemberId(Guid.NewGuid());\n            var settingMemberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newOrganizerId);\n            meetingTestData.MeetingGroup.JoinToGroupMember(settingMemberId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newOrganizerId, 0);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, settingMemberId, 0);\n            meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, creatorId, settingMemberId);\n            DomainEventsTestHelper.ClearAllDomainEvents(meetingTestData.Meeting);\n\n            meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, settingMemberId, newOrganizerId);\n\n            var newMeetingHostSetEvent = AssertPublishedDomainEvent<NewMeetingHostSetDomainEvent>(meetingTestData.Meeting);\n            newMeetingHostSetEvent.HostId.Should().Be(newOrganizerId);\n        }\n\n        [Test]\n        public void SetAttendeeRole_WhenMeetingHasStarted_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.SetAttendeeRole(meetingTestData.MeetingGroup, creatorId, creatorId);\n            });\n        }\n\n        [Test]\n        public void SetAttendeeRole_WhenSettingMemberIsNotAOrganizerOrHostMeeting_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var settingMemberId = new MemberId(Guid.NewGuid());\n            var newOrganizerId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newOrganizerId);\n            meetingTestData.MeetingGroup.JoinToGroupMember(settingMemberId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newOrganizerId, 0);\n\n            AssertBrokenRule<OnlyMeetingOrGroupOrganizerCanSetMeetingMemberRolesRule>(() =>\n            {\n                meetingTestData.Meeting.SetAttendeeRole(meetingTestData.MeetingGroup, settingMemberId, newOrganizerId);\n            });\n        }\n\n        [Test]\n        public void SetAttendeeRole_WhenMemberIsOrganizer_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var newOrganizerId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(newOrganizerId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newOrganizerId, 0);\n            meetingTestData.Meeting.SetHostRole(meetingTestData.MeetingGroup, creatorId, newOrganizerId);\n\n            meetingTestData.Meeting.SetAttendeeRole(meetingTestData.MeetingGroup, creatorId, newOrganizerId);\n\n            var newMeetingHostSet = AssertPublishedDomainEvent<MemberSetAsAttendeeDomainEvent>(meetingTestData.Meeting);\n            newMeetingHostSet.HostId.Should().Be(newOrganizerId);\n        }\n\n        [Test]\n        public void SetAttendeeRole_WhenMemberIsAlreadyAttendee_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var attendeeId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(attendeeId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, attendeeId, 0);\n\n            AssertBrokenRule<MemberCannotHaveSetAttendeeRoleMoreThanOnceRule>(() =>\n            {\n                meetingTestData.Meeting.SetAttendeeRole(meetingTestData.MeetingGroup, creatorId, attendeeId);\n            });\n        }\n\n        [Test]\n        public void SetAttendeeRole_ForLastOrganizer_BreaksMeetingMustHaveAtLeastOneHostRule()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n\n            AssertBrokenRule<MeetingMustHaveAtLeastOneHostRule>(() =>\n            {\n                meetingTestData.Meeting.SetAttendeeRole(meetingTestData.MeetingGroup, creatorId, creatorId);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingTests : MeetingTestsBase\n    {\n        [Test]\n        public void CancelMeeting_WhenMeetingHasStarted_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.Cancel(creatorId);\n            });\n        }\n\n        [Test]\n        public void CancelMeeting_WhenMeetingHasNotStarted_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var date = DateTime.UtcNow;\n            SystemClock.Set(date);\n\n            meetingTestData.Meeting.Cancel(creatorId);\n\n            var meetingCanceled = AssertPublishedDomainEvent<MeetingCanceledDomainEvent>(meetingTestData.Meeting);\n            meetingCanceled.MeetingId.Should().Be(meetingTestData.Meeting.Id);\n            meetingCanceled.CancelMemberId.Should().Be(creatorId);\n            meetingCanceled.CancelDate.Should().Be(date);\n        }\n\n        [Test]\n        public void RemoveAttendee_WhenMeetingHasStarted_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.RemoveAttendee(new MemberId(Guid.NewGuid()), creatorId, null);\n            });\n        }\n\n        [Test]\n        public void RemoveAttendee_WhenMemberIsNotAttendee_BreaksOnlyActiveAttendeeCanBeRemovedFromMeetingRule()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var attendeeToRemoveId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<OnlyActiveAttendeeCanBeRemovedFromMeetingRule>(() =>\n            {\n                meetingTestData.Meeting.RemoveAttendee(attendeeToRemoveId, creatorId, null);\n            });\n        }\n\n        [Test]\n        public void RemoveAttendee_WhenMemberIsAttendee_AndReasonIsProvided_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var attendeeToRemoveId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(attendeeToRemoveId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, attendeeToRemoveId, 0);\n            const string reason = \"reasonOfRemoval\";\n\n            meetingTestData.Meeting.RemoveAttendee(attendeeToRemoveId, creatorId, reason);\n\n            var meetingAttendeeRemoved = AssertPublishedDomainEvent<MeetingAttendeeRemovedDomainEvent>(meetingTestData.Meeting);\n            meetingAttendeeRemoved.MemberId.Should().Be(attendeeToRemoveId);\n            meetingAttendeeRemoved.MeetingId.Should().Be(meetingTestData.Meeting.Id);\n            meetingAttendeeRemoved.Reason.Should().Be(reason);\n        }\n\n        [Test]\n        public void RemoveAttendee_WhenMemberIsAttendee_AndReasonIsNotProvided_BreaksReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var attendeeToRemoveId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(attendeeToRemoveId);\n            meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, attendeeToRemoveId, 0);\n\n            AssertBrokenRule<ReasonOfRemovingAttendeeFromMeetingMustBeProvidedRule>(() =>\n            {\n                meetingTestData.Meeting.RemoveAttendee(attendeeToRemoveId, creatorId, null);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingTestsBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingCommentingConfigurations;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.MeetingGroups;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    public class MeetingTestsBase : TestBase\n    {\n        protected class MeetingTestDataOptions\n        {\n            internal MemberId CreatorId { get; set; }\n\n            internal MeetingTerm MeetingTerm { get; set; }\n\n            internal Term RvspTerm { get; set; }\n\n            internal int GuestsLimit { get; set; }\n\n            internal int? AttendeesLimit { get; set; }\n\n            internal bool IsMeetingCommentingEnabled { get; set; } = true;\n\n            internal IEnumerable<MemberId> Attendees { get; set; } = Enumerable.Empty<MemberId>();\n        }\n\n        protected class MeetingTestData\n        {\n            public MeetingTestData(MeetingGroup meetingGroup, Meeting meeting, MeetingCommentingConfiguration meetingCommentingConfiguration)\n            {\n                MeetingGroup = meetingGroup;\n                Meeting = meeting;\n                MeetingCommentingConfiguration = meetingCommentingConfiguration;\n            }\n\n            internal MeetingGroup MeetingGroup { get; }\n\n            internal Meeting Meeting { get; }\n\n            internal MeetingCommentingConfiguration MeetingCommentingConfiguration { get; }\n        }\n\n        protected MeetingTestData CreateMeetingTestData(MeetingTestDataOptions options)\n        {\n            var proposalMemberId = options.CreatorId ?? new MemberId(Guid.NewGuid());\n            var meetingProposal = MeetingGroupProposal.ProposeNew(\n                \"name\",\n                \"description\",\n                MeetingGroupLocation.CreateNew(\"Warsaw\", \"PL\"),\n                proposalMemberId);\n\n            meetingProposal.Accept();\n\n            var meetingGroup = meetingProposal.CreateMeetingGroup();\n\n            meetingGroup.SetExpirationDate(DateTime.Now.AddDays(1));\n\n            var meetingTerm = options.MeetingTerm ??\n                              MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(1), DateTime.UtcNow.AddDays(2));\n\n            var rsvpTerm = options.RvspTerm ?? Term.NoTerm;\n            var meeting = meetingGroup.CreateMeeting(\n                \"title\",\n                meetingTerm,\n                \"description\",\n                MeetingLocation.CreateNew(\"Name\", \"Address\", \"PostalCode\", \"City\"),\n                options.AttendeesLimit,\n                options.GuestsLimit,\n                rsvpTerm,\n                MoneyValue.Undefined,\n                new List<MemberId>(),\n                proposalMemberId);\n\n            foreach (var attendee in options.Attendees)\n            {\n                meetingGroup.JoinToGroupMember(attendee);\n                meeting.AddAttendee(meetingGroup, attendee, 0);\n            }\n\n            var meetingCommentingConfiguration = meeting.CreateCommentingConfiguration();\n            if (options.IsMeetingCommentingEnabled)\n            {\n                meetingCommentingConfiguration.EnableCommenting(proposalMemberId, meetingGroup);\n            }\n            else\n            {\n                meetingCommentingConfiguration.DisableCommenting(proposalMemberId, meetingGroup);\n            }\n\n            DomainEventsTestHelper.ClearAllDomainEvents(meetingGroup);\n\n            return new MeetingTestData(meetingGroup, meeting, meetingCommentingConfiguration);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Meetings/MeetingWaitlistTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings.Rules;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Meetings\n{\n    [TestFixture]\n    public class MeetingWaitlistTests : MeetingTestsBase\n    {\n        [Test]\n        public void SignUpMemberToWaitList_WhenMeetingHasStared_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n            });\n        }\n\n        [Test]\n        public void SignUpMemberToWaitList_WhenRsvpTermEnded_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                RvspTerm = Term.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<AttendeeCanBeAddedOnlyInRsvpTermRule>(() =>\n            {\n                meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n            });\n        }\n\n        [Test]\n        public void SignUpMemberToWaitList_WhenMemberIsNotAMemberOfMeetingGroup_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n\n            AssertBrokenRule<MemberOnWaitlistMustBeAMemberOfGroupRule>(() =>\n            {\n                meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, new MemberId(Guid.NewGuid()));\n            });\n        }\n\n        [Test]\n        public void SignUpMemberToWaitList_WhenMemberIsOnTheListAlready_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(memberId);\n\n            meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n\n            AssertBrokenRule<MemberCannotBeMoreThanOnceOnMeetingWaitlistRule>(() =>\n            {\n                meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n            });\n        }\n\n        [Test]\n        public void SignUpMemberToWaitList_WhenAllConditionsAreSatisfied_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(memberId);\n\n            meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n\n            var meetingWaitlistMemberAdded = AssertPublishedDomainEvent<MeetingWaitlistMemberAddedDomainEvent>(meetingTestData.Meeting);\n            meetingWaitlistMemberAdded.MemberId.Should().Be(memberId);\n        }\n\n        [Test]\n        public void SignOffMemberFromWaitList_WhenMeetingHasStared_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId,\n                MeetingTerm = MeetingTerm.CreateNewBetweenDates(DateTime.UtcNow.AddDays(-2), DateTime.UtcNow.AddDays(-1))\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<MeetingCannotBeChangedAfterStartRule>(() =>\n            {\n                meetingTestData.Meeting.SignOffMemberFromWaitlist(memberId);\n            });\n        }\n\n        [Test]\n        public void SignOffMemberFromWaitList_WhenMemberIsNotActiveWaitlistMember_IsNotPossible()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n            var memberId = new MemberId(Guid.NewGuid());\n\n            AssertBrokenRule<NotActiveMemberOfWaitlistCannotBeSignedOffRule>(() =>\n            {\n                meetingTestData.Meeting.SignOffMemberFromWaitlist(memberId);\n            });\n        }\n\n        [Test]\n        public void SignOffMemberFromWaitList_WhenMemberIsOnWaitList_IsSuccessful()\n        {\n            var creatorId = new MemberId(Guid.NewGuid());\n            var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions\n            {\n                CreatorId = creatorId\n            });\n\n            var memberId = new MemberId(Guid.NewGuid());\n            meetingTestData.MeetingGroup.JoinToGroupMember(memberId);\n            meetingTestData.Meeting.SignUpMemberToWaitlist(meetingTestData.MeetingGroup, memberId);\n\n            meetingTestData.Meeting.SignOffMemberFromWaitlist(memberId);\n\n            var memberSignedOffFromMeetingWaitlist = AssertPublishedDomainEvent<MemberSignedOffFromMeetingWaitlistDomainEvent>(meetingTestData.Meeting);\n            memberSignedOffFromMeetingWaitlist.MemberId.Should().Be(memberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/Members/MemberTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Meetings.Domain.Members;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Members.Events;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.Members\n{\n    [TestFixture]\n    public class MemberTests : TestBase\n    {\n        [Test]\n        public void CreateMember_IsSuccessful()\n        {\n            var memberId = new MemberId(Guid.NewGuid());\n            var member = Member.Create(\n                memberId.Value,\n                \"memberLogin\",\n                \"memberEmail@mail.com\",\n                \"John\",\n                \"Doe\",\n                \"John Doe\");\n\n            var memberCreated = AssertPublishedDomainEvent<MemberCreatedDomainEvent>(member);\n\n            memberCreated.MemberId.Should().Be(memberId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/SeedWork/DomainEventsTestHelper.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork\n{\n    public class DomainEventsTestHelper\n    {\n        public static List<IDomainEvent> GetAllDomainEvents(Entity aggregate)\n        {\n            List<IDomainEvent> domainEvents = [];\n\n            if (aggregate.DomainEvents != null)\n            {\n                domainEvents.AddRange(aggregate.DomainEvents);\n            }\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = typeof(Entity).IsAssignableFrom(field.FieldType);\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    domainEvents.AddRange(GetAllDomainEvents(entity).ToList());\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                domainEvents.AddRange(GetAllDomainEvents(entityItem));\n                            }\n                        }\n                    }\n                }\n            }\n\n            return domainEvents;\n        }\n\n        public static void ClearAllDomainEvents(Entity aggregate)\n        {\n            aggregate.ClearDomainEvents();\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = field.FieldType.IsAssignableFrom(typeof(Entity));\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    ClearAllDomainEvents(entity);\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                ClearAllDomainEvents(entityItem);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Meetings/Tests/UnitTests/SeedWork/TestBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Meetings.Domain.UnitTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        public static T AssertPublishedDomainEvent<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static void AssertDomainEventNotPublished<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n            Assert.That(domainEvent, Is.Null);\n        }\n\n        public static List<T> AssertPublishedDomainEvents<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvents = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().ToList();\n\n            if (!domainEvents.Any())\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvents;\n        }\n\n        public static void AssertBrokenRule<TRule>(TestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.Catch<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                businessRuleValidationException.BrokenRule.Should().BeOfType<TRule>();\n            }\n        }\n\n        public static void AssertBrokenRule<TRule>(AsyncTestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.CatchAsync<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            SystemClock.Reset();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/CompanyName.MyMeetings.Modules.Payments.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Administration\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\Meetings\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\Registrations\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents.csproj\" />\n    <ProjectReference Include=\"..\\..\\UserAccess\\IntegrationEvents\\CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Projections/IProjector.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections\n{\n    public interface IProjector\n    {\n        Task Project(IDomainEvent @event);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Projections/ProjectorBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections\n{\n    internal abstract class ProjectorBase\n    {\n        protected static Task When(IDomainEvent @event)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Configuration/Queries/IQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries\n{\n    public interface IQueryHandler<in TQuery, TResult> :\n        IRequestHandler<TQuery, TResult>\n        where TQuery : IQuery<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/CommandBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public abstract class CommandBase : ICommand\n    {\n        public Guid Id { get; }\n\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n\n    public abstract class CommandBase<TResult> : ICommand<TResult>\n    {\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/ICommand.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public interface ICommand<out TResult> : IRequest<TResult>\n    {\n        Guid Id { get; }\n    }\n\n    public interface ICommand : IRequest\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/IPaymentsModule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public interface IPaymentsModule\n    {\n        Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n        Task ExecuteCommandAsync(ICommand command);\n\n        Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/IQuery.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public interface IQuery<out TResult> : IRequest<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Contracts/QueryBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Contracts\n{\n    public abstract class QueryBase<TResult> : IQuery<TResult>\n    {\n        public Guid Id { get; }\n\n        protected QueryBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected QueryBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/CreateMeetingFee/CreateMeetingFeeCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFee\n{\n    public class CreateMeetingFeeCommand : InternalCommandBase<Guid>\n    {\n        [JsonConstructor]\n        public CreateMeetingFeeCommand(\n            Guid id, Guid payerId, Guid meetingId, decimal value, string currency)\n            : base(id)\n        {\n            PayerId = payerId;\n            MeetingId = meetingId;\n            Value = value;\n            Currency = currency;\n        }\n\n        internal decimal Value { get; }\n\n        internal string Currency { get; }\n\n        internal Guid PayerId { get; }\n\n        internal Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/CreateMeetingFee/CreateMeetingFeeCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFee\n{\n    internal class CreateMeetingFeeCommandHandler : ICommandHandler<CreateMeetingFeeCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        internal CreateMeetingFeeCommandHandler(\n            IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public Task<Guid> Handle(CreateMeetingFeeCommand command, CancellationToken cancellationToken)\n        {\n            var meetingFee = MeetingFee.Create(\n                new PayerId(command.PayerId),\n                new MeetingId(command.MeetingId),\n                MoneyValue.Of(command.Value, command.Currency));\n\n            _aggregateStore.AppendChanges(meetingFee);\n\n            return Task.FromResult(meetingFee.Id);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/CreateMeetingFeePayment/CreateMeetingFeePaymentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFeePayment\n{\n    public class CreateMeetingFeePaymentCommand : CommandBase<Guid>\n    {\n        public CreateMeetingFeePaymentCommand(Guid meetingFeeId)\n        {\n            MeetingFeeId = meetingFeeId;\n        }\n\n        public Guid MeetingFeeId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/CreateMeetingFeePayment/CreateMeetingFeePaymentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFeePayment\n{\n    internal class CreateMeetingFeePaymentCommandHandler : ICommandHandler<CreateMeetingFeePaymentCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        internal CreateMeetingFeePaymentCommandHandler(IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public Task<Guid> Handle(CreateMeetingFeePaymentCommand command, CancellationToken cancellationToken)\n        {\n            var meetingFeePayment = MeetingFeePayment.Create(new MeetingFeeId(command.MeetingFeeId));\n\n            _aggregateStore.AppendChanges(meetingFeePayment);\n\n            return Task.FromResult(meetingFeePayment.Id);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/GetMeetingFees/GetMeetingFeesQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.GetMeetingFees\n{\n    public class GetMeetingFeesQuery : QueryBase<List<MeetingFeeDto>>\n    {\n        public GetMeetingFeesQuery(Guid meetingId)\n        {\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/GetMeetingFees/GetMeetingFeesQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.GetMeetingFees\n{\n    internal class GetMeetingFeesQueryHandler : IQueryHandler<GetMeetingFeesQuery, List<MeetingFeeDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetMeetingFeesQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<MeetingFeeDto>> Handle(GetMeetingFeesQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [MeetingFee].MeetingFeeId AS [{nameof(MeetingFeeDto.MeetingFeeId)}],\n                                    [MeetingFee].PayerId AS [{nameof(MeetingFeeDto.PayerId)}], \n                                    [MeetingFee].FeeCurrency AS [{nameof(MeetingFeeDto.FeeCurrency)}], \n                                    [MeetingFee].FeeValue AS [{nameof(MeetingFeeDto.FeeValue)}],\n                                    [MeetingFee].MeetingId AS [{nameof(MeetingFeeDto.MeetingId)}], \n                                    [MeetingFee].Status AS [{nameof(MeetingFeeDto.Status)}]\n                                FROM [payments].[MeetingFees] AS [MeetingFee] \n                                WHERE [MeetingFee].MeetingId = @MeetingId\n                                \"\"\";\n            var meetingFees = await connection.QueryAsync<MeetingFeeDto>(\n                sql,\n                new\n                {\n                    query.MeetingId\n                });\n\n            return meetingFees.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/GetMeetingFees/MeetingFeeDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.GetMeetingFees\n{\n    public class MeetingFeeDto\n    {\n        public Guid MeetingFeeId { get; }\n\n        public Guid PayerId { get; }\n\n        public Guid MeetingId { get; }\n\n        public decimal FeeValue { get; }\n\n        public string FeeCurrency { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/GetMeetingFees/MeetingFeesProjector.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.GetMeetingFees\n{\n    internal class MeetingFeesProjector : ProjectorBase, IProjector\n    {\n        private readonly IDbConnection _connection;\n\n        public MeetingFeesProjector(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _connection = sqlConnectionFactory.GetOpenConnection();\n        }\n\n        public async Task Project(IDomainEvent @event)\n        {\n            await When((dynamic)@event);\n        }\n\n        private async Task When(MeetingFeeCreatedDomainEvent meetingFeeCreated)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.MeetingFees \" +\n                \"([MeetingFeeId], [PayerId], [MeetingId], [FeeValue], [FeeCurrency], [Status]) \" +\n                \"VALUES (@MeetingFeeId, @PayerId, @MeetingId, @FeeValue, @FeeCurrency, @Status)\",\n                new\n                {\n                    meetingFeeCreated.MeetingFeeId,\n                    meetingFeeCreated.PayerId,\n                    meetingFeeCreated.MeetingId,\n                    meetingFeeCreated.FeeValue,\n                    meetingFeeCreated.FeeCurrency,\n                    meetingFeeCreated.Status\n                });\n        }\n\n        private async Task When(MeetingFeePaidDomainEvent meetingFeePaid)\n        {\n            await UpdateStatus(meetingFeePaid.MeetingFeeId, meetingFeePaid.Status);\n        }\n\n        private async Task When(MeetingFeeExpiredDomainEvent meetingFeeExpired)\n        {\n            await UpdateStatus(meetingFeeExpired.MeetingFeeId, meetingFeeExpired.Status);\n        }\n\n        private async Task When(MeetingFeeCanceledDomainEvent meetingFeeCanceled)\n        {\n            await UpdateStatus(meetingFeeCanceled.MeetingFeeId, meetingFeeCanceled.Status);\n        }\n\n        private async Task UpdateStatus(Guid meetingFeeId, string status)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.MeetingFees \" +\n                \"SET \" +\n                \"[Status] = @Status \" +\n                \"WHERE [MeetingFeeId] = @MeetingFeeId\",\n                new\n                {\n                    meetingFeeId,\n                    status\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeeAsPaid/MarkMeetingFeeAsPaidCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid\n{\n    public class MarkMeetingFeeAsPaidCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public MarkMeetingFeeAsPaidCommand(Guid meetingFeeId)\n            : base(Guid.Empty)\n        {\n            MeetingFeeId = meetingFeeId;\n        }\n\n        public Guid MeetingFeeId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeeAsPaid/MarkMeetingFeeAsPaidCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid\r\n{\r\n    internal class MarkMeetingFeeAsPaidCommandHandler : ICommandHandler<MarkMeetingFeeAsPaidCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        internal MarkMeetingFeeAsPaidCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(MarkMeetingFeeAsPaidCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingFee =\r\n                await _aggregateStore.Load(new MeetingFeeId(command.MeetingFeeId));\r\n\r\n            meetingFee.MarkAsPaid();\r\n\r\n            _aggregateStore.AppendChanges(meetingFee);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeeAsPaid/MeetingFeePaidNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid\n{\n    public class MeetingFeePaidNotification : DomainNotificationBase<MeetingFeePaidDomainEvent>\n    {\n        public MeetingFeePaidNotification(MeetingFeePaidDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeeAsPaid/MeetingFeePaidNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\r\nusing MediatR;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid\r\n{\r\n    public class MeetingFeePaidNotificationHandler : INotificationHandler<MeetingFeePaidNotification>\r\n    {\r\n        private readonly IEventsBus _eventsBus;\r\n\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public MeetingFeePaidNotificationHandler(IEventsBus eventsBus, IAggregateStore aggregateStore)\r\n        {\r\n            _eventsBus = eventsBus;\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(MeetingFeePaidNotification notification, CancellationToken cancellationToken)\r\n        {\r\n            var meetingFee = await _aggregateStore.Load(new MeetingFeeId(notification.DomainEvent.MeetingFeeId));\r\n\r\n            var meetingFeeSnapshot = meetingFee.GetSnapshot();\r\n\r\n            await _eventsBus.Publish(new MeetingFeePaidIntegrationEvent(\r\n                notification.Id,\r\n                notification.DomainEvent.OccurredOn,\r\n                meetingFeeSnapshot.PayerId,\r\n                meetingFeeSnapshot.MeetingId));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeePaymentAsPaid/MarkMeetingFeePaymentAsPaidCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid\n{\n    public class MarkMeetingFeePaymentAsPaidCommand : CommandBase\n    {\n        public MarkMeetingFeePaymentAsPaidCommand(Guid meetingFeePaymentId)\n        {\n            MeetingFeePaymentId = meetingFeePaymentId;\n        }\n\n        public Guid MeetingFeePaymentId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeePaymentAsPaid/MarkMeetingFeePaymentAsPaidCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid\r\n{\r\n    internal class MarkMeetingFeePaymentAsPaidCommandHandler : ICommandHandler<MarkMeetingFeePaymentAsPaidCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        internal MarkMeetingFeePaymentAsPaidCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(MarkMeetingFeePaymentAsPaidCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var meetingFeePayment =\r\n                await _aggregateStore.Load(new MeetingFeePaymentId(command.MeetingFeePaymentId));\r\n\r\n            meetingFeePayment.MarkAsPaid();\r\n\r\n            _aggregateStore.AppendChanges(meetingFeePayment);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeePaymentAsPaid/MeetingFeePaymentPaidNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid\n{\n    public class MeetingFeePaymentPaidNotification : DomainNotificationBase<MeetingFeePaymentPaidDomainEvent>\n    {\n        public MeetingFeePaymentPaidNotification(MeetingFeePaymentPaidDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MarkMeetingFeePaymentAsPaid/MeetingFeePaymentPaidNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid\n{\n    public class MeetingFeePaymentPaidNotificationHandler : INotificationHandler<MeetingFeePaymentPaidNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        private readonly IAggregateStore _aggregateStore;\n\n        public MeetingFeePaymentPaidNotificationHandler(\n            ICommandsScheduler commandsScheduler,\n            IAggregateStore aggregateStore)\n        {\n            _commandsScheduler = commandsScheduler;\n            _aggregateStore = aggregateStore;\n        }\n\n        public async Task Handle(MeetingFeePaymentPaidNotification notification, CancellationToken cancellationToken)\n        {\n            var meetingFeePayment =\n                await _aggregateStore.Load(new MeetingFeePaymentId(notification.DomainEvent.MeetingFeePaymentId));\n\n            var meetingFeePaymentSnapshot = meetingFeePayment.GetSnapshot();\n            await _commandsScheduler.EnqueueAsync(\n                new MarkMeetingFeeAsPaidCommand(\n                    meetingFeePaymentSnapshot.MeetingFeeId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/MeetingFees/MeetingAttendeeAddedIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFee;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees\n{\n    internal class MeetingAttendeeAddedIntegrationEventHandler : INotificationHandler<MeetingAttendeeAddedIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal MeetingAttendeeAddedIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(MeetingAttendeeAddedIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            if (notification.FeeValue.HasValue)\n            {\n                await _commandsScheduler.EnqueueAsync(new CreateMeetingFeeCommand(\n                    Guid.NewGuid(),\n                    notification.AttendeeId,\n                    notification.MeetingId,\n                    notification.FeeValue.Value,\n                    notification.FeeCurrency));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/CreatePayer/CreatePayerCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.CreatePayer\n{\n    public class CreatePayerCommand : InternalCommandBase<Guid>\n    {\n        internal Guid UserId { get; }\n\n        internal string Login { get; }\n\n        internal string Email { get; }\n\n        internal string FirstName { get; }\n\n        internal string LastName { get; }\n\n        internal string Name { get; }\n\n        [JsonConstructor]\n        public CreatePayerCommand(\n            Guid id,\n            Guid userId,\n            string login,\n            string email,\n            string firstName,\n            string lastName,\n            string name)\n            : base(id)\n        {\n            UserId = userId;\n            Login = login;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/CreatePayer/CreatePayerCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.CreatePayer\n{\n    internal class CreatePayerCommandHandler : ICommandHandler<CreatePayerCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        public CreatePayerCommandHandler(IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public Task<Guid> Handle(CreatePayerCommand request, CancellationToken cancellationToken)\n        {\n            var payer = Payer.Create(\n                request.UserId,\n                request.Login,\n                request.Email,\n                request.FirstName,\n                request.LastName,\n                request.Name);\n\n            _aggregateStore.AppendChanges(payer);\n\n            return Task.FromResult(payer.Id);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/CreatePayer/NewUserRegisteredIntegrationEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.CreatePayer\n{\n    internal class NewUserRegisteredIntegrationEventHandler : INotificationHandler<NewUserRegisteredIntegrationEvent>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        internal NewUserRegisteredIntegrationEventHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(NewUserRegisteredIntegrationEvent notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new\n                CreatePayerCommand(\n                    Guid.NewGuid(),\n                    notification.UserId,\n                    notification.Login,\n                    notification.Email,\n                    notification.FirstName,\n                    notification.LastName,\n                    notification.Name));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/GetPayer/GetPayerQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayer\n{\n    public class GetPayerQuery : QueryBase<PayerDto>\n    {\n        public GetPayerQuery(Guid payerId)\n        {\n            PayerId = payerId;\n        }\n\n        public Guid PayerId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/GetPayer/GetPayerQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayer\n{\n    internal class GetPayerQueryHandler : IQueryHandler<GetPayerQuery, PayerDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetPayerQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<PayerDto> Handle(GetPayerQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                               SELECT \n                                   [Payer].[Id] as [{nameof(PayerDto.Id)}], \n                                   [Payer].[Login] as [{nameof(PayerDto.Login)}], \n                                   [Payer].[Email] as [{nameof(PayerDto.Email)}], \n                                   [Payer].[FirstName] as [{nameof(PayerDto.FirstName)}], \n                                   [Payer].[LastName] as [{nameof(PayerDto.LastName)}], \n                                   [Payer].[Name] as [{nameof(PayerDto.Name)}]\n                               FROM [payments].[Payers] AS [Payer] \n                               WHERE [Payer].[Id] = @PayerId\n                               \"\"\";\n\n            return await connection.QuerySingleAsync<PayerDto>(sql, new\n            {\n                query.PayerId\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/GetPayer/PayerDetailsProjector.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers.Events;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayer\n{\n    internal class PayerDetailsProjector : ProjectorBase, IProjector\n    {\n        private readonly IDbConnection _connection;\n\n        public PayerDetailsProjector(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _connection = sqlConnectionFactory.GetOpenConnection();\n        }\n\n        public async Task Project(IDomainEvent @event)\n        {\n            await When((dynamic)@event);\n        }\n\n        private async Task When(PayerCreatedDomainEvent payerCreated)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.Payers \" +\n                \"([Id], [Login], [Email], [FirstName], [LastName], \" +\n                \"[Name]) \" +\n                \"VALUES (@PayerId, @Login, @Email, @FirstName, @LastName,\" +\n                \"@Name)\",\n                new\n                {\n                    payerCreated.PayerId,\n                    payerCreated.FirstName,\n                    payerCreated.LastName,\n                    payerCreated.Email,\n                    payerCreated.Login,\n                    payerCreated.Name\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/GetPayer/PayerDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayer\n{\n    public class PayerDto\n    {\n        public Guid Id { get; set; }\n\n        public string Login { get; set; }\n\n        public string Email { get; set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Payers/GetPayerEmail/PayerEmailProvider.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayerEmail\n{\n    public static class PayerEmailProvider\n    {\n        public static async Task<string> GetPayerEmail(Guid payerId, ISqlConnectionFactory sqlConnectionFactory)\n        {\n            var connection = sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [Payer].[Email] \n                                FROM [payments].[Payers] AS [Payer] \n                                WHERE [Payer].[Id] = @PayerId\n                                \"\"\";\n\n            return await connection.QuerySingleAsync<string>(sql, new\n            {\n                payerId\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/ActivatePriceListItem/ActivatePriceListItemCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ActivatePriceListItem\n{\n    public class ActivatePriceListItemCommand : CommandBase\n    {\n        public ActivatePriceListItemCommand(Guid priceListItemId)\n        {\n            PriceListItemId = priceListItemId;\n        }\n\n        public Guid PriceListItemId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/ActivatePriceListItem/ActivatePriceListItemCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ActivatePriceListItem\r\n{\r\n    internal class ActivatePriceListItemCommandHandler : ICommandHandler<ActivatePriceListItemCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public ActivatePriceListItemCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(ActivatePriceListItemCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var priceListItem = await _aggregateStore.Load(new PriceListItemId(command.PriceListItemId));\r\n\r\n            if (priceListItem == null)\r\n            {\r\n                throw new InvalidCommandException([\"Pricelist item for activation must exist.\"]);\r\n            }\r\n\r\n            priceListItem.Activate();\r\n\r\n            _aggregateStore.AppendChanges(priceListItem);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/ChangePriceListItemAttributes/ChangePriceListItemAttributesCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ChangePriceListItemAttributes\n{\n    public class ChangePriceListItemAttributesCommand : CommandBase\n    {\n        public ChangePriceListItemAttributesCommand(Guid priceListItemId, string countryCode, string subscriptionPeriodCode, string categoryCode, decimal priceValue, string priceCurrency)\n        {\n            PriceListItemId = priceListItemId;\n            CountryCode = countryCode;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CategoryCode = categoryCode;\n            PriceValue = priceValue;\n            PriceCurrency = priceCurrency;\n        }\n\n        public Guid PriceListItemId { get; }\n\n        public string CountryCode { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CategoryCode { get; }\n\n        public decimal PriceValue { get; }\n\n        public string PriceCurrency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/ChangePriceListItemAttributes/ChangePriceListItemAttributesCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.ChangePriceListItemAttributes\r\n{\r\n    internal class ChangePriceListItemAttributesCommandHandler : ICommandHandler<ChangePriceListItemAttributesCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public ChangePriceListItemAttributesCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(ChangePriceListItemAttributesCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var priceListItem = await _aggregateStore.Load(new PriceListItemId(command.PriceListItemId));\r\n\r\n            if (priceListItem == null)\r\n            {\r\n                throw new InvalidCommandException([\"Pricelist item for changing must exist.\"]);\r\n            }\r\n\r\n            priceListItem.ChangeAttributes(\r\n                command.CountryCode,\r\n                SubscriptionPeriod.Of(command.SubscriptionPeriodCode),\r\n                PriceListItemCategory.Of(command.CategoryCode),\r\n                MoneyValue.Of(command.PriceValue, command.PriceCurrency));\r\n\r\n            _aggregateStore.AppendChanges(priceListItem);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/CreatePriceListItem/CreatePriceListItemCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.CreatePriceListItem\n{\n    public class CreatePriceListItemCommand : CommandBase<Guid>\n    {\n        public string CountryCode { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CategoryCode { get; }\n\n        public decimal PriceValue { get; }\n\n        public string PriceCurrency { get; }\n\n        public CreatePriceListItemCommand(string subscriptionPeriodCode, string categoryCode, string countryCode, decimal priceValue, string priceCurrency)\n        {\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CategoryCode = categoryCode;\n            CountryCode = countryCode;\n            PriceValue = priceValue;\n            PriceCurrency = priceCurrency;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/CreatePriceListItem/CreatePriceListItemCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.CreatePriceListItem\n{\n    internal class CreatePriceListItemCommandHandler : ICommandHandler<CreatePriceListItemCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        internal CreatePriceListItemCommandHandler(IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public Task<Guid> Handle(CreatePriceListItemCommand command, CancellationToken cancellationToken)\n        {\n            var priceListItem = PriceListItem.Create(\n                command.CountryCode,\n                SubscriptionPeriod.Of(command.SubscriptionPeriodCode),\n                PriceListItemCategory.Of(command.CategoryCode),\n                MoneyValue.Of(command.PriceValue, command.PriceCurrency));\n\n            _aggregateStore.AppendChanges(priceListItem);\n\n            return Task.FromResult(priceListItem.Id);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/DeactivatePriceListItem/DeactivatePriceListItemCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.DeactivatePriceListItem\n{\n    public class DeactivatePriceListItemCommand : CommandBase\n    {\n        public DeactivatePriceListItemCommand(Guid priceListItemId)\n        {\n            PriceListItemId = priceListItemId;\n        }\n\n        public Guid PriceListItemId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/DeactivatePriceListItem/DeactivatePriceListItemCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.DeactivatePriceListItem\r\n{\r\n    internal class DeactivatePriceListItemCommandHandler : ICommandHandler<DeactivatePriceListItemCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public DeactivatePriceListItemCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(DeactivatePriceListItemCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var priceListItem = await _aggregateStore.Load(new PriceListItemId(command.PriceListItemId));\r\n\r\n            if (priceListItem == null)\r\n            {\r\n                throw new InvalidCommandException([\"Pricelist item for deactivation must exist.\"]);\r\n            }\r\n\r\n            priceListItem.Deactivate();\r\n\r\n            _aggregateStore.AppendChanges(priceListItem);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItem/GetPriceListItemQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItem\n{\n    public class GetPriceListItemQuery : QueryBase<PriceListItemMoneyValueDto>\n    {\n        public GetPriceListItemQuery(string countryCode, string categoryCode, string periodTypeCode)\n        {\n            CountryCode = countryCode;\n            CategoryCode = categoryCode;\n            PeriodTypeCode = periodTypeCode;\n        }\n\n        public string CountryCode { get; }\n\n        public string CategoryCode { get; }\n\n        public string PeriodTypeCode { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItem/GetPriceListItemQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItem\n{\n    internal class GetPriceListItemQueryHandler : IQueryHandler<GetPriceListItemQuery, PriceListItemMoneyValueDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetPriceListItemQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<PriceListItemMoneyValueDto> Handle(\n            GetPriceListItemQuery query,\n            CancellationToken cancellationToken)\n        {\n            using var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [PriceListItem].[MoneyCurrency] AS [{nameof(PriceListItemMoneyValueDto.Currency)}], \n                                    [PriceListItem].[MoneyValue] AS [{nameof(PriceListItemMoneyValueDto.Value)}] \n                                FROM [payments].[PriceListItems] AS [PriceListItem] \n                                WHERE \n                                    [PriceListItem].[IsActive] = 1 \n                                    AND [PriceListItem].[SubscriptionPeriodCode] = @PeriodTypeCode \n                                    AND [PriceListItem].[CategoryCode] = @CategoryCode \n                                    AND [PriceListItem].[CountryCode] = @CountryCode \n                                \"\"\";\n            return await connection.QuerySingleAsync<PriceListItemMoneyValueDto>(\n                sql,\n                new\n                {\n                    query.CategoryCode,\n                    query.PeriodTypeCode,\n                    query.CountryCode\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItem/PriceListItemMoneyValueDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItem\n{\n    public class PriceListItemMoneyValueDto\n    {\n        public decimal Value { get; set; }\n\n        public string Currency { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItem/PriceListItemsProjector.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItem\n{\n    internal class PriceListItemsProjector : ProjectorBase, IProjector\n    {\n        private readonly IDbConnection _connection;\n\n        public PriceListItemsProjector(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _connection = sqlConnectionFactory.GetOpenConnection();\n        }\n\n        public async Task Project(IDomainEvent @event)\n        {\n            await When((dynamic)@event);\n        }\n\n        private async Task When(PriceListItemCreatedDomainEvent @event)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.PriceListItems \" +\n                \"([Id], [SubscriptionPeriodCode], [CategoryCode], [CountryCode], [MoneyValue], [MoneyCurrency], [IsActive])\" +\n                \"VALUES (@PriceListItemId, @SubscriptionPeriodCode, @CategoryCode, @CountryCode, @Price, @Currency, @IsActive)\",\n                new\n                {\n                    @event.PriceListItemId,\n                    @event.SubscriptionPeriodCode,\n                    @event.CategoryCode,\n                    @event.CountryCode,\n                    @event.Price,\n                    @event.Currency,\n                    @event.IsActive\n                });\n        }\n\n        private async Task When(PriceListItemActivatedDomainEvent @event)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.PriceListItems \" +\n                \"SET [IsActive] = 'true' \" +\n                \"WHERE [Id] = @PriceListItemId\",\n                new\n                {\n                    @event.PriceListItemId\n                });\n        }\n\n        private async Task When(PriceListItemDeactivatedDomainEvent @event)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.PriceListItems \" +\n                \"SET [IsActive] = 'false' \" +\n                \"WHERE [Id] = @PriceListItemId\",\n                new\n                {\n                    @event.PriceListItemId\n                });\n        }\n\n        private async Task When(PriceListItemAttributesChangedDomainEvent @event)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.PriceListItems \" +\n                \"SET \" +\n                    \"[SubscriptionPeriodCode] = @SubscriptionPeriodCode,\" +\n                    \"[CountryCode] = @CountryCode,\" +\n                    \"[CategoryCode] = @CategoryCode,\" +\n                    \"[MoneyValue] = @Price,\" +\n                    \"[MoneyCurrency] = @Currency \" +\n                \"WHERE [Id] = @PriceListItemId\",\n                new\n                {\n                    @event.PriceListItemId,\n                    @event.SubscriptionPeriodCode,\n                    @event.CountryCode,\n                    @event.CategoryCode,\n                    @event.Price,\n                    @event.Currency\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItems/GetPriceListItemsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItems\n{\n    public class GetPriceListItemsQuery : QueryBase<List<PriceListItemDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/GetPriceListItems/GetPriceListItemsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItems\n{\n    internal class GetPriceListItemsQueryHandler : IQueryHandler<GetPriceListItemsQuery, List<PriceListItemDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetPriceListItemsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<PriceListItemDto>> Handle(GetPriceListItemsQuery request, CancellationToken cancellationToken)\n        {\n            return await PriceListFactory.GetPriceListItems(_sqlConnectionFactory.GetOpenConnection());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/PriceListFactory.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems\n{\n    public static class PriceListFactory\n    {\n        public static async Task<PriceList> CreatePriceList(IDbConnection connection)\n        {\n            var priceListItemList = await GetPriceListItems(connection);\n\n            var priceListItems = priceListItemList\n                .Select(x =>\n                    new PriceListItemData(\n                        x.CountryCode,\n                        SubscriptionPeriod.Of(x.SubscriptionPeriodCode),\n                        MoneyValue.Of(x.MoneyValue, x.MoneyCurrency),\n                        PriceListItemCategory.Of(x.CategoryCode)))\n                .ToList();\n\n            // This is place for selecting pricing strategy based on provided data and the system state.\n            IPricingStrategy pricingStrategy = new DirectValueFromPriceListPricingStrategy(priceListItems);\n\n            return PriceList.Create(\n                priceListItems,\n                pricingStrategy);\n        }\n\n        public static async Task<List<PriceListItemDto>> GetPriceListItems(IDbConnection connection)\n        {\n            const string sql = $\"\"\"\n                                SELECT\n                                    [PriceListItem].[CountryCode] AS [{nameof(PriceListItemDto.CountryCode)}],\n                                    [PriceListItem].[SubscriptionPeriodCode] AS [{nameof(PriceListItemDto.SubscriptionPeriodCode)}],\n                                    [PriceListItem].[MoneyValue] AS [{nameof(PriceListItemDto.MoneyValue)}],\n                                    [PriceListItem].[MoneyCurrency] AS [{nameof(PriceListItemDto.MoneyCurrency)}],\n                                    [PriceListItem].[CategoryCode] AS [{nameof(PriceListItemDto.CategoryCode)}]\n                                FROM [payments].[PriceListItems] AS [PriceListItem]\n                                WHERE [PriceListItem].[IsActive] = 1\n                                \"\"\";\n            var priceListItems = await connection.QueryAsync<PriceListItemDto>(\n                sql);\n\n            var priceListItemList = priceListItems.AsList();\n            return priceListItemList;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/PriceListItems/PriceListItemDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems\n{\n    public class PriceListItemDto\n    {\n        public string CountryCode { get; set; }\n\n        public string SubscriptionPeriodCode { get; set; }\n\n        public decimal MoneyValue { get; set; }\n\n        public string MoneyCurrency { get; set; }\n\n        public string CategoryCode { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/BuySubscription/BuySubscriptionCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription\n{\n    public class BuySubscriptionCommand : CommandBase<Guid>\n    {\n        public BuySubscriptionCommand(\n            string subscriptionTypeCode,\n            string countryCode,\n            decimal value,\n            string currency)\n        {\n            SubscriptionTypeCode = subscriptionTypeCode;\n            CountryCode = countryCode;\n            Value = value;\n            Currency = currency;\n        }\n\n        public string SubscriptionTypeCode { get; }\n\n        public string CountryCode { get; }\n\n        public decimal Value { get; }\n\n        public string Currency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/BuySubscription/BuySubscriptionCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription\n{\n    internal class BuySubscriptionCommandHandler : ICommandHandler<BuySubscriptionCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        private readonly IPayerContext _payerContext;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        internal BuySubscriptionCommandHandler(\n            IAggregateStore aggregateStore,\n            IPayerContext payerContext,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _aggregateStore = aggregateStore;\n            _payerContext = payerContext;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<Guid> Handle(BuySubscriptionCommand command, CancellationToken cancellationToken)\n        {\n            var priceList = await PriceListFactory.CreatePriceList(_sqlConnectionFactory.GetOpenConnection());\n\n            var subscription = SubscriptionPayment.Buy(\n                _payerContext.PayerId,\n                SubscriptionPeriod.Of(command.SubscriptionTypeCode),\n                command.CountryCode,\n                MoneyValue.Of(command.Value, command.Currency),\n                priceList);\n\n            _aggregateStore.AppendChanges(subscription);\n\n            return subscription.Id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/BuySubscriptionRenewal/BuySubscriptionRenewalCommand.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscriptionRenewal\n{\n    public class BuySubscriptionRenewalCommand : CommandBase<Guid>\n    {\n        public BuySubscriptionRenewalCommand(\n            Guid subscriptionId,\n            string subscriptionTypeCode,\n            string countryCode,\n            decimal value,\n            string currency)\n        {\n            SubscriptionId = subscriptionId;\n            SubscriptionTypeCode = subscriptionTypeCode;\n            CountryCode = countryCode;\n            Value = value;\n            Currency = currency;\n        }\n\n        public Guid SubscriptionId { get; }\n\n        public string SubscriptionTypeCode { get; }\n\n        public string CountryCode { get; }\n\n        public decimal Value { get; }\n\n        public string Currency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/BuySubscriptionRenewal/BuySubscriptionRenewalCommandHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscriptionRenewal\n{\n    internal class BuySubscriptionRenewalCommandHandler : ICommandHandler<BuySubscriptionRenewalCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        private readonly IPayerContext _payerContext;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        internal BuySubscriptionRenewalCommandHandler(\n            IAggregateStore aggregateStore,\n            IPayerContext payerContext,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _aggregateStore = aggregateStore;\n            _payerContext = payerContext;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<Guid> Handle(BuySubscriptionRenewalCommand command, CancellationToken cancellationToken)\n        {\n            var priceList = await PriceListFactory.CreatePriceList(_sqlConnectionFactory.GetOpenConnection());\n\n            var subscriptionId = new SubscriptionId(command.SubscriptionId);\n\n            var subscription = await _aggregateStore.Load(new SubscriptionId(command.SubscriptionId));\n\n            if (subscription == null)\n            {\n                throw new InvalidCommandException([\"Subscription for renewal must exist.\"]);\n            }\n\n            var subscriptionRenewalPayment = SubscriptionRenewalPayment.Buy(\n                _payerContext.PayerId,\n                subscriptionId,\n                SubscriptionPeriod.Of(command.SubscriptionTypeCode),\n                command.CountryCode,\n                MoneyValue.Of(command.Value, command.Currency),\n                priceList);\n\n            _aggregateStore.AppendChanges(subscriptionRenewalPayment);\n\n            return subscriptionRenewalPayment.Id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/CreateSubscription/CreateSubscriptionCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription\n{\n    public class CreateSubscriptionCommand : InternalCommandBase<Guid>\n    {\n        public Guid SubscriptionPaymentId { get; }\n\n        [JsonConstructor]\n        public CreateSubscriptionCommand(\n            Guid id,\n            Guid subscriptionPaymentId)\n            : base(id)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/CreateSubscription/CreateSubscriptionCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription\n{\n    internal class CreateSubscriptionCommandHandler : ICommandHandler<CreateSubscriptionCommand, Guid>\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        internal CreateSubscriptionCommandHandler(\n            IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public async Task<Guid> Handle(CreateSubscriptionCommand command, CancellationToken cancellationToken)\n        {\n            var subscriptionPayment =\n                await _aggregateStore.Load(new SubscriptionPaymentId(command.SubscriptionPaymentId));\n\n            var subscription = Subscription.Create(subscriptionPayment.GetSnapshot());\n\n            _aggregateStore.AppendChanges(subscription);\n\n            return subscription.Id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/CreateSubscription/SubscriptionCreatedEnqueueEmailConfirmationHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayerEmail;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionCreationConfirmationEmail;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription\n{\n    public class SubscriptionCreatedEnqueueEmailConfirmationHandler : INotificationHandler<SubscriptionCreatedNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public SubscriptionCreatedEnqueueEmailConfirmationHandler(\n            ICommandsScheduler commandsScheduler,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _commandsScheduler = commandsScheduler;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(SubscriptionCreatedNotification notification, CancellationToken cancellationToken)\n        {\n            var payerEmail = await PayerEmailProvider.GetPayerEmail(\n                notification.DomainEvent.PayerId,\n                _sqlConnectionFactory);\n\n            await _commandsScheduler.EnqueueAsync(new SendSubscriptionCreationConfirmationEmailCommand(\n                Guid.NewGuid(),\n                new SubscriptionId(notification.DomainEvent.SubscriptionId),\n                payerEmail));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/CreateSubscription/SubscriptionCreatedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription\n{\n    public class SubscriptionCreatedNotification : DomainNotificationBase<SubscriptionCreatedDomainEvent>\n    {\n        [JsonConstructor]\n        protected SubscriptionCreatedNotification(SubscriptionCreatedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/CreateSubscription/SubscriptionCreatedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription\n{\n    public class SubscriptionCreatedNotificationHandler : INotificationHandler<SubscriptionCreatedNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public SubscriptionCreatedNotificationHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(SubscriptionCreatedNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new SubscriptionExpirationDateChangedIntegrationEvent(\n                notification.Id,\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.PayerId,\n                notification.DomainEvent.ExpirationDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscription/ExpireSubscriptionCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscription\n{\n    public class ExpireSubscriptionCommand : InternalCommandBase\n    {\n        public Guid SubscriptionId { get; }\n\n        [JsonConstructor]\n        public ExpireSubscriptionCommand(\n            Guid id,\n            Guid subscriptionId)\n        : base(id)\n        {\n            SubscriptionId = subscriptionId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscription/ExpireSubscriptionCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscription\r\n{\r\n    internal class ExpireSubscriptionCommandHandler : ICommandHandler<ExpireSubscriptionCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public ExpireSubscriptionCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(ExpireSubscriptionCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var subscription = await _aggregateStore.Load(new SubscriptionId(command.SubscriptionId));\r\n\r\n            subscription.Expire();\r\n\r\n            _aggregateStore.AppendChanges(subscription);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptionPayment/ExpireSubscriptionPaymentCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayment\n{\n    public class ExpireSubscriptionPaymentCommand : CommandBase\n    {\n        public ExpireSubscriptionPaymentCommand(Guid paymentId)\n        {\n            PaymentId = paymentId;\n        }\n\n        public Guid PaymentId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptionPayment/ExpireSubscriptionPaymentCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayment\r\n{\r\n    internal class ExpireSubscriptionPaymentCommandHandler : ICommandHandler<ExpireSubscriptionPaymentCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public ExpireSubscriptionPaymentCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(ExpireSubscriptionPaymentCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var subscriptionPayment = await _aggregateStore.Load(new SubscriptionPaymentId(command.PaymentId));\r\n\r\n            subscriptionPayment.Expire();\r\n\r\n            _aggregateStore.AppendChanges(subscriptionPayment);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptionPayments/ExpireSubscriptionPaymentsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayments\n{\n    public class ExpireSubscriptionPaymentsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptionPayments/ExpireSubscriptionPaymentsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayment;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\r\nusing Dapper;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayments\r\n{\r\n    internal class ExpireSubscriptionPaymentsCommandHandler : ICommandHandler<ExpireSubscriptionPaymentsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly ICommandsScheduler _commandsScheduler;\r\n\r\n        public ExpireSubscriptionPaymentsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            ICommandsScheduler commandsScheduler)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _commandsScheduler = commandsScheduler;\r\n        }\r\n\r\n        public async Task Handle(ExpireSubscriptionPaymentsCommand request, CancellationToken cancellationToken)\r\n        {\r\n            const string sql = \"\"\"\r\n                                SELECT \r\n                                    [SubscriptionPayment].PaymentId \r\n                                FROM [payments].[SubscriptionPayments] AS [SubscriptionPayment] \r\n                                WHERE \r\n                                    [SubscriptionPayment].Date > @Date \r\n                                    AND [SubscriptionPayment].[Status] = @Status\r\n                                \"\"\";\r\n\r\n            var connection = _sqlConnectionFactory.GetOpenConnection();\r\n\r\n            var timeForPayment = TimeSpan.FromMinutes(20);\r\n            var date = SystemClock.Now.Add(timeForPayment);\r\n\r\n            var expiredSubscriptionPaymentsIds =\r\n                await connection.QueryAsync<Guid>(sql, new\r\n                {\r\n                    Date = date,\r\n                    Status = SubscriptionPaymentStatus.WaitingForPayment.Code\r\n                });\r\n\r\n            var expiredSubscriptionsPaymentsIdsList = expiredSubscriptionPaymentsIds.AsList();\r\n\r\n            foreach (var subscriptionPaymentId in expiredSubscriptionsPaymentsIdsList)\r\n            {\r\n                await _commandsScheduler.EnqueueAsync(\r\n                    new ExpireSubscriptionPaymentCommand(subscriptionPaymentId));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptions/ExpireSubscriptionsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptions\n{\n    public class ExpireSubscriptionsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/ExpireSubscriptions/ExpireSubscriptionsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscription;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing Dapper;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptions\r\n{\r\n    internal class ExpireSubscriptionsCommandHandler : ICommandHandler<ExpireSubscriptionsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly ICommandsScheduler _commandsScheduler;\r\n\r\n        public ExpireSubscriptionsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            ICommandsScheduler commandsScheduler)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _commandsScheduler = commandsScheduler;\r\n        }\r\n\r\n        public async Task Handle(ExpireSubscriptionsCommand request, CancellationToken cancellationToken)\r\n        {\r\n            const string sql = \"\"\"\r\n                               SELECT \r\n                                   [SubscriptionDetails].Id \r\n                               FROM [payments].[SubscriptionDetails] AS [SubscriptionDetails] \r\n                               WHERE [SubscriptionDetails].ExpirationDate < @Date\r\n                               \"\"\";\r\n\r\n            var connection = _sqlConnectionFactory.GetOpenConnection();\r\n\r\n            var expiredSubscriptionsIds =\r\n                await connection.QueryAsync<Guid>(sql, new\r\n                {\r\n                    Date = SystemClock.Now\r\n                });\r\n\r\n            var expiredSubscriptionsIdsList = expiredSubscriptionsIds.AsList();\r\n\r\n            foreach (var subscriptionId in expiredSubscriptionsIdsList)\r\n            {\r\n                await _commandsScheduler.EnqueueAsync(\r\n                    new ExpireSubscriptionCommand(\r\n                        Guid.NewGuid(),\r\n                        subscriptionId));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetPayerSubscription/GetAuthenticatedPayerSubscriptionQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetPayerSubscription\n{\n    public class GetAuthenticatedPayerSubscriptionQuery : QueryBase<SubscriptionDetailsDto>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetPayerSubscription/GetAuthenticatedPayerSubscriptionQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetPayerSubscription\n{\n    internal class GetAuthenticatedPayerSubscriptionQueryHandler : IQueryHandler<GetAuthenticatedPayerSubscriptionQuery, SubscriptionDetailsDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public GetAuthenticatedPayerSubscriptionQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _executionContextAccessor = executionContextAccessor;\n        }\n\n        public async Task<SubscriptionDetailsDto> Handle(GetAuthenticatedPayerSubscriptionQuery query, CancellationToken cancellationToken)\n        {\n            const string sql = $\"\"\"\n                                SELECT\n                                   [SubscriptionDetails].[Id] AS [{nameof(SubscriptionDetailsDto.SubscriptionId)}],\n                                   [SubscriptionDetails].[Period] AS [{nameof(SubscriptionDetailsDto.Period)}],\n                                   [SubscriptionDetails].[Status] AS [{nameof(SubscriptionDetailsDto.Status)}],\n                                   [SubscriptionDetails].[ExpirationDate] AS [{nameof(SubscriptionDetailsDto.ExpirationDate)}]\n                                FROM [payments].[SubscriptionDetails] AS [SubscriptionDetails]\n                                WHERE [SubscriptionDetails].[PayerId] = @PayerId\n                                \"\"\";\n\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            return await connection.QuerySingleOrDefaultAsync<SubscriptionDetailsDto>(\n                sql,\n                new\n                {\n                    PayerId = _executionContextAccessor.UserId\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionDetails/GetSubscriptionDetailsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails\n{\n    public class GetSubscriptionDetailsQuery : QueryBase<SubscriptionDetailsDto>\n    {\n        public GetSubscriptionDetailsQuery(Guid subscriptionId)\n        {\n            SubscriptionId = subscriptionId;\n        }\n\n        public Guid SubscriptionId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionDetails/GetSubscriptionDetailsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails\n{\n    internal class GetSubscriptionDetailsQueryHandler : IQueryHandler<GetSubscriptionDetailsQuery, SubscriptionDetailsDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetSubscriptionDetailsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<SubscriptionDetailsDto> Handle(GetSubscriptionDetailsQuery query, CancellationToken cancellationToken)\n        {\n            const string sql = $\"\"\"\n                               SELECT \n                                   [SubscriptionDetails].[Id] AS [{nameof(SubscriptionDetailsDto.SubscriptionId)}],\n                                   [SubscriptionDetails].[Period] AS [{nameof(SubscriptionDetailsDto.Period)}],\n                                   [SubscriptionDetails].[Status] AS [{nameof(SubscriptionDetailsDto.Status)}], \n                                   [SubscriptionDetails].[ExpirationDate] AS [{nameof(SubscriptionDetailsDto.ExpirationDate)}] \n                               FROM [payments].[SubscriptionDetails] AS [SubscriptionDetails] \n                               WHERE [SubscriptionDetails].[Id] = @SubscriptionId\n                               \"\"\";\n\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            return await connection.QuerySingleAsync<SubscriptionDetailsDto>(\n                sql,\n                new\n                {\n                    query.SubscriptionId\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionDetails/SubscriptionDetailsDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails\n{\n    public class SubscriptionDetailsDto\n    {\n        public Guid SubscriptionId { get; set; }\n\n        public string Period { get; set; }\n\n        public DateTime ExpirationDate { get; set; }\n\n        public string Status { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionDetails/SubscriptionDetailsProjector.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails\n{\n    internal class SubscriptionDetailsProjector : ProjectorBase, IProjector\n    {\n        private readonly IDbConnection _connection;\n\n        public SubscriptionDetailsProjector(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _connection = sqlConnectionFactory.GetOpenConnection();\n        }\n\n        public async Task Project(IDomainEvent @event)\n        {\n            await When((dynamic)@event);\n        }\n\n        private async Task When(SubscriptionRenewedDomainEvent subscriptionRenewed)\n        {\n            var period = SubscriptionPeriod.GetName(subscriptionRenewed.SubscriptionPeriodCode);\n\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionDetails \" +\n                \"SET \" +\n                \"[Status] = @Status, \" +\n                \"[ExpirationDate] = @ExpirationDate, \" +\n                \"[Period] = @Period \" +\n                \"WHERE [Id] = @SubscriptionId\",\n                new\n                {\n                    subscriptionRenewed.SubscriptionId,\n                    subscriptionRenewed.Status,\n                    subscriptionRenewed.ExpirationDate,\n                    period\n                });\n        }\n\n        private async Task When(SubscriptionExpiredDomainEvent subscriptionExpired)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionDetails \" +\n                \"SET \" +\n                \"[Status] = @Status \" +\n                \"WHERE [Id] = @SubscriptionId\",\n                new\n                {\n                    subscriptionExpired.SubscriptionId,\n                    subscriptionExpired.Status\n                });\n        }\n\n        private async Task When(SubscriptionCreatedDomainEvent subscriptionCreated)\n        {\n            var period = SubscriptionPeriod.GetName(subscriptionCreated.SubscriptionPeriodCode);\n\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.SubscriptionDetails \" +\n                \"([Id], [PayerId], [Period], [Status], [CountryCode], [ExpirationDate]) \" +\n                \"VALUES (@SubscriptionId, @PayerId, @Period, @Status, @CountryCode, @ExpirationDate)\",\n                new\n                {\n                    subscriptionCreated.SubscriptionId,\n                    subscriptionCreated.PayerId,\n                    period,\n                    subscriptionCreated.Status,\n                    subscriptionCreated.CountryCode,\n                    subscriptionCreated.ExpirationDate\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionPayments/GetSubscriptionPaymentsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments\n{\n    public class GetSubscriptionPaymentsQuery : QueryBase<List<SubscriptionPaymentDto>>\n    {\n        public GetSubscriptionPaymentsQuery(Guid payerId)\n        {\n            PayerId = payerId;\n        }\n\n        public Guid PayerId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionPayments/GetSubscriptionPaymentsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments\n{\n    internal class\n        GetSubscriptionPaymentsQueryHandler : IQueryHandler<GetSubscriptionPaymentsQuery, List<SubscriptionPaymentDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetSubscriptionPaymentsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<SubscriptionPaymentDto>> Handle(\n            GetSubscriptionPaymentsQuery query,\n            CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [SubscriptionPayment].[PaymentId] AS [{nameof(SubscriptionPaymentDto.PaymentId)}], \n                                    [SubscriptionPayment].[PayerId] AS [{nameof(SubscriptionPaymentDto.PayerId)}], \n                                    [SubscriptionPayment].[Status] AS [{nameof(SubscriptionPaymentDto.Status)}], \n                                    [SubscriptionPayment].[MoneyCurrency] AS [{nameof(SubscriptionPaymentDto.MoneyCurrency)}], \n                                    [SubscriptionPayment].[MoneyValue] AS [{nameof(SubscriptionPaymentDto.MoneyValue)}], \n                                    [SubscriptionPayment].[Date] AS [{nameof(SubscriptionPaymentDto.Date)}], \n                                    [SubscriptionPayment].[SubscriptionId] AS [{nameof(SubscriptionPaymentDto.SubscriptionId)}], \n                                    [SubscriptionPayment].[Type] AS [{nameof(SubscriptionPaymentDto.Type)}], \n                                    [SubscriptionPayment].[Period] AS [{nameof(SubscriptionPaymentDto.Period)}] \n                                FROM [payments].[SubscriptionPayments] AS [SubscriptionPayment] \n                                WHERE [SubscriptionPayment].PayerId = @PayerId\n                                \"\"\";\n\n            var subscriptionPayments = await connection.QueryAsync<SubscriptionPaymentDto>(\n                sql,\n                new\n                {\n                    query.PayerId\n                });\n\n            return subscriptionPayments.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionPayments/SubscriptionPaymentDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments\n{\n    public class SubscriptionPaymentDto\n    {\n        public Guid PaymentId { get; set; }\n\n        public Guid PayerId { get; set; }\n\n        public string Type { get; set; }\n\n        public string Status { get; set; }\n\n        public string Period { get; set; }\n\n        public DateTime Date { get; set; }\n\n        public Guid? SubscriptionId { get; set; }\n\n        public decimal MoneyValue { get; set; }\n\n        public string MoneyCurrency { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/GetSubscriptionPayments/SubscriptionPaymentsProjector.cs",
    "content": "﻿using System.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments\n{\n    internal class SubscriptionPaymentsProjector : ProjectorBase, IProjector\n    {\n        private readonly IDbConnection _connection;\n\n        public SubscriptionPaymentsProjector(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _connection = sqlConnectionFactory.GetOpenConnection();\n        }\n\n        public async Task Project(IDomainEvent @event)\n        {\n            await When((dynamic)@event);\n        }\n\n        private async Task When(SubscriptionPaymentCreatedDomainEvent subscriptionPaymentCreated)\n        {\n            string period = SubscriptionPeriod.GetName(subscriptionPaymentCreated.SubscriptionPeriodCode);\n\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.SubscriptionPayments \" +\n                    \"([PaymentId], [PayerId], [Type], [Status], [Period], [Date], \" +\n                \"[SubscriptionId], [MoneyValue], [MoneyCurrency]) \" +\n                \"VALUES (@SubscriptionPaymentId, @PayerId, @Type, @Status, @Period, \" +\n                \"@OccurredOn, NULL, @Value, @Currency)\",\n                new\n                {\n                    subscriptionPaymentCreated.SubscriptionPaymentId,\n                    subscriptionPaymentCreated.PayerId,\n                    Type = \"Initial Payment\",\n                    subscriptionPaymentCreated.Status,\n                    period,\n                    subscriptionPaymentCreated.OccurredOn,\n                    subscriptionPaymentCreated.Value,\n                    subscriptionPaymentCreated.Currency\n                });\n        }\n\n        private async Task When(SubscriptionPaymentPaidDomainEvent subscriptionPaymentPaid)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionPayments SET Status = @Status \" +\n                \"WHERE PaymentId = @SubscriptionPaymentId \",\n                new\n                {\n                    subscriptionPaymentPaid.SubscriptionPaymentId,\n                    subscriptionPaymentPaid.Status\n                });\n        }\n\n        private async Task When(SubscriptionRenewalPaymentCreatedDomainEvent subscriptionRenewalPaymentCreated)\n        {\n            string period = SubscriptionPeriod.GetName(subscriptionRenewalPaymentCreated.SubscriptionPeriodCode);\n\n            await _connection.ExecuteScalarAsync(\n                \"INSERT INTO payments.SubscriptionPayments \" +\n                \"([PaymentId], [PayerId], [Type], [Status], [Period], [Date], \" +\n                \"[SubscriptionId], [MoneyValue], [MoneyCurrency]) \" +\n                \"VALUES (@SubscriptionRenewalPaymentId, @PayerId, @Type, @Status, @Period, \" +\n                \"@OccurredOn, @SubscriptionId, @Value, @Currency)\",\n                new\n                {\n                    subscriptionRenewalPaymentCreated.SubscriptionRenewalPaymentId,\n                    subscriptionRenewalPaymentCreated.PayerId,\n                    Type = \"Renewal Payment\",\n                    subscriptionRenewalPaymentCreated.Status,\n                    period,\n                    subscriptionRenewalPaymentCreated.OccurredOn,\n                    subscriptionRenewalPaymentCreated.SubscriptionId,\n                    subscriptionRenewalPaymentCreated.Value,\n                    subscriptionRenewalPaymentCreated.Currency\n                });\n        }\n\n        private async Task When(SubscriptionRenewalPaymentPaidDomainEvent subscriptionRenewalPaymentPaid)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionPayments SET Status = @Status \" +\n                \"WHERE PaymentId = @SubscriptionRenewalPaymentId\",\n                new\n                {\n                    subscriptionRenewalPaymentPaid.SubscriptionRenewalPaymentId,\n                    subscriptionRenewalPaymentPaid.Status\n                });\n        }\n\n        private async Task When(SubscriptionCreatedDomainEvent subscriptionCreated)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionPayments SET SubscriptionId = @SubscriptionId \" +\n                \"WHERE PaymentId = @SubscriptionPaymentId \",\n                new\n                {\n                    subscriptionCreated.SubscriptionId,\n                    subscriptionCreated.SubscriptionPaymentId\n                });\n        }\n\n        private async Task When(SubscriptionPaymentExpiredDomainEvent subscriptionPaymentExpired)\n        {\n            await _connection.ExecuteScalarAsync(\n                \"UPDATE payments.SubscriptionPayments SET Status = @Status \" +\n                \"WHERE PaymentId = @SubscriptionPaymentId \",\n                new\n                {\n                    subscriptionPaymentExpired.SubscriptionPaymentId,\n                    subscriptionPaymentExpired.Status\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionPaymentAsPaid/MarkSubscriptionPaymentAsPaidCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid\n{\n    public class MarkSubscriptionPaymentAsPaidCommand : CommandBase\n    {\n        public MarkSubscriptionPaymentAsPaidCommand(Guid subscriptionPaymentId)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n        }\n\n        public Guid SubscriptionPaymentId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionPaymentAsPaid/MarkSubscriptionPaymentAsPaidCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid\r\n{\r\n    internal class MarkSubscriptionPaymentAsPaidCommandHandler : ICommandHandler<MarkSubscriptionPaymentAsPaidCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        internal MarkSubscriptionPaymentAsPaidCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(MarkSubscriptionPaymentAsPaidCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var subscriptionPayment =\r\n                await _aggregateStore.Load(new SubscriptionPaymentId(command.SubscriptionPaymentId));\r\n\r\n            subscriptionPayment.MarkAsPaid();\r\n\r\n            _aggregateStore.AppendChanges(subscriptionPayment);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionPaymentAsPaid/SubscriptionPaymentPaidNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid\n{\n    public class SubscriptionPaymentPaidNotification : DomainNotificationBase<SubscriptionPaymentPaidDomainEvent>\n    {\n        public SubscriptionPaymentPaidNotification(SubscriptionPaymentPaidDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionPaymentAsPaid/SubscriptionPaymentPaidNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid\n{\n    public class SubscriptionPaymentPaidNotificationHandler : INotificationHandler<SubscriptionPaymentPaidNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public SubscriptionPaymentPaidNotificationHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(SubscriptionPaymentPaidNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new CreateSubscriptionCommand(\n                    Guid.NewGuid(),\n                    notification.DomainEvent.SubscriptionPaymentId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionRenewalPaymentAsPaid/MarkSubscriptionRenewalPaymentAsPaidCommand.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid\n{\n    public class MarkSubscriptionRenewalPaymentAsPaidCommand : CommandBase\n    {\n        public Guid SubscriptionRenewalPaymentId { get; }\n\n        public MarkSubscriptionRenewalPaymentAsPaidCommand(Guid subscriptionRenewalPaymentId)\n        {\n            SubscriptionRenewalPaymentId = subscriptionRenewalPaymentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionRenewalPaymentAsPaid/MarkSubscriptionRenewalPaymentAsPaidCommandHandler.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid\r\n{\r\n    internal class MarkSubscriptionRenewalPaymentAsPaidCommandHandler\r\n        : ICommandHandler<MarkSubscriptionRenewalPaymentAsPaidCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        internal MarkSubscriptionRenewalPaymentAsPaidCommandHandler(IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(MarkSubscriptionRenewalPaymentAsPaidCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var subscriptionRenewalPayment =\r\n                await _aggregateStore.Load(\r\n                    new SubscriptionRenewalPaymentId(command.SubscriptionRenewalPaymentId));\r\n\r\n            subscriptionRenewalPayment.MarkRenewalAsPaid();\r\n\r\n            _aggregateStore.AppendChanges(subscriptionRenewalPayment);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionRenewalPaymentAsPaid/SubscriptionRenewalPaymentAsPaidNotificationHandler.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid\n{\n    public class SubscriptionRenewalPaymentAsPaidNotificationHandler\n        : INotificationHandler<SubscriptionRenewalPaymentPaidNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public SubscriptionRenewalPaymentAsPaidNotificationHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(SubscriptionRenewalPaymentPaidNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(\n                new RenewSubscriptionCommand(\n                    Guid.NewGuid(),\n                    notification.DomainEvent.SubscriptionId,\n                    notification.DomainEvent.SubscriptionRenewalPaymentId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/MarkSubscriptionRenewalPaymentAsPaid/SubscriptionRenewalPaymentPaidNotification.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid\n{\n    public class SubscriptionRenewalPaymentPaidNotification\n        : DomainNotificationBase<SubscriptionRenewalPaymentPaidDomainEvent>\n    {\n        public SubscriptionRenewalPaymentPaidNotification(SubscriptionRenewalPaymentPaidDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/RenewSubscription/RenewSubscriptionCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription\n{\n    public class RenewSubscriptionCommand : InternalCommandBase\n    {\n        public Guid SubscriptionId { get; }\n\n        public Guid SubscriptionRenewalPaymentId { get; }\n\n        [JsonConstructor]\n        public RenewSubscriptionCommand(\n            Guid id, Guid subscriptionId, Guid subscriptionRenewalPaymentId)\n            : base(id)\n        {\n            SubscriptionId = subscriptionId;\n            SubscriptionRenewalPaymentId = subscriptionRenewalPaymentId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/RenewSubscription/RenewSubscriptionCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\r\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription\r\n{\r\n    internal class RenewSubscriptionCommandHandler : ICommandHandler<RenewSubscriptionCommand>\r\n    {\r\n        private readonly IAggregateStore _aggregateStore;\r\n\r\n        public RenewSubscriptionCommandHandler(\r\n            IAggregateStore aggregateStore)\r\n        {\r\n            _aggregateStore = aggregateStore;\r\n        }\r\n\r\n        public async Task Handle(RenewSubscriptionCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var subscriptionRenewalPayment =\r\n                await _aggregateStore.Load(new SubscriptionRenewalPaymentId(command.SubscriptionRenewalPaymentId));\r\n\r\n            var subscription = await _aggregateStore.Load(new SubscriptionId(command.SubscriptionId));\r\n\r\n            subscription.Renew(subscriptionRenewalPayment.GetSnapshot());\r\n\r\n            _aggregateStore.AppendChanges(subscription);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/RenewSubscription/SubscriptionRenewedEnqueueEmailConfirmationHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayerEmail;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionRenewalConfirmationEmail;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription\n{\n    public class SubscriptionRenewedEnqueueEmailConfirmationHandler : INotificationHandler<SubscriptionRenewedNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public SubscriptionRenewedEnqueueEmailConfirmationHandler(\n            ICommandsScheduler commandsScheduler,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _commandsScheduler = commandsScheduler;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(SubscriptionRenewedNotification notification, CancellationToken cancellationToken)\n        {\n            var payerEmail = await PayerEmailProvider.GetPayerEmail(\n                notification.DomainEvent.PayerId,\n                _sqlConnectionFactory);\n\n            await _commandsScheduler.EnqueueAsync(new SendSubscriptionRenewalConfirmationEmailCommand(\n                Guid.NewGuid(),\n                new SubscriptionId(notification.DomainEvent.SubscriptionId),\n                payerEmail));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/RenewSubscription/SubscriptionRenewedNotification.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription\n{\n    public class SubscriptionRenewedNotification : DomainNotificationBase<SubscriptionRenewedDomainEvent>\n    {\n        [JsonConstructor]\n        public SubscriptionRenewedNotification(SubscriptionRenewedDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/RenewSubscription/SubscriptionRenewedNotificationHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription\n{\n    public class SubscriptionRenewedNotificationHandler : INotificationHandler<SubscriptionRenewedNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public SubscriptionRenewedNotificationHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(SubscriptionRenewedNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new SubscriptionExpirationDateChangedIntegrationEvent(\n                notification.Id,\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.PayerId,\n                notification.DomainEvent.ExpirationDate));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/SendSubscriptionCreationConfirmationEmail/SendSubscriptionCreationConfirmationEmailCommand.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionCreationConfirmationEmail\n{\n    public class SendSubscriptionCreationConfirmationEmailCommand : InternalCommandBase\n    {\n        internal SubscriptionId SubscriptionId { get; }\n\n        internal string Email { get; }\n\n        [JsonConstructor]\n        public SendSubscriptionCreationConfirmationEmailCommand(\n            Guid id,\n            SubscriptionId subscriptionId,\n            string email)\n            : base(id)\n        {\n            SubscriptionId = subscriptionId;\n            Email = email;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/SendSubscriptionCreationConfirmationEmail/SendSubscriptionCreationConfirmationEmailCommandHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionCreationConfirmationEmail\r\n{\r\n    internal class SendSubscriptionCreationConfirmationEmailCommandHandler : ICommandHandler<SendSubscriptionCreationConfirmationEmailCommand>\r\n    {\r\n        private readonly IEmailSender _emailSender;\r\n\r\n        public SendSubscriptionCreationConfirmationEmailCommandHandler(IEmailSender emailSender)\r\n        {\r\n            _emailSender = emailSender;\r\n        }\r\n\r\n        public async Task Handle(SendSubscriptionCreationConfirmationEmailCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var emailMessage = new EmailMessage(\r\n                request.Email,\r\n                \"MyMeetings - Subscription purchased\",\r\n                $\"Subscription {request.SubscriptionId.Value} was successfully paid and created with ❤ for you!\");\r\n\r\n            await _emailSender.SendEmail(emailMessage);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/SendSubscriptionRenewalConfirmationEmail/SendSubscriptionRenewalConfirmationEmailCommand.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionRenewalConfirmationEmail\n{\n    public class SendSubscriptionRenewalConfirmationEmailCommand : InternalCommandBase\n    {\n        internal SubscriptionId SubscriptionId { get; }\n\n        internal string Email { get; }\n\n        [JsonConstructor]\n        public SendSubscriptionRenewalConfirmationEmailCommand(\n            Guid id,\n            SubscriptionId subscriptionId,\n            string email)\n            : base(id)\n        {\n            SubscriptionId = subscriptionId;\n            Email = email;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Application/Subscriptions/SendSubscriptionRenewalConfirmationEmail/SendSubscriptionRenewalConfirmationEmailCommandHandler.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.SendSubscriptionRenewalConfirmationEmail\r\n{\r\n    internal class SendSubscriptionRenewalConfirmationEmailCommandHandler : ICommandHandler<SendSubscriptionRenewalConfirmationEmailCommand>\r\n    {\r\n        private readonly IEmailSender _emailSender;\r\n\r\n        public SendSubscriptionRenewalConfirmationEmailCommandHandler(IEmailSender emailSender)\r\n        {\r\n            _emailSender = emailSender;\r\n        }\r\n\r\n        public async Task Handle(SendSubscriptionRenewalConfirmationEmailCommand request, CancellationToken cancellationToken)\r\n        {\r\n            var emailMessage = new EmailMessage(\r\n                request.Email,\r\n                \"MyMeetings - Subscription renewed\",\r\n                $\"Subscription {request.SubscriptionId.Value} was successfully paid and renewed with ❤ for you!\");\r\n\r\n            await _emailSender.SendEmail(emailMessage);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/CompanyName.MyMeetings.Modules.Payments.Domain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/Events/MeetingFeePaymentCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events\n{\n    public class MeetingFeePaymentCreatedDomainEvent : DomainEventBase\n    {\n        public MeetingFeePaymentCreatedDomainEvent(\n            Guid meetingFeePaymentId,\n            Guid meetingFeeId,\n            string status)\n        {\n            MeetingFeeId = meetingFeeId;\n            Status = status;\n            MeetingFeePaymentId = meetingFeePaymentId;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public Guid MeetingFeePaymentId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/Events/MeetingFeePaymentExpiredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events\n{\n    public class MeetingFeePaymentExpiredDomainEvent : DomainEventBase\n    {\n        public MeetingFeePaymentExpiredDomainEvent(Guid meetingFeePaymentId, string status)\n        {\n            MeetingFeePaymentId = meetingFeePaymentId;\n            Status = status;\n        }\n\n        public Guid MeetingFeePaymentId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/Events/MeetingFeePaymentPaidDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events\n{\n    public class MeetingFeePaymentPaidDomainEvent : DomainEventBase\n    {\n        public MeetingFeePaymentPaidDomainEvent(Guid meetingFeePaymentId, string status)\n        {\n            MeetingFeePaymentId = meetingFeePaymentId;\n            Status = status;\n        }\n\n        public Guid MeetingFeePaymentId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/MeetingFeePayment.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments\n{\n    public class MeetingFeePayment : AggregateRoot\n    {\n        private MeetingFeeId _meetingFeeId;\n\n        private MeetingFeePaymentStatus _status;\n\n        public static MeetingFeePayment Create(\n            MeetingFeeId meetingFeeId)\n        {\n            var meetingFeePayment = new MeetingFeePayment();\n\n            var meetingFeePaymentCreated = new MeetingFeePaymentCreatedDomainEvent(\n                Guid.NewGuid(),\n                meetingFeeId.Value,\n                MeetingFeePaymentStatus.WaitingForPayment.Code);\n\n            meetingFeePayment.Apply(meetingFeePaymentCreated);\n            meetingFeePayment.AddDomainEvent(meetingFeePaymentCreated);\n\n            return meetingFeePayment;\n        }\n\n        public void Expire()\n        {\n            MeetingFeePaymentPaidDomainEvent @event =\n                new MeetingFeePaymentPaidDomainEvent(\n                    this.Id,\n                    MeetingFeePaymentStatus.Expired.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        public void MarkAsPaid()\n        {\n            MeetingFeePaymentPaidDomainEvent @event =\n                new MeetingFeePaymentPaidDomainEvent(\n                    this.Id,\n                    MeetingFeePaymentStatus.Paid.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        public MeetingFeePaymentSnapshot GetSnapshot()\n        {\n            return new MeetingFeePaymentSnapshot(this.Id, _meetingFeeId.Value);\n        }\n\n        protected override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private void When(MeetingFeePaymentCreatedDomainEvent @event)\n        {\n            this.Id = @event.MeetingFeePaymentId;\n            _meetingFeeId = new MeetingFeeId(@event.MeetingFeeId);\n            _status = MeetingFeePaymentStatus.Of(@event.Status);\n        }\n\n        private void When(MeetingFeePaymentExpiredDomainEvent @event)\n        {\n            _status = MeetingFeePaymentStatus.Of(@event.Status);\n        }\n\n        private void When(MeetingFeePaymentPaidDomainEvent @event)\n        {\n            _status = MeetingFeePaymentStatus.Of(@event.Status);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/MeetingFeePaymentId.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments\n{\n    public class MeetingFeePaymentId : AggregateId<MeetingFeePayment>\n    {\n        public MeetingFeePaymentId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/MeetingFeePaymentSnapshot.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments\n{\n    public class MeetingFeePaymentSnapshot\n    {\n        public MeetingFeePaymentSnapshot(Guid meetingFeePaymentId, Guid meetingFeeId)\n        {\n            MeetingFeePaymentId = meetingFeePaymentId;\n            MeetingFeeId = meetingFeeId;\n        }\n\n        public Guid MeetingFeePaymentId { get; }\n\n        public Guid MeetingFeeId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFeePayments/MeetingFeePaymentStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments\n{\n    public class MeetingFeePaymentStatus : ValueObject\n    {\n        public static MeetingFeePaymentStatus WaitingForPayment => new MeetingFeePaymentStatus(nameof(WaitingForPayment));\n\n        public static MeetingFeePaymentStatus Paid => new MeetingFeePaymentStatus(nameof(Paid));\n\n        public static MeetingFeePaymentStatus Expired => new MeetingFeePaymentStatus(nameof(Expired));\n\n        public string Code { get; }\n\n        private MeetingFeePaymentStatus(string code)\n        {\n            Code = code;\n        }\n\n        public static MeetingFeePaymentStatus Of(string code)\n        {\n            return new MeetingFeePaymentStatus(code);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/Events/MeetingFeeCanceledDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events\n{\n    public class MeetingFeeCanceledDomainEvent : DomainEventBase\n    {\n        public MeetingFeeCanceledDomainEvent(Guid meetingFeeId, string status)\n        {\n            MeetingFeeId = meetingFeeId;\n            Status = status;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/Events/MeetingFeeCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events\n{\n    public class MeetingFeeCreatedDomainEvent : DomainEventBase\n    {\n        public MeetingFeeCreatedDomainEvent(\n            Guid meetingFeeId,\n            Guid payerId,\n            Guid meetingId,\n            decimal feeValue,\n            string feeCurrency,\n            string status)\n        {\n            PayerId = payerId;\n            MeetingId = meetingId;\n            FeeValue = feeValue;\n            FeeCurrency = feeCurrency;\n            Status = status;\n            MeetingFeeId = meetingFeeId;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public Guid PayerId { get; }\n\n        public Guid MeetingId { get; }\n\n        public decimal FeeValue { get; }\n\n        public string FeeCurrency { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/Events/MeetingFeeExpiredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events\n{\n    public class MeetingFeeExpiredDomainEvent : DomainEventBase\n    {\n        public MeetingFeeExpiredDomainEvent(Guid meetingFeeId, string status)\n        {\n            MeetingFeeId = meetingFeeId;\n            Status = status;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/Events/MeetingFeePaidDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events\n{\n    public class MeetingFeePaidDomainEvent : DomainEventBase\n    {\n        public MeetingFeePaidDomainEvent(Guid meetingFeeId, string status)\n        {\n            MeetingFeeId = meetingFeeId;\n            Status = status;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/MeetingFee.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees\n{\n    public class MeetingFee : AggregateRoot\n    {\n        private PayerId _payerId;\n\n        private MeetingId _meetingId;\n\n        private MoneyValue _fee;\n\n        private MeetingFeeStatus _status;\n\n        protected override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private MeetingFee()\n        {\n        }\n\n        public static MeetingFee Create(\n            PayerId payerId,\n            MeetingId meetingId,\n            MoneyValue fee)\n        {\n            var meetingFee = new MeetingFee();\n\n            var meetingFeeCreated = new MeetingFeeCreatedDomainEvent(\n                Guid.NewGuid(),\n                payerId.Value,\n                meetingId.Value,\n                fee.Value,\n                fee.Currency,\n                MeetingFeeStatus.WaitingForPayment.Code);\n\n            meetingFee.Apply(meetingFeeCreated);\n            meetingFee.AddDomainEvent(meetingFeeCreated);\n\n            return meetingFee;\n        }\n\n        public void MarkAsPaid()\n        {\n            var @event =\n                new MeetingFeePaidDomainEvent(\n                    this.Id,\n                    MeetingFeeStatus.Paid.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        public MeetingFeeSnapshot GetSnapshot()\n        {\n            return new MeetingFeeSnapshot(this.Id, _payerId.Value, _meetingId.Value);\n        }\n\n        private void When(MeetingFeeCreatedDomainEvent meetingFeeCreated)\n        {\n            this.Id = meetingFeeCreated.MeetingFeeId;\n            _payerId = new PayerId(meetingFeeCreated.PayerId);\n            _meetingId = new MeetingId(meetingFeeCreated.MeetingId);\n            _fee = MoneyValue.Of(meetingFeeCreated.FeeValue, meetingFeeCreated.FeeCurrency);\n            _status = MeetingFeeStatus.Of(meetingFeeCreated.Status);\n        }\n\n        private void When(MeetingFeeCanceledDomainEvent meetingFeeCanceled)\n        {\n            _status = MeetingFeeStatus.Of(meetingFeeCanceled.Status);\n        }\n\n        private void When(MeetingFeeExpiredDomainEvent meetingFeeExpired)\n        {\n            _status = MeetingFeeStatus.Of(meetingFeeExpired.Status);\n        }\n\n        private void When(MeetingFeePaidDomainEvent meetingFeePaid)\n        {\n            _status = MeetingFeeStatus.Of(meetingFeePaid.Status);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/MeetingFeeId.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees\n{\n    public class MeetingFeeId : AggregateId<MeetingFee>\n    {\n        public MeetingFeeId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/MeetingFeeSnapshot.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees\n{\n    public class MeetingFeeSnapshot\n    {\n        public MeetingFeeSnapshot(Guid meetingFeeId, Guid payerId, Guid meetingId)\n        {\n            MeetingFeeId = meetingFeeId;\n            PayerId = payerId;\n            MeetingId = meetingId;\n        }\n\n        public Guid MeetingFeeId { get; }\n\n        public Guid PayerId { get; }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/MeetingFeeStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees\n{\n    public class MeetingFeeStatus : ValueObject\n    {\n        public static MeetingFeeStatus WaitingForPayment => new MeetingFeeStatus(nameof(WaitingForPayment));\n\n        public static MeetingFeeStatus Paid => new MeetingFeeStatus(nameof(Paid));\n\n        public static MeetingFeeStatus Expired => new MeetingFeeStatus(nameof(Expired));\n\n        public static MeetingFeeStatus Canceled => new MeetingFeeStatus(nameof(Canceled));\n\n        public string Code { get; }\n\n        private MeetingFeeStatus(string code)\n        {\n            Code = code;\n        }\n\n        public static MeetingFeeStatus Of(string code)\n        {\n            return new MeetingFeeStatus(code);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/MeetingFees/MeetingId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees\n{\n    public class MeetingId : TypedIdValueBase\n    {\n        public MeetingId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Payers/Events/PayerCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Payers.Events\n{\n    public class PayerCreatedDomainEvent : DomainEventBase\n    {\n        public Guid PayerId { get; }\n\n        public string Login { get; }\n\n        public string FirstName { get; }\n\n        public string LastName { get; }\n\n        public string Name { get; }\n\n        public string Email { get; }\n\n        public PayerCreatedDomainEvent(\n            Guid payerId,\n            string login,\n            string firstName,\n            string lastName,\n            string name,\n            string email)\n        {\n            PayerId = payerId;\n            Login = login;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n            Email = email;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Payers/IPayerContext.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.Payers\n{\n    public interface IPayerContext\n    {\n        PayerId PayerId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Payers/IPayerRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.Payers\n{\n    public interface IPayerRepository\n    {\n        Task AddAsync(Payer payer);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Payers/Payer.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Payers\n{\n    public class Payer : AggregateRoot, IAggregateRoot\n    {\n        protected override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private string _login;\n\n        private string _email;\n\n        private string _firstName;\n\n        private string _lastName;\n\n        private string _name;\n\n        private DateTime _createDate;\n\n        public static Payer Create(\n            Guid id,\n            string login,\n            string email,\n            string firstName,\n            string lastName,\n            string name)\n        {\n            var payer = new Payer();\n\n            var payerCreated = new PayerCreatedDomainEvent(\n                id,\n                login,\n                firstName,\n                lastName,\n                name,\n                email);\n\n            payer.Apply(payerCreated);\n            payer.AddDomainEvent(payerCreated);\n\n            return payer;\n        }\n\n        private Payer()\n        {\n        }\n\n        private void When(PayerCreatedDomainEvent @event)\n        {\n            this.Id = @event.PayerId;\n            _login = @event.Login;\n            _createDate = @event.OccurredOn;\n            _email = @event.Email;\n            _firstName = @event.FirstName;\n            _lastName = @event.LastName;\n            _name = @event.Name;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Payers/PayerId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Payers\n{\n    public class PayerId : TypedIdValueBase\n    {\n        public PayerId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/Events/PriceListItemActivatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events\n{\n    public class PriceListItemActivatedDomainEvent : DomainEventBase\n    {\n        public PriceListItemActivatedDomainEvent(Guid priceListItemId)\n        {\n            PriceListItemId = priceListItemId;\n        }\n\n        public Guid PriceListItemId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/Events/PriceListItemAttributesChangedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events\n{\n    public class PriceListItemAttributesChangedDomainEvent : DomainEventBase\n    {\n        public PriceListItemAttributesChangedDomainEvent(Guid priceListItemId, string countryCode, string subscriptionPeriodCode, string categoryCode, decimal price, string currency)\n        {\n            PriceListItemId = priceListItemId;\n            CountryCode = countryCode;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CategoryCode = categoryCode;\n            Price = price;\n            Currency = currency;\n        }\n\n        public Guid PriceListItemId { get; }\n\n        public string CountryCode { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CategoryCode { get; }\n\n        public decimal Price { get; }\n\n        public string Currency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/Events/PriceListItemCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events\n{\n    public class PriceListItemCreatedDomainEvent : DomainEventBase\n    {\n        public PriceListItemCreatedDomainEvent(\n        Guid priceListItemId,\n        string countryCode,\n        string subscriptionPeriodCode,\n        string categoryCode,\n        decimal price,\n        string currency,\n        bool isActive)\n        {\n            PriceListItemId = priceListItemId;\n            CountryCode = countryCode;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CategoryCode = categoryCode;\n            Price = price;\n            Currency = currency;\n            IsActive = isActive;\n        }\n\n        public Guid PriceListItemId { get; }\n\n        public string CountryCode { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CategoryCode { get; }\n\n        public decimal Price { get; }\n\n        public string Currency { get; }\n\n        public bool IsActive { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/Events/PriceListItemDeactivatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events\n{\n    public class PriceListItemDeactivatedDomainEvent : DomainEventBase\n    {\n        public PriceListItemDeactivatedDomainEvent(Guid priceListItemId)\n        {\n            PriceListItemId = priceListItemId;\n        }\n\n        public Guid PriceListItemId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PriceList.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Rules;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems\n{\n    public class PriceList : ValueObject\n    {\n        private readonly List<PriceListItemData> _items;\n\n        private readonly IPricingStrategy _pricingStrategy;\n\n        private PriceList(\n            List<PriceListItemData> items,\n            IPricingStrategy pricingStrategy)\n        {\n            _items = items;\n            _pricingStrategy = pricingStrategy;\n        }\n\n        public static PriceList Create(\n            List<PriceListItemData> items,\n            IPricingStrategy pricingStrategy)\n        {\n            return new PriceList(items, pricingStrategy);\n        }\n\n        public MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category)\n        {\n            CheckRule(new PriceForSubscriptionMustBeDefinedRule(countryCode, subscriptionPeriod, _items, category));\n\n            return _pricingStrategy.GetPrice(countryCode, subscriptionPeriod, category);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PriceListItem.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems\n{\n    public class PriceListItem : AggregateRoot\n    {\n        private string _countryCode;\n\n        private SubscriptionPeriod _subscriptionPeriod;\n\n        private PriceListItemCategory _category;\n\n        private MoneyValue _price;\n\n        private bool _isActive;\n\n        private PriceListItem()\n        {\n        }\n\n        public static PriceListItem Create(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category,\n            MoneyValue price)\n        {\n            var priceListItem = new PriceListItem();\n\n            var priceListItemCreatedEvent = new PriceListItemCreatedDomainEvent(\n                Guid.NewGuid(),\n                countryCode,\n                subscriptionPeriod.Code,\n                category.Code,\n                price.Value,\n                price.Currency,\n                isActive: true);\n\n            priceListItem.Apply(priceListItemCreatedEvent);\n            priceListItem.AddDomainEvent(priceListItemCreatedEvent);\n\n            return priceListItem;\n        }\n\n        public void Activate()\n        {\n            if (!_isActive)\n            {\n                var priceListItemActivatedEvent = new PriceListItemActivatedDomainEvent(this.Id);\n\n                this.Apply(priceListItemActivatedEvent);\n                this.AddDomainEvent(priceListItemActivatedEvent);\n            }\n        }\n\n        public void Deactivate()\n        {\n            if (_isActive)\n            {\n                var priceListItemDeactivatedEvent = new PriceListItemDeactivatedDomainEvent(this.Id);\n\n                this.Apply(priceListItemDeactivatedEvent);\n                this.AddDomainEvent(priceListItemDeactivatedEvent);\n            }\n        }\n\n        public void ChangeAttributes(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category,\n            MoneyValue price)\n        {\n            var priceListItemChangedDomainEvent = new PriceListItemAttributesChangedDomainEvent(this.Id, countryCode, subscriptionPeriod.Code, category.Code, price.Value, price.Currency);\n\n            this.Apply(priceListItemChangedDomainEvent);\n            this.AddDomainEvent(priceListItemChangedDomainEvent);\n        }\n\n        protected override void Apply(IDomainEvent @event) => When((dynamic)@event);\n\n        private void When(PriceListItemActivatedDomainEvent @event)\n        {\n            this._isActive = true;\n        }\n\n        private void When(PriceListItemCreatedDomainEvent @event)\n        {\n            this.Id = @event.PriceListItemId;\n            _countryCode = @event.CountryCode;\n            _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            _category = PriceListItemCategory.Of(@event.CategoryCode);\n            _price = MoneyValue.Of(@event.Price, @event.Currency);\n            _isActive = true;\n        }\n\n        private void When(PriceListItemDeactivatedDomainEvent @event)\n        {\n            this._isActive = false;\n        }\n\n        private void When(PriceListItemAttributesChangedDomainEvent @event)\n        {\n            this._countryCode = @event.CountryCode;\n            this._subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            this._category = PriceListItemCategory.Of(@event.CategoryCode);\n            this._price = MoneyValue.Of(@event.Price, @event.Currency);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PriceListItemCategory.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems\n{\n    public class PriceListItemCategory : ValueObject\n    {\n        public static PriceListItemCategory New => new PriceListItemCategory(nameof(New));\n\n        public static PriceListItemCategory Renewal => new PriceListItemCategory(nameof(Renewal));\n\n        public string Code { get; }\n\n        private PriceListItemCategory(string code)\n        {\n            Code = code;\n        }\n\n        public static PriceListItemCategory Of(string code) => new PriceListItemCategory(code);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PriceListItemData.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems\n{\n    public class PriceListItemData\n    {\n        public PriceListItemData(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            MoneyValue value,\n            PriceListItemCategory category)\n        {\n            CountryCode = countryCode;\n            Value = value;\n            Category = category;\n            SubscriptionPeriod = subscriptionPeriod;\n        }\n\n        public string CountryCode { get; }\n\n        public SubscriptionPeriod SubscriptionPeriod { get; }\n\n        public MoneyValue Value { get; }\n\n        public PriceListItemCategory Category { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PriceListItemId.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems\n{\n    public class PriceListItemId : AggregateId<PriceListItem>\n    {\n        public PriceListItemId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PricingStrategies/DirectValueFromPriceListPricingStrategy.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies\n{\n    public class DirectValueFromPriceListPricingStrategy : IPricingStrategy\n    {\n        private readonly List<PriceListItemData> _items;\n\n        public DirectValueFromPriceListPricingStrategy(List<PriceListItemData> items)\n        {\n            _items = items;\n        }\n\n        public MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category)\n        {\n            var priceListItem = _items.Single(x =>\n                x.CountryCode == countryCode && x.SubscriptionPeriod == subscriptionPeriod &&\n                x.Category == category);\n\n            return priceListItem.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PricingStrategies/DirectValuePricingStrategy.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies\n{\n    public class DirectValuePricingStrategy : IPricingStrategy\n    {\n        private readonly MoneyValue _directValue;\n\n        public DirectValuePricingStrategy(MoneyValue directValue)\n        {\n            _directValue = directValue;\n        }\n\n        public MoneyValue GetPrice(string countryCode, SubscriptionPeriod subscriptionPeriod, PriceListItemCategory category)\n        {\n            return _directValue;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PricingStrategies/DiscountedValueFromPriceListPricingStrategy.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies\n{\n    public class DiscountedValueFromPriceListPricingStrategy : IPricingStrategy\n    {\n        private readonly List<PriceListItemData> _items;\n\n        private readonly MoneyValue _discountValue;\n\n        public DiscountedValueFromPriceListPricingStrategy(\n            List<PriceListItemData> items,\n            MoneyValue discountValue)\n        {\n            _items = items;\n            _discountValue = discountValue;\n        }\n\n        public MoneyValue GetPrice(string countryCode, SubscriptionPeriod subscriptionPeriod, PriceListItemCategory category)\n        {\n            var priceListItem = _items.Single(x =>\n                x.CountryCode == countryCode && x.SubscriptionPeriod == subscriptionPeriod &&\n                x.Category == category);\n\n            return priceListItem.Value - _discountValue;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/PriceListItems/PricingStrategies/IPricingStrategy.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies\n{\n    public interface IPricingStrategy\n    {\n        MoneyValue GetPrice(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            PriceListItemCategory category);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/AggregateId.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork\n{\n    public abstract class AggregateId<T>\n        where T : AggregateRoot\n    {\n        protected AggregateId(Guid value)\n        {\n            Value = value;\n        }\n\n        public Guid Value { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/AggregateRoot.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork\n{\n    public abstract class AggregateRoot\n    {\n        private readonly List<IDomainEvent> _domainEvents;\n\n        public Guid Id { get; protected set; }\n\n        public int Version { get; private set; }\n\n        public IReadOnlyCollection<IDomainEvent> GetDomainEvents() => _domainEvents.AsReadOnly();\n\n        protected void AddDomainEvent(IDomainEvent @event)\n        {\n            _domainEvents.Add(@event);\n        }\n\n        protected AggregateRoot()\n        {\n            _domainEvents = [];\n\n            Version = -1;\n        }\n\n        public void Load(IEnumerable<IDomainEvent> history)\n        {\n            foreach (var e in history)\n            {\n                Apply(e);\n                Version++;\n            }\n        }\n\n        protected abstract void Apply(IDomainEvent @event);\n\n        protected static void CheckRule(IBusinessRule rule)\n        {\n            if (rule.IsBroken())\n            {\n                throw new BusinessRuleValidationException(rule);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/IAggregateStore.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork\n{\n    public interface IAggregateStore\n    {\n        Task Save();\n\n        Task<T> Load<T>(AggregateId<T> aggregateId)\n            where T : AggregateRoot;\n\n        List<IDomainEvent> GetChanges();\n\n        void AppendChanges<T>(T aggregate)\n            where T : AggregateRoot;\n\n        void ClearChanges();\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/MoneyValue.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork.Rules;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork\n{\n    public class MoneyValue : ValueObject\n    {\n        public decimal Value { get; }\n\n        public string Currency { get; }\n\n        private MoneyValue(decimal value, string currency)\n        {\n            this.Value = value;\n            this.Currency = currency;\n        }\n\n        public static MoneyValue Of(decimal value, string currency)\n        {\n            CheckRule(new ValueOfMoneyMustNotBeNegativeRule(value));\n\n            return new MoneyValue(value, currency);\n        }\n\n        public static bool operator >(decimal left, MoneyValue right) => left > right.Value;\n\n        public static bool operator <(decimal left, MoneyValue right) => left < right.Value;\n\n        public static bool operator >=(decimal left, MoneyValue right) => left >= right.Value;\n\n        public static bool operator <=(decimal left, MoneyValue right) => left <= right.Value;\n\n        public static bool operator >(MoneyValue left, decimal right) => left.Value > right;\n\n        public static bool operator <(MoneyValue left, decimal right) => left.Value < right;\n\n        public static bool operator >=(MoneyValue left, decimal right) => left.Value >= right;\n\n        public static bool operator <=(MoneyValue left, decimal right) => left.Value <= right;\n\n        public static MoneyValue operator -(MoneyValue left, MoneyValue right)\n        {\n            CheckRule(new MoneyMustHaveTheSameCurrencyRule(left, right));\n\n            return Of(left.Value - right.Value, left.Currency);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/Rules/MoneyMustHaveTheSameCurrencyRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork.Rules\n{\n    public class MoneyMustHaveTheSameCurrencyRule : IBusinessRule\n    {\n        private readonly MoneyValue _left;\n\n        private readonly MoneyValue _right;\n\n        public MoneyMustHaveTheSameCurrencyRule(MoneyValue left, MoneyValue right)\n        {\n            _left = left;\n            _right = right;\n        }\n\n        public bool IsBroken() => _left.Currency != _right.Currency;\n\n        public string Message => \"Currency of money must be the same.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/Rules/ValueOfMoneyMustNotBeNegativeRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork.Rules\n{\n    public class ValueOfMoneyMustNotBeNegativeRule : IBusinessRule\n    {\n        private readonly decimal _value;\n\n        public ValueOfMoneyMustNotBeNegativeRule(decimal value)\n        {\n            _value = value;\n        }\n\n        public bool IsBroken() => _value < 0;\n\n        public string Message => \"Value of money must not be negative.\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SeedWork/SystemClock.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork\n{\n    public static class SystemClock\n    {\n        private static DateTime? _customDate;\n\n        public static DateTime Now\n        {\n            get\n            {\n                if (_customDate.HasValue)\n                {\n                    return _customDate.Value;\n                }\n\n                return DateTime.UtcNow;\n            }\n        }\n\n        public static void Set(DateTime customDate) => _customDate = customDate;\n\n        public static void Reset() => _customDate = null;\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/Events/SubscriptionPaymentCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events\n{\n    public class SubscriptionPaymentCreatedDomainEvent : DomainEventBase\n    {\n        public SubscriptionPaymentCreatedDomainEvent(\n            Guid subscriptionPaymentId,\n            Guid payerId,\n            string subscriptionPeriodCode,\n            string countryCode,\n            string status,\n            decimal value,\n            string currency)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n            PayerId = payerId;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CountryCode = countryCode;\n            Status = status;\n            Value = value;\n            Currency = currency;\n        }\n\n        public Guid SubscriptionPaymentId { get; }\n\n        public Guid PayerId { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CountryCode { get; }\n\n        public string Status { get; }\n\n        public decimal Value { get; }\n\n        public string Currency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/Events/SubscriptionPaymentExpiredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events\n{\n    public class SubscriptionPaymentExpiredDomainEvent : DomainEventBase\n    {\n        public SubscriptionPaymentExpiredDomainEvent(Guid subscriptionPaymentId, string status)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n            Status = status;\n        }\n\n        public Guid SubscriptionPaymentId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/Events/SubscriptionPaymentPaidDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events\n{\n    public class SubscriptionPaymentPaidDomainEvent : DomainEventBase\n    {\n        public SubscriptionPaymentPaidDomainEvent(Guid subscriptionPaymentId, string status)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n            Status = status;\n        }\n\n        public Guid SubscriptionPaymentId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/Rules/PriceForSubscriptionMustBeDefinedRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Rules\n{\n    public class PriceForSubscriptionMustBeDefinedRule : IBusinessRule\n    {\n        private readonly string _countryCode;\n\n        private readonly SubscriptionPeriod _subscriptionPeriod;\n\n        private readonly IList<PriceListItemData> _priceListItems;\n\n        private readonly PriceListItemCategory _category;\n\n        public PriceForSubscriptionMustBeDefinedRule(\n            string countryCode,\n            SubscriptionPeriod subscriptionPeriod,\n            IList<PriceListItemData> priceListItems,\n            PriceListItemCategory category)\n        {\n            _countryCode = countryCode;\n            _subscriptionPeriod = subscriptionPeriod;\n            _priceListItems = priceListItems;\n            _category = category;\n        }\n\n        public bool IsBroken() => _priceListItems.Count(x =>\n                                      x.CountryCode == _countryCode &&\n                                      x.Category == _category &&\n                                      x.SubscriptionPeriod == _subscriptionPeriod) != 1;\n\n        public string Message => \"Price for subscription must be defined\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/Rules/PriceOfferMustMatchPriceInPriceListRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Rules\n{\n    public class PriceOfferMustMatchPriceInPriceListRule : IBusinessRule\n    {\n        private readonly MoneyValue _priceOffer;\n\n        private readonly MoneyValue _priceInPriceList;\n\n        public PriceOfferMustMatchPriceInPriceListRule(\n            MoneyValue priceOffer,\n            MoneyValue priceInPriceList)\n        {\n            _priceOffer = priceOffer;\n            _priceInPriceList = priceInPriceList;\n        }\n\n        public bool IsBroken() => _priceOffer != _priceInPriceList;\n\n        public string Message => \"Price offer must match price in Price List\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/SubscriptionPayment.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Rules;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments\n{\n    public class SubscriptionPayment : AggregateRoot\n    {\n        private PayerId _payerId;\n\n        private SubscriptionPeriod _subscriptionPeriod;\n\n        private string _countryCode;\n\n        private SubscriptionPaymentStatus _subscriptionPaymentStatus;\n\n        private MoneyValue _value;\n\n        public static SubscriptionPayment Buy(\n            PayerId payerId,\n            SubscriptionPeriod period,\n            string countryCode,\n            MoneyValue priceOffer,\n            PriceList priceList)\n        {\n            var priceInPriceList = priceList.GetPrice(countryCode, period, PriceListItemCategory.New);\n            CheckRule(new PriceOfferMustMatchPriceInPriceListRule(priceOffer, priceInPriceList));\n\n            var subscriptionPayment = new SubscriptionPayment();\n\n            var subscriptionPaymentCreated = new SubscriptionPaymentCreatedDomainEvent(\n                Guid.NewGuid(),\n                payerId.Value,\n                period.Code,\n                countryCode,\n                SubscriptionPaymentStatus.WaitingForPayment.Code,\n                priceOffer.Value,\n                priceOffer.Currency);\n\n            subscriptionPayment.Apply(subscriptionPaymentCreated);\n            subscriptionPayment.AddDomainEvent(subscriptionPaymentCreated);\n\n            return subscriptionPayment;\n        }\n\n        public SubscriptionPaymentSnapshot GetSnapshot()\n        {\n            return new SubscriptionPaymentSnapshot(new SubscriptionPaymentId(this.Id), _payerId, _subscriptionPeriod, _countryCode);\n        }\n\n        public void MarkAsPaid()\n        {\n            SubscriptionPaymentPaidDomainEvent @event =\n                new SubscriptionPaymentPaidDomainEvent(\n                    this.Id,\n                    SubscriptionPaymentStatus.Paid.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        public void Expire()\n        {\n            SubscriptionPaymentExpiredDomainEvent @event =\n                new SubscriptionPaymentExpiredDomainEvent(\n                    this.Id,\n                    SubscriptionPaymentStatus.Expired.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        protected override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private void When(SubscriptionPaymentPaidDomainEvent @event)\n        {\n            _subscriptionPaymentStatus = SubscriptionPaymentStatus.Of(@event.Status);\n        }\n\n        private void When(SubscriptionPaymentCreatedDomainEvent @event)\n        {\n            this.Id = @event.SubscriptionPaymentId;\n            _payerId = new PayerId(@event.PayerId);\n            _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            _countryCode = @event.CountryCode;\n            _subscriptionPaymentStatus = SubscriptionPaymentStatus.Of(@event.Status);\n            _value = MoneyValue.Of(@event.Value, @event.Currency);\n        }\n\n        private void When(SubscriptionPaymentExpiredDomainEvent @event)\n        {\n            _subscriptionPaymentStatus = SubscriptionPaymentStatus.Of(@event.Status);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/SubscriptionPaymentId.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments\n{\n    public class SubscriptionPaymentId : AggregateId<SubscriptionPayment>\n    {\n        public SubscriptionPaymentId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/SubscriptionPaymentSnapshot.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments\n{\n    public class SubscriptionPaymentSnapshot\n    {\n        public SubscriptionPaymentSnapshot(\n            SubscriptionPaymentId id,\n            PayerId payerId,\n            SubscriptionPeriod subscriptionPeriod,\n            string countryCode)\n        {\n            PayerId = payerId;\n            SubscriptionPeriod = subscriptionPeriod;\n            CountryCode = countryCode;\n            Id = id;\n        }\n\n        public PayerId PayerId { get; }\n\n        public SubscriptionPeriod SubscriptionPeriod { get; }\n\n        public string CountryCode { get; }\n\n        public SubscriptionPaymentId Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionPayments/SubscriptionPaymentStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments\n{\n    public class SubscriptionPaymentStatus : ValueObject\n    {\n        public static SubscriptionPaymentStatus WaitingForPayment => new SubscriptionPaymentStatus(nameof(WaitingForPayment));\n\n        public static SubscriptionPaymentStatus Paid => new SubscriptionPaymentStatus(nameof(Paid));\n\n        public static SubscriptionPaymentStatus Expired => new SubscriptionPaymentStatus(nameof(Expired));\n\n        public string Code { get; }\n\n        private SubscriptionPaymentStatus(string code)\n        {\n            Code = code;\n        }\n\n        public static SubscriptionPaymentStatus Of(string code)\n        {\n            return new SubscriptionPaymentStatus(code);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/Events/SubscriptionRenewalPaymentCreatedDomainEvent.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events\n{\n    public class SubscriptionRenewalPaymentCreatedDomainEvent : DomainEventBase\n    {\n        public SubscriptionRenewalPaymentCreatedDomainEvent(\n            Guid subscriptionRenewalPaymentId,\n            Guid payerId,\n            Guid subscriptionId,\n            string subscriptionPeriodCode,\n            string countryCode,\n            string status,\n            decimal value,\n            string currency)\n        {\n            SubscriptionRenewalPaymentId = subscriptionRenewalPaymentId;\n            PayerId = payerId;\n            SubscriptionId = subscriptionId;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CountryCode = countryCode;\n            Status = status;\n            Value = value;\n            Currency = currency;\n        }\n\n        public Guid SubscriptionRenewalPaymentId { get; }\n\n        public Guid PayerId { get; }\n\n        public Guid SubscriptionId { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CountryCode { get; }\n\n        public string Status { get; }\n\n        public decimal Value { get; }\n\n        public string Currency { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/Events/SubscriptionRenewalPaymentPaidDomainEvent.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events\n{\n    public class SubscriptionRenewalPaymentPaidDomainEvent : DomainEventBase\n    {\n        public SubscriptionRenewalPaymentPaidDomainEvent(\n            Guid subscriptionRenewalPaymentId, Guid subscriptionId, string status)\n        {\n            SubscriptionRenewalPaymentId = subscriptionRenewalPaymentId;\n            SubscriptionId = subscriptionId;\n            Status = status;\n        }\n\n        public Guid SubscriptionRenewalPaymentId { get; }\n\n        public Guid SubscriptionId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/Rules/PriceOfferMustMatchPriceInPriceListRule.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Rules\n{\n    public class PriceOfferMustMatchPriceInPriceListRule : IBusinessRule\n    {\n        private readonly MoneyValue _priceOffer;\n\n        private readonly MoneyValue _priceInPriceList;\n\n        public PriceOfferMustMatchPriceInPriceListRule(\n            MoneyValue priceOffer,\n            MoneyValue priceInPriceList)\n        {\n            _priceOffer = priceOffer;\n            _priceInPriceList = priceInPriceList;\n        }\n\n        public bool IsBroken() => _priceOffer != _priceInPriceList;\n\n        public string Message => \"Price offer must match price in Price List\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/SubscriptionRenewalPayment.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Rules;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments\n{\n    public class SubscriptionRenewalPayment : AggregateRoot\n    {\n        private PayerId _payerId;\n\n        private SubscriptionId _subscriptionId;\n\n        private SubscriptionPeriod _subscriptionPeriod;\n\n        private string _countryCode;\n\n        private SubscriptionRenewalPaymentStatus _subscriptionRenewalPaymentStatus;\n\n        private MoneyValue _value;\n\n        public static SubscriptionRenewalPayment Buy(\n            PayerId payerId,\n            SubscriptionId subscriptionId,\n            SubscriptionPeriod period,\n            string countryCode,\n            MoneyValue priceOffer,\n            PriceList priceList)\n        {\n            var priceInPriceList = priceList.GetPrice(countryCode, period, PriceListItemCategory.Renewal);\n            CheckRule(new PriceOfferMustMatchPriceInPriceListRule(priceOffer, priceInPriceList));\n\n            var subscriptionRenewalPayment = new SubscriptionRenewalPayment();\n\n            var subscriptionRenewalPaymentCreated = new SubscriptionRenewalPaymentCreatedDomainEvent(\n                Guid.NewGuid(),\n                payerId.Value,\n                subscriptionId.Value,\n                period.Code,\n                countryCode,\n                SubscriptionRenewalPaymentStatus.WaitingForPayment.Code,\n                priceOffer.Value,\n                priceOffer.Currency);\n\n            subscriptionRenewalPayment.Apply(subscriptionRenewalPaymentCreated);\n            subscriptionRenewalPayment.AddDomainEvent(subscriptionRenewalPaymentCreated);\n\n            return subscriptionRenewalPayment;\n        }\n\n        public SubscriptionRenewalPaymentSnapshot GetSnapshot()\n        {\n            return new SubscriptionRenewalPaymentSnapshot(new SubscriptionRenewalPaymentId(this.Id), _payerId, _subscriptionPeriod, _countryCode);\n        }\n\n        public void MarkRenewalAsPaid()\n        {\n            SubscriptionRenewalPaymentPaidDomainEvent @event =\n                new SubscriptionRenewalPaymentPaidDomainEvent(\n                    this.Id,\n                    this._subscriptionId.Value,\n                    SubscriptionRenewalPaymentStatus.Paid.Code);\n\n            this.Apply(@event);\n            this.AddDomainEvent(@event);\n        }\n\n        protected override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private void When(SubscriptionRenewalPaymentCreatedDomainEvent @event)\n        {\n            this.Id = @event.SubscriptionRenewalPaymentId;\n            _payerId = new PayerId(@event.PayerId);\n            _subscriptionId = new SubscriptionId(@event.SubscriptionId);\n            _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            _countryCode = @event.CountryCode;\n            _subscriptionRenewalPaymentStatus = SubscriptionRenewalPaymentStatus.Of(@event.Status);\n            _value = MoneyValue.Of(@event.Value, @event.Currency);\n        }\n\n        private void When(SubscriptionRenewalPaymentPaidDomainEvent @event)\n        {\n            _subscriptionRenewalPaymentStatus = SubscriptionRenewalPaymentStatus.Of(@event.Status);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/SubscriptionRenewalPaymentId.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments\n{\n    public class SubscriptionRenewalPaymentId : AggregateId<SubscriptionRenewalPayment>\n    {\n        public SubscriptionRenewalPaymentId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/SubscriptionRenewalPaymentSnapshot.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments\n{\n    public class SubscriptionRenewalPaymentSnapshot\n    {\n        public SubscriptionRenewalPaymentSnapshot(\n            SubscriptionRenewalPaymentId id,\n            PayerId payerId,\n            SubscriptionPeriod subscriptionPeriod,\n            string countryCode)\n        {\n            PayerId = payerId;\n            SubscriptionPeriod = subscriptionPeriod;\n            CountryCode = countryCode;\n            Id = id;\n        }\n\n        public PayerId PayerId { get; }\n\n        public SubscriptionPeriod SubscriptionPeriod { get; }\n\n        public string CountryCode { get; }\n\n        public SubscriptionRenewalPaymentId Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/SubscriptionRenewalPayments/SubscriptionRenewalPaymentStatus.cs",
    "content": "namespace CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments\n{\n    public class SubscriptionRenewalPaymentStatus\n    {\n        public static SubscriptionRenewalPaymentStatus WaitingForPayment\n            => new SubscriptionRenewalPaymentStatus(nameof(WaitingForPayment));\n\n        public static SubscriptionRenewalPaymentStatus Paid\n            => new SubscriptionRenewalPaymentStatus(nameof(Paid));\n\n        public static SubscriptionRenewalPaymentStatus Expired\n            => new SubscriptionRenewalPaymentStatus(nameof(Expired));\n\n        public string Code { get; }\n\n        private SubscriptionRenewalPaymentStatus(string code)\n        {\n            Code = code;\n        }\n\n        public static SubscriptionRenewalPaymentStatus Of(string code)\n        {\n            return new SubscriptionRenewalPaymentStatus(code);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/Events/SubscriptionCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events\n{\n    public class SubscriptionCreatedDomainEvent : DomainEventBase\n    {\n        public SubscriptionCreatedDomainEvent(\n            Guid subscriptionPaymentId,\n            Guid subscriptionId,\n            Guid payerId,\n            string subscriptionPeriodCode,\n            string countryCode,\n            DateTime expirationDate,\n            string status)\n        {\n            SubscriptionPaymentId = subscriptionPaymentId;\n            SubscriptionId = subscriptionId;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            CountryCode = countryCode;\n            ExpirationDate = expirationDate;\n            Status = status;\n            PayerId = payerId;\n        }\n\n        public Guid PayerId { get; }\n\n        public Guid SubscriptionPaymentId { get; }\n\n        public Guid SubscriptionId { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string CountryCode { get; }\n\n        public DateTime ExpirationDate { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/Events/SubscriptionExpiredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events\n{\n    public class SubscriptionExpiredDomainEvent : DomainEventBase\n    {\n        public SubscriptionExpiredDomainEvent(\n            Guid subscriptionId,\n            string status)\n        {\n            SubscriptionId = subscriptionId;\n            Status = status;\n        }\n\n        public Guid SubscriptionId { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/Events/SubscriptionRenewedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events\n{\n    public class SubscriptionRenewedDomainEvent : DomainEventBase\n    {\n        public SubscriptionRenewedDomainEvent(\n            Guid subscriptionId,\n            DateTime expirationDate,\n            Guid payerId,\n            string subscriptionPeriodCode,\n            string status)\n        {\n            SubscriptionId = subscriptionId;\n            ExpirationDate = expirationDate;\n            PayerId = payerId;\n            SubscriptionPeriodCode = subscriptionPeriodCode;\n            Status = status;\n        }\n\n        public Guid SubscriptionId { get; }\n\n        public DateTime ExpirationDate { get; }\n\n        public Guid PayerId { get; }\n\n        public string SubscriptionPeriodCode { get; }\n\n        public string Status { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/SubscriberId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class SubscriberId : TypedIdValueBase\n    {\n        public SubscriberId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/Subscription.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class Subscription : AggregateRoot\n    {\n        private SubscriberId _subscriberId;\n\n        private SubscriptionPeriod _subscriptionPeriod;\n\n        private SubscriptionStatus _status;\n\n        private string _countryCode;\n\n        private DateTime _expirationDate;\n\n        private Subscription()\n        {\n        }\n\n        public void Renew(\n            SubscriptionRenewalPaymentSnapshot subscriptionRenewalPayment)\n        {\n            var expirationDate = SubscriptionDateExpirationCalculator.CalculateForRenewal(\n                _expirationDate, subscriptionRenewalPayment.SubscriptionPeriod);\n\n            SubscriptionRenewedDomainEvent subscriptionRenewedDomainEvent = new SubscriptionRenewedDomainEvent(\n                this.Id,\n                expirationDate,\n                subscriptionRenewalPayment.PayerId.Value,\n                subscriptionRenewalPayment.SubscriptionPeriod.Code,\n                SubscriptionStatus.Active.Code);\n\n            this.Apply(subscriptionRenewedDomainEvent);\n            this.AddDomainEvent(subscriptionRenewedDomainEvent);\n        }\n\n        public void Expire()\n        {\n            if (_expirationDate < SystemClock.Now)\n            {\n                SubscriptionExpiredDomainEvent subscriptionExpiredDomainEvent =\n                    new SubscriptionExpiredDomainEvent(this.Id, SubscriptionStatus.Expired.Code);\n\n                this.When(subscriptionExpiredDomainEvent);\n                this.AddDomainEvent(subscriptionExpiredDomainEvent);\n            }\n        }\n\n        public static Subscription Create(\n            SubscriptionPaymentSnapshot subscriptionPayment)\n        {\n            var subscription = new Subscription();\n\n            var expirationDate = SubscriptionDateExpirationCalculator.CalculateForNew(subscriptionPayment.SubscriptionPeriod);\n\n            var subscriptionCreatedDomainEvent = new SubscriptionCreatedDomainEvent(\n                subscriptionPayment.Id.Value,\n                Guid.NewGuid(),\n                subscriptionPayment.PayerId.Value,\n                subscriptionPayment.SubscriptionPeriod.Code,\n                subscriptionPayment.CountryCode,\n                expirationDate,\n                SubscriptionStatus.Active.Code);\n\n            subscription.Apply(subscriptionCreatedDomainEvent);\n            subscription.AddDomainEvent(subscriptionCreatedDomainEvent);\n\n            return subscription;\n        }\n\n        protected sealed override void Apply(IDomainEvent @event)\n        {\n            this.When((dynamic)@event);\n        }\n\n        private void When(SubscriptionCreatedDomainEvent @event)\n        {\n            this.Id = @event.SubscriptionId;\n            _subscriberId = new SubscriberId(@event.PayerId);\n            _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            _countryCode = @event.CountryCode;\n            _status = SubscriptionStatus.Of(@event.Status);\n            _expirationDate = @event.ExpirationDate;\n        }\n\n        private void When(SubscriptionRenewedDomainEvent @event)\n        {\n            this.Id = @event.SubscriptionId;\n            _subscriptionPeriod = SubscriptionPeriod.Of(@event.SubscriptionPeriodCode);\n            _status = SubscriptionStatus.Of(@event.Status);\n            _expirationDate = @event.ExpirationDate;\n        }\n\n        private void When(SubscriptionExpiredDomainEvent @event)\n        {\n            _status = SubscriptionStatus.Of(@event.Status);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/SubscriptionDateExpirationCalculator.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class SubscriptionDateExpirationCalculator\n    {\n        public static DateTime CalculateForNew(SubscriptionPeriod period)\n        {\n            return SystemClock.Now.AddMonths(period.GetMonthsNumber());\n        }\n\n        public static DateTime CalculateForRenewal(DateTime expirationDate, SubscriptionPeriod period)\n        {\n            if (expirationDate > SystemClock.Now)\n            {\n                return expirationDate.AddMonths(period.GetMonthsNumber());\n            }\n\n            return SystemClock.Now.AddMonths(period.GetMonthsNumber());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/SubscriptionId.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class SubscriptionId : AggregateId<Subscription>\n    {\n        public SubscriptionId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/SubscriptionPeriod.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class SubscriptionPeriod : ValueObject\n    {\n        public string Code { get; }\n\n        public static SubscriptionPeriod Month => new SubscriptionPeriod(nameof(Month));\n\n        public static SubscriptionPeriod HalfYear => new SubscriptionPeriod(nameof(HalfYear));\n\n        public static SubscriptionPeriod Of(string code)\n        {\n            return new SubscriptionPeriod(code);\n        }\n\n        public static string GetName(string code)\n        {\n            return code == Month.Code\n                ? \"Month\"\n                : \"6 months\";\n        }\n\n        private SubscriptionPeriod(string code)\n        {\n            Code = code;\n        }\n\n        public int GetMonthsNumber() => this == Month ? 1 : 6;\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Subscriptions/SubscriptionStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions\n{\n    public class SubscriptionStatus : ValueObject\n    {\n        public static SubscriptionStatus Active => new SubscriptionStatus(nameof(Active));\n\n        public static SubscriptionStatus Expired => new SubscriptionStatus(nameof(Expired));\n\n        public string Code { get; }\n\n        private SubscriptionStatus(string code)\n        {\n            Code = code;\n        }\n\n        public static SubscriptionStatus Of(string code)\n        {\n            return new SubscriptionStatus(code);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Users/IUserContext.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Domain.Users\n{\n    public interface IUserContext\n    {\n        UserId UserId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Domain/Users/UserId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.Users\n{\n    public class UserId : TypedIdValueBase\n    {\n        public UserId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/AggregateStoreDomainEventsAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public class AggregateStoreDomainEventsAccessor : IDomainEventsAccessor\n    {\n        private readonly IAggregateStore _aggregateStore;\n\n        public AggregateStoreDomainEventsAccessor(IAggregateStore aggregateStore)\n        {\n            _aggregateStore = aggregateStore;\n        }\n\n        public IReadOnlyCollection<IDomainEvent> GetAllDomainEvents()\n        {\n            return _aggregateStore\n                .GetChanges()\n                .ToList()\n                .AsReadOnly();\n        }\n\n        public void ClearAllDomainEvents()\n        {\n            _aggregateStore.ClearChanges();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/DomainEventTypeMappings.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    internal static class DomainEventTypeMappings\n    {\n        internal static IDictionary<string, Type> Dictionary { get; }\n\n        static DomainEventTypeMappings()\n        {\n            Dictionary = new Dictionary<string, Type>();\n            Dictionary.Add(\"SubscriptionPaymentCreated\", typeof(SubscriptionPaymentCreatedDomainEvent));\n            Dictionary.Add(\"SubscriptionPaymentPaid\", typeof(SubscriptionPaymentPaidDomainEvent));\n            Dictionary.Add(\"SubscriptionPaymentExpired\", typeof(SubscriptionPaymentExpiredDomainEvent));\n\n            Dictionary.Add(\"SubscriptionRenewalPaymentCreated\", typeof(SubscriptionRenewalPaymentCreatedDomainEvent));\n            Dictionary.Add(\"SubscriptionRenewalPaymentPaid\", typeof(SubscriptionRenewalPaymentPaidDomainEvent));\n\n            Dictionary.Add(\"SubscriptionCreated\", typeof(SubscriptionCreatedDomainEvent));\n            Dictionary.Add(\"SubscriptionRenewed\", typeof(SubscriptionRenewedDomainEvent));\n            Dictionary.Add(\"SubscriptionExpired\", typeof(SubscriptionExpiredDomainEvent));\n\n            Dictionary.Add(\"PayerCreated\", typeof(PayerCreatedDomainEvent));\n\n            Dictionary.Add(\"PriceListItemCreated\", typeof(PriceListItemCreatedDomainEvent));\n            Dictionary.Add(\"PriceListItemActivated\", typeof(PriceListItemActivatedDomainEvent));\n            Dictionary.Add(\"PriceListItemDeactivated\", typeof(PriceListItemDeactivatedDomainEvent));\n            Dictionary.Add(\"PriceListItemAttributesChanged\", typeof(PriceListItemAttributesChangedDomainEvent));\n\n            Dictionary.Add(\"MeetingFeeCanceled\", typeof(MeetingFeeCanceledDomainEvent));\n            Dictionary.Add(\"MeetingFeeCreated\", typeof(MeetingFeeCreatedDomainEvent));\n            Dictionary.Add(\"MeetingFeeExpired\", typeof(MeetingFeeExpiredDomainEvent));\n            Dictionary.Add(\"MeetingFeePaid\", typeof(MeetingFeePaidDomainEvent));\n\n            Dictionary.Add(\"MeetingFeePaymentCreated\", typeof(MeetingFeePaymentCreatedDomainEvent));\n            Dictionary.Add(\"MeetingFeePaymentExpired\", typeof(MeetingFeePaymentExpiredDomainEvent));\n            Dictionary.Add(\"MeetingFeePaymentPaid\", typeof(MeetingFeePaymentPaidDomainEvent));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/ICheckpointStore.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public interface ICheckpointStore\n    {\n        long? GetCheckpoint(SubscriptionCode subscriptionCode);\n\n        Task StoreCheckpoint(SubscriptionCode subscriptionCode, long checkpoint);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/SqlOutboxAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public class SqlOutboxAccessor : IOutbox\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly List<OutboxMessage> _messages;\n\n        public SqlOutboxAccessor(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _messages = [];\n        }\n\n        public void Add(OutboxMessage message)\n        {\n            _messages.Add(message);\n        }\n\n        public async Task Save()\n        {\n            if (_messages.Any())\n            {\n                using var connection = _sqlConnectionFactory.CreateNewConnection();\n\n                const string sql = \"INSERT INTO [payments].[OutboxMessages] \" +\n                                   \"([Id], [OccurredOn], [Type], [Data]) VALUES \" +\n                                   \"(@Id, @OccurredOn, @Type, @Data)\";\n\n                foreach (var message in _messages)\n                {\n                    await connection.ExecuteScalarAsync(sql, new\n                    {\n                        message.Id,\n                        message.OccurredOn,\n                        message.Type,\n                        message.Data\n                    });\n                }\n\n                _messages.Clear();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/SqlServerCheckpointStore.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public class SqlServerCheckpointStore : ICheckpointStore\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public SqlServerCheckpointStore(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public long? GetCheckpoint(SubscriptionCode subscriptionCode)\n        {\n            using var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = \"\"\"\n                               SELECT [SubscriptionCheckpoint].Position \n                               FROM [payments].[SubscriptionCheckpoints] AS [SubscriptionCheckpoint] \n                               WHERE [Code] = @Code\n                               \"\"\";\n\n            var checkpoint = connection.QuerySingleOrDefault<long?>(\n                sql,\n                new\n                {\n                    Code = subscriptionCode\n                });\n\n            return checkpoint;\n        }\n\n        public async Task StoreCheckpoint(SubscriptionCode subscriptionCode, long checkpoint)\n        {\n            var actualCheckpoint = GetCheckpoint(subscriptionCode);\n\n            using var connection = _sqlConnectionFactory.GetOpenConnection();\n            if (actualCheckpoint == null)\n            {\n                await connection.ExecuteScalarAsync(\n                    \"INSERT INTO [payments].[SubscriptionCheckpoints] VALUES (@Code, @Position)\",\n                    new\n                    {\n                        Code = subscriptionCode,\n                        Position = checkpoint\n                    });\n            }\n            else\n            {\n                await connection.ExecuteScalarAsync(\n                    \"UPDATE [payments].[SubscriptionCheckpoints] \" +\n                    \"SET Position = @Position \" +\n                    \"WHERE Code = @Code\",\n                    new\n                    {\n                        Code = subscriptionCode,\n                        Position = checkpoint\n                    });\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/SqlStreamAggregateStore.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing Newtonsoft.Json;\nusing SqlStreamStore;\nusing SqlStreamStore.Streams;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public class SqlStreamAggregateStore : IAggregateStore\n    {\n        private readonly IStreamStore _streamStore;\n\n        private readonly List<IDomainEvent> _appendedChanges;\n\n        private readonly List<AggregateToSave> _aggregatesToSave;\n\n        public SqlStreamAggregateStore(\n            ISqlConnectionFactory sqlConnectionFactory, IStreamStore streamStore)\n        {\n            _appendedChanges = [];\n\n            _aggregatesToSave = [];\n            _streamStore = streamStore;\n        }\n\n        public async Task Save()\n        {\n            foreach (var aggregateToSave in _aggregatesToSave)\n            {\n                await _streamStore.AppendToStream(\n                    GetStreamId(aggregateToSave.Aggregate),\n                    aggregateToSave.Aggregate.Version,\n                    aggregateToSave.Messages.ToArray());\n            }\n\n            _aggregatesToSave.Clear();\n        }\n\n        public async Task<T> Load<T>(AggregateId<T> aggregateId)\n            where T : AggregateRoot\n        {\n            var streamId = GetStreamId(aggregateId);\n\n            List<IDomainEvent> domainEvents = [];\n            ReadStreamPage readStreamPage;\n            int position = StreamVersion.Start;\n            int take = 100;\n            do\n            {\n                readStreamPage = await _streamStore.ReadStreamForwards(streamId, position, take);\n                var messages = readStreamPage.Messages;\n                foreach (var streamMessage in messages)\n                {\n                    Type type = DomainEventTypeMappings.Dictionary[streamMessage.Type];\n                    var jsonData = await streamMessage.GetJsonData();\n                    var domainEvent = JsonConvert.DeserializeObject(jsonData, type) as IDomainEvent;\n\n                    domainEvents.Add(domainEvent);\n                }\n\n                position += take;\n            }\n            while (!readStreamPage.IsEnd);\n\n            if (!domainEvents.Any())\n            {\n                return null;\n            }\n\n            var aggregate = (T)Activator.CreateInstance(typeof(T), true);\n\n            aggregate.Load(domainEvents);\n\n            return aggregate;\n        }\n\n        public List<IDomainEvent> GetChanges()\n        {\n            return _appendedChanges;\n        }\n\n        public void AppendChanges<T>(T aggregate)\n            where T : AggregateRoot\n        {\n            _aggregatesToSave.Add(new AggregateToSave(aggregate, CreateStreamMessages(aggregate).ToList()));\n        }\n\n        public void ClearChanges()\n        {\n            _appendedChanges.Clear();\n        }\n\n        private class AggregateToSave\n        {\n            public AggregateToSave(AggregateRoot aggregate, List<NewStreamMessage> messages)\n            {\n                Aggregate = aggregate;\n                Messages = messages;\n            }\n\n            public AggregateRoot Aggregate { get; }\n\n            public List<NewStreamMessage> Messages { get; }\n        }\n\n        private NewStreamMessage[] CreateStreamMessages<T>(\n            T aggregate)\n            where T : AggregateRoot\n        {\n            List<NewStreamMessage> newStreamMessages = [];\n\n            var domainEvents = aggregate.GetDomainEvents();\n\n            foreach (var domainEvent in domainEvents)\n            {\n                string jsonData = JsonConvert.SerializeObject(domainEvent, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                });\n                var message = new NewStreamMessage(\n                    domainEvent.Id,\n                    MapDomainEventToType(domainEvent),\n                    jsonData);\n                newStreamMessages.Add(message);\n                _appendedChanges.Add(domainEvent);\n            }\n\n            return newStreamMessages.ToArray();\n        }\n\n        private string MapDomainEventToType(IDomainEvent domainEvent)\n        {\n            foreach (var key in DomainEventTypeMappings.Dictionary.Keys)\n            {\n                if (DomainEventTypeMappings.Dictionary[key] == domainEvent.GetType())\n                {\n                    return key;\n                }\n            }\n\n            throw new ArgumentException(\"Invalid Domain Event type\", nameof(domainEvent));\n        }\n\n        private static string GetStreamId<T>(T aggregate)\n            where T : AggregateRoot\n        {\n            return $\"{aggregate.GetType().Name}-{aggregate.Id:N}\";\n        }\n\n        private static string GetStreamId<T>(AggregateId<T> aggregateId)\n            where T : AggregateRoot\n            => $\"{typeof(T).Name}-{aggregateId.Value:N}\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/SubscriptionCode.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public enum SubscriptionCode\n    {\n        /// <summary>\n        /// All.\n        /// </summary>\n        All\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/AggregateStore/SubscriptionsManager.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing Newtonsoft.Json;\nusing SqlStreamStore;\nusing SqlStreamStore.Streams;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore\n{\n    public class SubscriptionsManager\n    {\n        private readonly IStreamStore _streamStore;\n\n        public SubscriptionsManager(\n            IStreamStore streamStore)\n        {\n            _streamStore = streamStore;\n        }\n\n        public void Start()\n        {\n            long? actualPosition;\n\n            using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n            {\n                var checkpointStore = scope.Resolve<ICheckpointStore>();\n\n                actualPosition = checkpointStore.GetCheckpoint(SubscriptionCode.All);\n            }\n\n            _streamStore.SubscribeToAll(actualPosition, StreamMessageReceived);\n        }\n\n        public void Stop()\n        {\n            _streamStore.Dispose();\n        }\n\n        private static async Task StreamMessageReceived(\n            IAllStreamSubscription subscription, StreamMessage streamMessage, CancellationToken cancellationToken)\n        {\n            var type = DomainEventTypeMappings.Dictionary[streamMessage.Type];\n            var jsonData = await streamMessage.GetJsonData(cancellationToken);\n            var domainEvent = JsonConvert.DeserializeObject(jsonData, type) as IDomainEvent;\n\n            using var scope = PaymentsCompositionRoot.BeginLifetimeScope();\n\n            var projectors = scope.Resolve<IList<IProjector>>();\n\n            foreach (var projector in projectors)\n            {\n                await projector.Project(domainEvent);\n            }\n\n            var checkpointStore = scope.Resolve<ICheckpointStore>();\n            await checkpointStore.StoreCheckpoint(SubscriptionCode.All, streamMessage.Position);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/CompanyName.MyMeetings.Modules.Payments.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/AllConstructorFinder.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing Autofac.Core.Activators.Reflection;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration\n{\n    internal class AllConstructorFinder : IConstructorFinder\n    {\n        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =\n            new ConcurrentDictionary<Type, ConstructorInfo[]>();\n\n        public ConstructorInfo[] FindConstructors(Type targetType)\n        {\n            var result = Cache.GetOrAdd(\n                targetType,\n                t => t.GetTypeInfo().DeclaredConstructors.ToArray());\n\n            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType, this);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Assemblies.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration\n{\n    internal static class Assemblies\n    {\n        public static readonly Assembly Application = typeof(IPaymentsModule).Assembly;\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Authentication/AuthenticationModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Authentication\n{\n    internal class AuthenticationModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<PayerContext>()\n                .As<IPayerContext>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Authentication/PayerContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Authentication\n{\n    internal class PayerContext : IPayerContext\n    {\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public PayerContext(IExecutionContextAccessor executionContextAccessor)\n        {\n            this._executionContextAccessor = executionContextAccessor;\n        }\n\n        public PayerId PayerId => new PayerId(_executionContextAccessor.UserId);\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/DataAccess/DataAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Projections;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore;\nusing Microsoft.Extensions.Logging;\nusing SqlStreamStore;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.DataAccess\n{\n    internal class DataAccessModule : Autofac.Module\n    {\n        private readonly string _databaseConnectionString;\n        private readonly ILoggerFactory _loggerFactory;\n\n        internal DataAccessModule(string databaseConnectionString, ILoggerFactory loggerFactory)\n        {\n            _databaseConnectionString = databaseConnectionString;\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlConnectionFactory>()\n                .As<ISqlConnectionFactory>()\n                .WithParameter(\"connectionString\", _databaseConnectionString)\n                .InstancePerLifetimeScope();\n\n            builder.Register(a =>\n            new MsSqlStreamStore(new MsSqlStreamStoreSettings(_databaseConnectionString)\n            {\n                Schema = DatabaseSchema.Name\n            }))\n                .As<IStreamStore>();\n\n            builder.RegisterType<SqlStreamAggregateStore>()\n                .As<IAggregateStore>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<SqlServerCheckpointStore>()\n                .As<ICheckpointStore>()\n                .InstancePerLifetimeScope();\n\n            var applicationAssembly = typeof(IProjector).Assembly;\n            builder.RegisterAssemblyTypes(applicationAssembly)\n                .Where(type => type.Name.EndsWith(\"Projector\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n\n            builder.RegisterType<SubscriptionsManager>()\n                .As<SubscriptionsManager>()\n                .SingleInstance();\n\n            var infrastructureAssembly = ThisAssembly;\n\n            builder.RegisterAssemblyTypes(infrastructureAssembly)\n                .Where(type => type.Name.EndsWith(\"Repository\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/DatabaseSchema.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration\n{\n    public class DatabaseSchema\n    {\n        public const string Name = \"payments\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Email/EmailModule.cs",
    "content": "using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Email\n{\n    internal class EmailModule : Module\n    {\n        private readonly EmailsConfiguration _configuration;\n\n        public EmailModule(EmailsConfiguration configuration)\n        {\n            _configuration = configuration;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<EmailSender>()\n                .As<IEmailSender>()\n                .WithParameter(\"configuration\", _configuration)\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/EventsBus/EventsBusModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.EventsBus\n{\n    internal class EventsBusModule : Autofac.Module\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public EventsBusModule(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_eventsBus != null)\n            {\n                builder.RegisterInstance(_eventsBus)\n                    .As<IEventsBus>();\n            }\n            else\n            {\n                builder.RegisterType<InMemoryEventBusClient>()\n                    .As<IEventsBus>()\n                    .SingleInstance();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/EventsBus/EventsBusStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Administration.IntegrationEvents.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.EventsBus\n{\n    public static class EventsBusStartup\n    {\n        public static void Initialize(\n            ILogger logger)\n        {\n            SubscribeToIntegrationEvents(logger);\n        }\n\n        private static void SubscribeToIntegrationEvents(ILogger logger)\n        {\n            var eventBus = PaymentsCompositionRoot.BeginLifetimeScope().Resolve<IEventsBus>();\n\n            SubscribeToIntegrationEvent<MeetingGroupProposalAcceptedIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<NewUserRegisteredIntegrationEvent>(eventBus, logger);\n            SubscribeToIntegrationEvent<MeetingAttendeeAddedIntegrationEvent>(eventBus, logger);\n        }\n\n        private static void SubscribeToIntegrationEvent<T>(IEventsBus eventBus, ILogger logger)\n            where T : IntegrationEvent\n        {\n            logger.Information(\"Subscribe to {@IntegrationEvent}\", typeof(T).FullName);\n            eventBus.Subscribe(\n                new IntegrationEventGenericHandler<T>());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/EventsBus/IntegrationEventGenericHandler.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.EventsBus\n{\n    internal class IntegrationEventGenericHandler<T> : IIntegrationEventHandler<T>\n        where T : IntegrationEvent\n    {\n        public async Task Handle(T @event)\n        {\n            using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n            {\n                using (var connection = scope.Resolve<ISqlConnectionFactory>().GetOpenConnection())\n                {\n                    string type = @event.GetType().FullName;\n                    var data = JsonConvert.SerializeObject(@event, new JsonSerializerSettings\n                    {\n                        ContractResolver = new AllPropertiesContractResolver()\n                    });\n\n                    var sql = \"INSERT INTO [payments].[InboxMessages] (Id, OccurredOn, Type, Data) \" +\n                              \"VALUES (@Id, @OccurredOn, @Type, @Data)\";\n\n                    await connection.ExecuteScalarAsync(sql, new\n                    {\n                        @event.Id,\n                        @event.OccurredOn,\n                        type,\n                        data\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Logging/LoggingModule.cs",
    "content": "﻿using Autofac;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Logging\n{\n    internal class LoggingModule : Autofac.Module\n    {\n        private readonly ILogger _logger;\n\n        internal LoggingModule(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterInstance(_logger)\n                .As<ILogger>()\n                .SingleInstance();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Mediation/MediatorModule.cs",
    "content": "﻿using System.Reflection;\nusing Autofac;\nusing Autofac.Core;\nusing Autofac.Features.Variance;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing FluentValidation;\nusing MediatR;\nusing MediatR.Pipeline;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Mediation\n{\n    public class MediatorModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<ServiceProviderWrapper>()\n            .As<IServiceProvider>()\n            .InstancePerDependency()\n            .IfNotRegistered(typeof(IServiceProvider));\n\n            builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope();\n\n            var mediatorOpenTypes = new[]\n            {\n                typeof(IRequestHandler<,>),\n                typeof(INotificationHandler<>),\n                typeof(IValidator<>),\n                typeof(IRequestPreProcessor<>),\n                typeof(IRequestHandler<>),\n                typeof(IStreamRequestHandler<,>),\n                typeof(IRequestPostProcessor<,>),\n                typeof(IRequestExceptionHandler<,,>),\n                typeof(IRequestExceptionAction<,>),\n                typeof(ICommandHandler<>),\n                typeof(ICommandHandler<,>),\n            };\n            builder.RegisterSource(new ScopedContravariantRegistrationSource(\n                mediatorOpenTypes));\n            foreach (var mediatorOpenType in mediatorOpenTypes)\n            {\n                builder\n                    .RegisterAssemblyTypes(Assemblies.Application, ThisAssembly)\n                    .AsClosedTypesOf(mediatorOpenType)\n                    .AsImplementedInterfaces()\n                    .FindConstructorsWith(new AllConstructorFinder());\n            }\n\n            builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n            builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n        }\n\n        private class ScopedContravariantRegistrationSource : IRegistrationSource\n        {\n            private readonly ContravariantRegistrationSource _source = new();\n            private readonly List<Type> _types = new();\n\n            public ScopedContravariantRegistrationSource(params Type[] types)\n            {\n                ArgumentNullException.ThrowIfNull(types);\n\n                if (!types.All(x => x.IsGenericTypeDefinition))\n                {\n                    throw new ArgumentException(\"Supplied types should be generic type definitions\");\n                }\n\n                _types.AddRange(types);\n            }\n\n            public IEnumerable<IComponentRegistration> RegistrationsFor(\n                Service service,\n                Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)\n            {\n                var components = _source.RegistrationsFor(service, registrationAccessor);\n                foreach (var c in components)\n                {\n                    var defs = c.Target.Services\n                        .OfType<TypedService>()\n                        .Select(x => x.ServiceType.GetGenericTypeDefinition());\n\n                    if (defs.Any(_types.Contains))\n                    {\n                        yield return c;\n                    }\n                }\n            }\n\n            public bool IsAdapterForIndividualComponents => _source.IsAdapterForIndividualComponents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/PaymentsCompositionRoot.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration\n{\n    public static class PaymentsCompositionRoot\n    {\n        private static IContainer _container;\n\n        public static void SetContainer(IContainer container)\n        {\n            _container = container;\n        }\n\n        public static ILifetimeScope BeginLifetimeScope()\n        {\n            return _container.BeginLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/PaymentsStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeeAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.RenewSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Authentication;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.DataAccess;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Email;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.EventsBus;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Logging;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Mediation;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz;\nusing ILogger = Serilog.ILogger;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration\n{\n    public class PaymentsStartup\n    {\n        private static IContainer _container;\n\n        private static SubscriptionsManager _subscriptionsManager;\n\n        public static void Initialize(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            IEventsBus eventsBus,\n            bool runQuartz = true,\n            long? internalProcessingPoolingInterval = null)\n        {\n            var moduleLogger = logger.ForContext(\"Module\", \"Payments\");\n\n            ConfigureCompositionRoot(connectionString, executionContextAccessor, moduleLogger, emailsConfiguration, eventsBus, runQuartz);\n\n            if (runQuartz)\n            {\n                QuartzStartup.Initialize(moduleLogger, internalProcessingPoolingInterval);\n            }\n\n            EventsBusStartup.Initialize(moduleLogger);\n        }\n\n        public static void Stop()\n        {\n            _subscriptionsManager.Stop();\n            QuartzStartup.StopQuartz();\n        }\n\n        private static void ConfigureCompositionRoot(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            IEventsBus eventsBus,\n            bool runQuartz = true)\n        {\n            var containerBuilder = new ContainerBuilder();\n\n            containerBuilder.RegisterModule(new LoggingModule(logger));\n\n            var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(logger);\n            containerBuilder.RegisterModule(new DataAccessModule(connectionString, loggerFactory));\n\n            containerBuilder.RegisterModule(new ProcessingModule());\n            containerBuilder.RegisterModule(new EmailModule(emailsConfiguration));\n            containerBuilder.RegisterModule(new EventsBusModule(eventsBus));\n            containerBuilder.RegisterModule(new MediatorModule());\n            containerBuilder.RegisterModule(new AuthenticationModule());\n\n            BiDictionary<string, Type> domainNotificationsMap = new BiDictionary<string, Type>();\n            domainNotificationsMap.Add(\"MeetingFeePaidNotification\", typeof(MeetingFeePaidNotification));\n            domainNotificationsMap.Add(\"MeetingFeePaymentPaidNotification\", typeof(MeetingFeePaymentPaidNotification));\n            domainNotificationsMap.Add(\"SubscriptionCreatedNotification\", typeof(SubscriptionCreatedNotification));\n            domainNotificationsMap.Add(\"SubscriptionPaymentPaidNotification\", typeof(SubscriptionPaymentPaidNotification));\n            domainNotificationsMap.Add(\"SubscriptionRenewalPaymentPaidNotification\", typeof(SubscriptionRenewalPaymentPaidNotification));\n            domainNotificationsMap.Add(\"SubscriptionRenewedNotification\", typeof(SubscriptionRenewedNotification));\n\n            containerBuilder.RegisterModule(new OutboxModule(domainNotificationsMap));\n\n            if (runQuartz)\n            {\n                containerBuilder.RegisterModule(new QuartzModule());\n            }\n\n            containerBuilder.RegisterInstance(executionContextAccessor);\n\n            _container = containerBuilder.Build();\n\n            PaymentsCompositionRoot.SetContainer(_container);\n\n            RunEventsProjectors();\n        }\n\n        private static void RunEventsProjectors()\n        {\n            _subscriptionsManager = _container.Resolve<SubscriptionsManager>();\n\n            _subscriptionsManager.Start();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/CommandsExecutor.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal static class CommandsExecutor\n    {\n        internal static async Task Execute(ICommand command)\n        {\n            using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                await mediator.Send(command);\n            }\n        }\n\n        internal static async Task<TResult> Execute<TResult>(ICommand<TResult> command)\n        {\n            using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                return await mediator.Send(command);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Inbox/InboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Inbox\n{\n    public class InboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Inbox\n{\n    public class ProcessInboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Inbox\r\n{\r\n    internal class ProcessInboxCommandHandler : ICommandHandler<ProcessInboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInboxCommandHandler(IMediator mediator, ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                                SELECT [InboxMessage].[Id] AS [{nameof(InboxMessageDto.Id)}],\r\n                                       [InboxMessage].[Type] AS [{nameof(InboxMessageDto.Type)}],\r\n                                       [InboxMessage].[Data] AS [{nameof(InboxMessageDto.Data)}]\r\n                                FROM [payments].[InboxMessages] AS [InboxMessage]\r\n                                WHERE [InboxMessage].[ProcessedDate] IS NULL\r\n                                ORDER BY [InboxMessage].[OccurredOn]\r\n                                \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<InboxMessageDto>(sql);\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [payments].[InboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n\r\n            foreach (var message in messages)\r\n            {\r\n                var messageAssembly = AppDomain.CurrentDomain.GetAssemblies()\r\n                    .SingleOrDefault(assembly => message.Type.Contains(assembly.GetName().Name));\r\n\r\n                Type type = messageAssembly.GetType(message.Type);\r\n                var request = JsonConvert.DeserializeObject(message.Data, type);\r\n\r\n                try\r\n                {\r\n                    await _mediator.Publish((INotification)request, cancellationToken);\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    Console.WriteLine(e);\r\n                    throw;\r\n                }\r\n\r\n                await connection.ExecuteScalarAsync(sqlUpdateProcessedDate, new\r\n                {\r\n                    Date = DateTime.UtcNow,\r\n                    message.Id\r\n                });\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Inbox/ProcessInboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Inbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/InternalCommands/CommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands\n{\n    public class CommandsScheduler : ICommandsScheduler\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public CommandsScheduler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task EnqueueAsync(ICommand command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [payments].[InternalCommands] ([Id], [EnqueueDate], [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n\n        public async Task EnqueueAsync<T>(ICommand<T> command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [payments].[InternalCommands] ([Id], [EnqueueDate], [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing Newtonsoft.Json;\r\nusing Polly;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands\r\n{\r\n    internal class ProcessInternalCommandsCommandHandler : ICommandHandler<ProcessInternalCommandsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInternalCommandsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInternalCommandsCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n\r\n            const string sql = $\"\"\"\r\n                               SELECT [Command].[Id] AS [{nameof(InternalCommandDto.Id)}], \r\n                                      [Command].[Type] AS [{nameof(InternalCommandDto.Type)}], \r\n                                      [Command].[Data] AS [{nameof(InternalCommandDto.Data)}] \r\n                               FROM [payments].[InternalCommands] AS [Command] \r\n                               WHERE [Command].[ProcessedDate] IS NULL \r\n                               ORDER BY [Command].[EnqueueDate]\r\n                               \"\"\";\r\n            var commands = await connection.QueryAsync<InternalCommandDto>(sql);\r\n\r\n            var internalCommandsList = commands.AsList();\r\n\r\n            var policy = Policy\r\n                .Handle<Exception>()\r\n                .WaitAndRetryAsync(new[]\r\n                {\r\n                    TimeSpan.FromSeconds(1),\r\n                    TimeSpan.FromSeconds(2),\r\n                    TimeSpan.FromSeconds(3)\r\n                });\r\n\r\n            foreach (var internalCommand in internalCommandsList)\r\n            {\r\n                var result = await policy.ExecuteAndCaptureAsync(() => ProcessCommand(\r\n                    internalCommand));\r\n\r\n                if (result.Outcome == OutcomeType.Failure)\r\n                {\r\n                    await connection.ExecuteScalarAsync(\r\n                        \"UPDATE [payments].[InternalCommands] \" +\r\n                        \"SET ProcessedDate = @NowDate, \" +\r\n                        \"Error = @Error \" +\r\n                        \"WHERE [Id] = @Id\",\r\n                        new\r\n                        {\r\n                            NowDate = DateTime.UtcNow,\r\n                            Error = result.FinalException.ToString(),\r\n                            internalCommand.Id\r\n                        });\r\n                }\r\n            }\r\n        }\r\n\r\n        private async Task ProcessCommand(\r\n            InternalCommandDto internalCommand)\r\n        {\r\n            Type type = Assemblies.Application.GetType(internalCommand.Type);\r\n            dynamic commandToProcess = JsonConvert.DeserializeObject(internalCommand.Data, type);\r\n\r\n            await CommandsExecutor.Execute(commandToProcess);\r\n        }\r\n\r\n        private class InternalCommandDto\r\n        {\r\n            public Guid Id { get; set; }\r\n\r\n            public string Type { get; set; }\r\n\r\n            public string Data { get; set; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInternalCommandsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInternalCommandsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/LoggingCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\r\nusing Serilog;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\r\n{\r\n    internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ILogger _logger;\r\n        private readonly IExecutionContextAccessor _executionContextAccessor;\r\n        private readonly ICommandHandler<T> _decorated;\r\n\r\n        public LoggingCommandHandlerDecorator(\r\n            ILogger logger,\r\n            IExecutionContextAccessor executionContextAccessor,\r\n            ICommandHandler<T> decorated)\r\n        {\r\n            _logger = logger;\r\n            _executionContextAccessor = executionContextAccessor;\r\n            _decorated = decorated;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            if (command is IRecurringCommand)\r\n            {\r\n                await _decorated.Handle(command, cancellationToken);\r\n\r\n                return;\r\n            }\r\n\r\n            using (\r\n                LogContext.Push(\r\n                    new RequestLogEnricher(_executionContextAccessor),\r\n                    new CommandLogEnricher(command)))\r\n            {\r\n                try\r\n                {\r\n                    this._logger.Information(\r\n                        \"Executing command {Command}\",\r\n                        command.GetType().Name);\r\n\r\n                    await _decorated.Handle(command, cancellationToken);\r\n\r\n                    this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\r\n                }\r\n                catch (Exception exception)\r\n                {\r\n                    this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\r\n                    throw;\r\n                }\r\n            }\r\n        }\r\n\r\n        private class CommandLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly ICommand _command;\r\n\r\n            public CommandLogEnricher(ICommand command)\r\n            {\r\n                _command = command;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\r\n            }\r\n        }\r\n\r\n        private class RequestLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IExecutionContextAccessor _executionContextAccessor;\r\n\r\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\r\n            {\r\n                _executionContextAccessor = executionContextAccessor;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                if (_executionContextAccessor.IsAvailable)\r\n                {\r\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/LoggingCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public LoggingCommandHandlerWithResultDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T, TResult> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                return await _decorated.Handle(command, cancellationToken);\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {@Command}\",\n                        command);\n\n                    var result = await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command processed successful, result {Result}\", result);\n\n                    return result;\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command processing failed\");\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand<TResult> _command;\n\n            public CommandLogEnricher(ICommand<TResult> command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\n                    \"Context\",\n                    new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\n                        \"CorrelationId\",\n                        new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Outbox/OutboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox\n{\n    public class OutboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Outbox/OutboxModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class OutboxModule : Module\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public OutboxModule(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlOutboxAccessor>()\n                .As<IOutbox>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .InstancePerLifetimeScope();\n\n            this.CheckMappings();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"domainNotificationsMap\", _domainNotificationsMap)\n                .SingleInstance();\n        }\n\n        private void CheckMappings()\n        {\n            var domainEventNotifications = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.GetInterfaces().Contains(typeof(IDomainEventNotification)))\n                .ToList();\n\n            List<Type> notMappedNotifications = [];\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                _domainNotificationsMap.TryGetBySecond(domainEventNotification, out var name);\n\n                if (name == null)\n                {\n                    notMappedNotifications.Add(domainEventNotification);\n                }\n            }\n\n            if (notMappedNotifications.Any())\n            {\n                throw new ApplicationException($\"Domain Event Notifications {notMappedNotifications.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox\n{\n    public class ProcessOutboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox\r\n{\r\n    internal class ProcessOutboxCommandHandler : ICommandHandler<ProcessOutboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\r\n\r\n        public ProcessOutboxCommandHandler(\r\n            IMediator mediator,\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IDomainNotificationsMapper domainNotificationsMapper)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _domainNotificationsMapper = domainNotificationsMapper;\r\n        }\r\n\r\n        public async Task Handle(ProcessOutboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                                SELECT \r\n                                  [OutboxMessage].[Id] AS [{nameof(OutboxMessageDto.Id)}], \r\n                                  [OutboxMessage].[Type] AS [{nameof(OutboxMessageDto.Type)}], \r\n                                  [OutboxMessage].[Data] AS [{nameof(OutboxMessageDto.Data)}] \r\n                                FROM [payments].[OutboxMessages] AS [OutboxMessage] \r\n                                WHERE [OutboxMessage].[ProcessedDate] IS NULL \r\n                                ORDER BY [OutboxMessage].[OccurredOn]\r\n                               \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\r\n            var messagesList = messages.AsList();\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [payments].[OutboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n            if (messagesList.Count > 0)\r\n            {\r\n                foreach (var message in messagesList)\r\n                {\r\n                    var type = _domainNotificationsMapper.GetType(message.Type);\r\n                    var @event = JsonConvert.DeserializeObject(message.Data, type) as IDomainEventNotification;\r\n\r\n                    using (LogContext.Push(new OutboxMessageContextEnricher(@event)))\r\n                    {\r\n                        await this._mediator.Publish(@event, cancellationToken);\r\n\r\n                        await connection.ExecuteAsync(sqlUpdateProcessedDate, new\r\n                        {\r\n                            Date = DateTime.UtcNow,\r\n                            message.Id\r\n                        });\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private class OutboxMessageContextEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IDomainEventNotification _notification;\r\n\r\n            public OutboxMessageContextEnricher(IDomainEventNotification notification)\r\n            {\r\n                _notification = notification;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"OutboxMessage:{_notification.Id.ToString()}\")));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessOutboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessOutboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/PaymentsUnitOfWork.cs",
    "content": "﻿using System.Transactions;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    public class PaymentsUnitOfWork : IUnitOfWork\n    {\n        private readonly IOutbox _outbox;\n\n        private readonly IAggregateStore _aggregateStore;\n\n        private readonly IDomainEventsDispatcher _domainEventsDispatcher;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public PaymentsUnitOfWork(\n            IOutbox outbox,\n            IAggregateStore aggregateStore,\n            IDomainEventsDispatcher domainEventsDispatcher,\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _outbox = outbox;\n            _aggregateStore = aggregateStore;\n            _domainEventsDispatcher = domainEventsDispatcher;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<int> CommitAsync(\n            CancellationToken cancellationToken = default,\n            Guid? internalCommandId = null)\n        {\n            await _domainEventsDispatcher.DispatchEventsAsync();\n\n            var options = new TransactionOptions\n            {\n                IsolationLevel = IsolationLevel.ReadCommitted\n            };\n\n            using var transaction = new TransactionScope(\n                TransactionScopeOption.Required,\n                options,\n                TransactionScopeAsyncFlowOption.Enabled);\n\n            await _aggregateStore.Save();\n\n            await _outbox.Save();\n\n            if (internalCommandId.HasValue)\n            {\n                using var connection = _sqlConnectionFactory.CreateNewConnection();\n                await connection.ExecuteScalarAsync(\n                    \"UPDATE payments.InternalCommands \" +\n                    \"SET ProcessedDate = @Date \" +\n                    \"WHERE Id = @Id\",\n                    new\n                    {\n                        Date = DateTime.UtcNow,\n                        Id = internalCommandId.Value\n                    });\n            }\n\n            transaction.Complete();\n\n            return 0;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/ProcessingModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.AggregateStore;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal class ProcessingModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<DomainEventsDispatcher>()\n                .As<IDomainEventsDispatcher>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<AggregateStoreDomainEventsAccessor>()\n                .As<IDomainEventsAccessor>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<PaymentsUnitOfWork>()\n                .As<IUnitOfWork>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<CommandsScheduler>()\n                .As<ICommandsScheduler>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerDecorator<>),\n                typeof(IRequestHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerWithResultDecorator<,>),\n                typeof(IRequestHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(DomainEventsDispatcherNotificationHandlerDecorator<>),\n                typeof(INotificationHandler<>));\n\n            builder.RegisterAssemblyTypes(Assemblies.Application)\n                .AsClosedTypesOf(typeof(IDomainEventNotification<>))\n                .InstancePerDependency()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\r\n{\r\n    internal class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ICommandHandler<T> _decorated;\r\n\r\n        private readonly IUnitOfWork _unitOfWork;\r\n\r\n        public UnitOfWorkCommandHandlerDecorator(\r\n            ICommandHandler<T> decorated,\r\n            IUnitOfWork unitOfWork)\r\n        {\r\n            _decorated = decorated;\r\n            _unitOfWork = unitOfWork;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            await this._decorated.Handle(command, cancellationToken);\r\n\r\n            Guid? internalCommandId = null;\r\n            if (command is InternalCommandBase)\r\n            {\r\n                internalCommandId = command.Id;\r\n            }\r\n\r\n            await this._unitOfWork.CommitAsync(cancellationToken, internalCommandId);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        private readonly IUnitOfWork _unitOfWork;\n\n        public UnitOfWorkCommandHandlerWithResultDecorator(\n            ICommandHandler<T, TResult> decorated,\n            IUnitOfWork unitOfWork)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var result = await this._decorated.Handle(command, cancellationToken);\n\n            Guid? internalCommandId = null;\n            if (command is InternalCommandBase<TResult>)\n            {\n                internalCommandId = command.Id;\n            }\n\n            await _unitOfWork.CommitAsync(cancellationToken, internalCommandId);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T> _decorated;\n\n        public ValidationCommandHandlerDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            await _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Quartz/Jobs/ExpireSubscriptionPaymentsJob.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz.Jobs\n{\n    public class ExpireSubscriptionPaymentsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ExpireSubscriptionPaymentsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Quartz/Jobs/ExpireSubscriptionsJob.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz.Jobs\n{\n    public class ExpireSubscriptionsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ExpireSubscriptionsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Quartz/QuartzModule.cs",
    "content": "﻿using Autofac;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz\n{\n    public class QuartzModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterAssemblyTypes(ThisAssembly)\n                .Where(x => typeof(IJob).IsAssignableFrom(x)).InstancePerDependency();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Quartz/QuartzStartup.cs",
    "content": "﻿using System.Collections.Specialized;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Inbox;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz.Jobs;\nusing Quartz;\nusing Quartz.Impl;\nusing Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz\n{\n    internal static class QuartzStartup\n    {\n        private static IScheduler _scheduler;\n\n        internal static void StopQuartz()\n        {\n            _scheduler.Shutdown();\n        }\n\n        internal static void Initialize(ILogger logger, long? internalProcessingPoolingInterval)\n        {\n            logger.Information(\"Quartz starting...\");\n\n            var schedulerConfiguration = new NameValueCollection();\n            schedulerConfiguration.Add(\"quartz.scheduler.instanceName\", \"Meetings\");\n\n            ISchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerConfiguration);\n            _scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult();\n\n            LogProvider.SetCurrentLogProvider(new SerilogLogProvider(logger));\n\n            _scheduler.Start().GetAwaiter().GetResult();\n\n            ScheduleProcessOutboxJob(_scheduler, internalProcessingPoolingInterval);\n\n            ScheduleProcessInboxJob(_scheduler, internalProcessingPoolingInterval);\n\n            ScheduleProcessInternalCommandsJob(_scheduler, internalProcessingPoolingInterval);\n\n            ScheduleExpireSubscriptionsJob(_scheduler);\n\n            ScheduleExpireSubscriptionPaymentsJob(_scheduler);\n\n            logger.Information(\"Quartz started.\");\n        }\n\n        private static void ScheduleExpireSubscriptionPaymentsJob(IScheduler scheduler)\n        {\n            var expireSubscriptionPaymentsJob = JobBuilder.Create<ExpireSubscriptionPaymentsJob>().Build();\n            var triggerCommandsProcessing =\n                TriggerBuilder\n                    .Create()\n                    .StartNow()\n                    .WithCronSchedule(\"0/59 * * ? * *\")\n                    .Build();\n\n            scheduler.ScheduleJob(expireSubscriptionPaymentsJob, triggerCommandsProcessing).GetAwaiter().GetResult();\n        }\n\n        private static void ScheduleExpireSubscriptionsJob(IScheduler scheduler)\n        {\n            var expireSubscriptionsJob = JobBuilder.Create<ExpireSubscriptionsJob>().Build();\n            var triggerCommandsProcessing =\n                TriggerBuilder\n                    .Create()\n                    .StartNow()\n                    .WithCronSchedule(\"0/59 * * ? * *\")\n                    .Build();\n\n            scheduler.ScheduleJob(expireSubscriptionsJob, triggerCommandsProcessing).GetAwaiter().GetResult();\n        }\n\n        private static void ScheduleProcessInternalCommandsJob(\n            IScheduler scheduler,\n            long? internalProcessingPoolingInterval)\n        {\n            var processInternalCommandsJob = JobBuilder.Create<ProcessInternalCommandsJob>().Build();\n\n            ITrigger triggerCommandsProcessing;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                triggerCommandsProcessing =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                triggerCommandsProcessing =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler.ScheduleJob(processInternalCommandsJob, triggerCommandsProcessing).GetAwaiter().GetResult();\n        }\n\n        private static void ScheduleProcessInboxJob(IScheduler scheduler, long? internalProcessingPoolingInterval)\n        {\n            var processInboxJob = JobBuilder.Create<ProcessInboxJob>().Build();\n\n            ITrigger processInboxTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processInboxJob, processInboxTrigger)\n                .GetAwaiter().GetResult();\n        }\n\n        private static void ScheduleProcessOutboxJob(IScheduler scheduler, long? internalProcessingPoolingInterval)\n        {\n            var processOutboxJob = JobBuilder.Create<ProcessOutboxJob>().Build();\n\n            ITrigger trigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processOutboxJob, trigger)\n                .GetAwaiter().GetResult();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/Configuration/Quartz/SerilogLogProvider.cs",
    "content": "﻿using Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Quartz\n{\n    internal class SerilogLogProvider : ILogProvider\n    {\n        private readonly ILogger _logger;\n\n        internal SerilogLogProvider(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public Logger GetLogger(string name)\n        {\n            return (level, func, exception, parameters) =>\n            {\n                if (func == null)\n                {\n                    return true;\n                }\n\n                if (level == LogLevel.Debug || level == LogLevel.Trace)\n                {\n                    _logger.Debug(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Info)\n                {\n                    _logger.Information(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Warn)\n                {\n                    _logger.Warning(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Error)\n                {\n                    _logger.Error(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Fatal)\n                {\n                    _logger.Fatal(exception, func(), parameters);\n                }\n\n                return true;\n            };\n        }\n\n        public IDisposable OpenNestedContext(string message)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, string value)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, object value, bool destructure = false)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/InternalCommands/InternalCommandEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure.InternalCommands\n{\n    internal class InternalCommandEntityTypeConfiguration : IEntityTypeConfiguration<InternalCommand>\n    {\n        public void Configure(EntityTypeBuilder<InternalCommand> builder)\n        {\n            builder.ToTable(\"InternalCommands\", \"payments\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Infrastructure/PaymentsModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Infrastructure\n{\n    public class PaymentsModule : IPaymentsModule\n    {\n        public async Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command)\n        {\n            return await CommandsExecutor.Execute(command);\n        }\n\n        public async Task ExecuteCommandAsync(ICommand command)\n        {\n            await CommandsExecutor.Execute(command);\n        }\n\n        public async Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)\n        {\n            using (var scope = PaymentsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n\n                return await mediator.Send(query);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/IntegrationEvents/CompanyName.MyMeetings.Modules.Payments.IntegrationEvents.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Payments/IntegrationEvents/MeetingFeePaidIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationEvents\n{\n    public class MeetingFeePaidIntegrationEvent : IntegrationEvent\n    {\n        public MeetingFeePaidIntegrationEvent(\n            Guid id,\n            DateTime occurredOn,\n            Guid payerId,\n            Guid meetingId)\n            : base(id, occurredOn)\n        {\n            PayerId = payerId;\n            MeetingId = meetingId;\n        }\n\n        public Guid PayerId { get; }\n\n        public Guid MeetingId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/IntegrationEvents/SubscriptionExpirationDateChangedIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationEvents\n{\n    public class SubscriptionExpirationDateChangedIntegrationEvent : IntegrationEvent\n    {\n        public SubscriptionExpirationDateChangedIntegrationEvent(\n            Guid id,\n            DateTime occurredOn,\n            Guid payerId,\n            DateTime expirationDate)\n            : base(id, occurredOn)\n        {\n            PayerId = payerId;\n            ExpirationDate = expirationDate;\n        }\n\n        public Guid PayerId { get; }\n\n        public DateTime ExpirationDate { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/ArchTests/Application/ApplicationTests.cs",
    "content": "using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.ArchTests.SeedWork;\nusing FluentValidation;\nusing MediatR;\nusing NetArchTest.Rules;\nusing Newtonsoft.Json;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.ArchTests.Application\n{\n    [TestFixture]\n    public class ApplicationTests : TestBase\n    {\n        [Test]\n        public void Command_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(CommandBase))\n                .Or()\n                .Inherit(typeof(CommandBase<>))\n                .Or()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .Or()\n                .ImplementInterface(typeof(ICommand))\n                .Or()\n                .ImplementInterface(typeof(ICommand<>))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Query_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(typeof(IQuery<>)).GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void CommandHandler_Should_Have_Name_EndingWith_CommandHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(ICommandHandler<>))\n                    .Or()\n                .ImplementInterface(typeof(ICommandHandler<,>))\n                .And()\n                .DoNotHaveNameMatching(\".*Decorator.*\").Should()\n                .HaveNameEndingWith(\"CommandHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void QueryHandler_Should_Have_Name_EndingWith_QueryHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(IQueryHandler<,>))\n                .Should()\n                .HaveNameEndingWith(\"QueryHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Command_And_Query_Handlers_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                    .ImplementInterface(typeof(IQueryHandler<,>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<,>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void Validator_Should_Have_Name_EndingWith_Validator()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should()\n                .HaveNameEndingWith(\"Validator\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Validators_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void InternalCommand_Should_Have_JsonConstructorAttribute()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n\n            foreach (var type in types)\n            {\n                bool hasJsonConstructorDefined = false;\n                var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var jsonConstructorAttribute = constructorInfo.GetCustomAttributes(typeof(JsonConstructorAttribute), false);\n                    if (jsonConstructorAttribute.Length > 0)\n                    {\n                        hasJsonConstructorDefined = true;\n                        break;\n                    }\n                }\n\n                if (!hasJsonConstructorDefined)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void MediatR_RequestHandler_Should_NotBe_Used_Directly()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().DoNotHaveName(\"ICommandHandler`1\")\n                .Should().ImplementInterface(typeof(IRequestHandler<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                bool isCommandHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));\n                bool isCommandWithResultHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<,>));\n                bool isQueryHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(IQueryHandler<,>));\n                if (!isCommandHandler && !isCommandWithResultHandler && !isQueryHandler)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Command_With_Result_Should_Not_Return_Unit()\n        {\n            Type commandWithResultHandlerType = typeof(ICommandHandler<,>);\n            IEnumerable<Type> types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(commandWithResultHandlerType)\n                .GetTypes().ToList();\n\n            List<Type> failingTypes = [];\n            foreach (Type type in types)\n            {\n                Type interfaceType = type.GetInterface(commandWithResultHandlerType.Name);\n                if (interfaceType?.GenericTypeArguments[1] == typeof(Unit))\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/ArchTests/CompanyName.MyMeetings.Modules.Payments.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Payments/Tests/ArchTests/Domain/DomainTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.ArchTests.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.ArchTests.Domain\n{\n    public class DomainTests : TestBase\n    {\n        [Test]\n        public void DomainEvent_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                    .Inherit(typeof(DomainEventBase))\n                        .Or()\n                    .ImplementInterface(typeof(IDomainEvent))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void ValueObject_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Entity_Which_Is_Not_Aggregate_Root_Cannot_Have_Public_Members()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity))\n                .And().DoNotImplementInterface(typeof(IAggregateRoot)).GetTypes();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.Public |\n                                              BindingFlags.Instance |\n                                              BindingFlags.Static;\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                var publicFields = type.GetFields(bindingFlags);\n                var publicProperties = type.GetProperties(bindingFlags);\n                var publicMethods = type.GetMethods(bindingFlags);\n\n                if (publicFields.Any() || publicProperties.Any() || publicMethods.Any())\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Cannot_Have_Reference_To_Other_AggregateRoot()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            var aggregateRoots = Types.InAssembly(DomainAssembly)\n                .That().ImplementInterface(typeof(IAggregateRoot)).GetTypes().ToList();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.NonPublic |\n                                              BindingFlags.Instance;\n\n            List<Type> failingTypes = [];\n            foreach (var type in entityTypes)\n            {\n                var fields = type.GetFields(bindingFlags);\n\n                foreach (var field in fields)\n                {\n                    if (aggregateRoots.Contains(field.FieldType) ||\n                        field.FieldType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n\n                var properties = type.GetProperties(bindingFlags);\n                foreach (var property in properties)\n                {\n                    if (aggregateRoots.Contains(property.PropertyType) ||\n                        property.PropertyType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Should_Have_Parameterless_Private_Constructor()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in entityTypes)\n            {\n                bool hasPrivateParameterlessConstructor = false;\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (constructorInfo.IsPrivate && constructorInfo.GetParameters().Length == 0)\n                    {\n                        hasPrivateParameterlessConstructor = true;\n                    }\n                }\n\n                if (!hasPrivateParameterlessConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Domain_Object_Should_Have_Only_Private_Constructors()\n        {\n            var domainObjectTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                        .Inherit(typeof(Entity))\n                    .Or()\n                        .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var domainObjectType in domainObjectTypes)\n            {\n                var constructors = domainObjectType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (!constructorInfo.IsPrivate)\n                    {\n                        failingTypes.Add(domainObjectType);\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void ValueObject_Should_Have_Private_Constructor_With_Parameters_For_His_State()\n        {\n            List<Type> excludedFromCheck = [typeof(PriceList)];\n\n            var valueObjects = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes()\n                .Where(x => !excludedFromCheck.Contains(x))\n                .ToList();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in valueObjects)\n            {\n                bool hasExpectedConstructor = false;\n\n                const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                                  BindingFlags.Public |\n                                                  BindingFlags.Instance;\n                var names = entityType.GetFields(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                var propertyNames = entityType.GetProperties(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                names.AddRange(propertyNames);\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var parameters = constructorInfo.GetParameters().Select(x => x.Name.ToLower()).ToList();\n\n                    if (names.Intersect(parameters).Count() == names.Count)\n                    {\n                        hasExpectedConstructor = true;\n                        break;\n                    }\n                }\n\n                if (!hasExpectedConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void DomainEvent_Should_Have_DomainEventPostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(DomainEventBase))\n                .Or()\n                .ImplementInterface(typeof(IDomainEvent))\n                .Should().HaveNameEndingWith(\"DomainEvent\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void BusinessRule_Should_Have_RulePostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .ImplementInterface(typeof(IBusinessRule))\n                .Should().HaveNameEndingWith(\"Rule\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/ArchTests/Module/LayersTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.ArchTests.Module\n{\n    [TestFixture]\n    public class LayersTests : TestBase\n    {\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToApplicationLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void ApplicationLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .Should()\n                .NotHaveDependencyOn(InfrastructureAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApplicationAssembly => typeof(CommandBase).Assembly;\n\n        protected static Assembly DomainAssembly => typeof(Subscription).Assembly;\n\n        protected static Assembly InfrastructureAssembly => typeof(PaymentsStartup).Assembly;\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/CompanyName.MyMeetings.Modules.Payments.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/MeetingFees/MeetingFeesTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFee;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.CreateMeetingFeePayment;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.GetMeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.Application.MeetingFees.MarkMeetingFeePaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFeePayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.MeetingFees\n{\n    [NonParallelizable]\n    [TestFixture]\n    public class MeetingFeesTests : TestBase\n    {\n        [Test]\n        public async Task Create_Then_Pay_MeetingFee_Test()\n        {\n            var payerId = Guid.NewGuid();\n            var meetingId = Guid.NewGuid();\n\n            var meetingFeeId = await PaymentsModule.ExecuteCommandAsync(new CreateMeetingFeeCommand(\n                Guid.NewGuid(),\n                payerId,\n                meetingId,\n                100,\n                \"PLN\"));\n\n            var meetingFees = await GetEventually(new GetMeetingFeesProbe(PaymentsModule, meetingId, x => x != null && x.Count > 0), 5000);\n\n            Assert.That(meetingFees[0].Status, Is.EqualTo(MeetingFeeStatus.WaitingForPayment.Code));\n\n            var meetingFeePaymentId = await PaymentsModule.ExecuteCommandAsync(new CreateMeetingFeePaymentCommand(meetingFeeId));\n\n            await PaymentsModule.ExecuteCommandAsync(new MarkMeetingFeePaymentAsPaidCommand(meetingFeePaymentId));\n\n            meetingFees = await GetEventually(new GetMeetingFeesProbe(PaymentsModule, meetingId, x => x.Any(y => y.Status == MeetingFeePaymentStatus.Paid.Code)), 10000);\n\n            Assert.That(meetingFees[0].Status, Is.EqualTo(MeetingFeeStatus.Paid.Code));\n        }\n\n        private class GetMeetingFeesProbe : IProbe<List<MeetingFeeDto>>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Guid _meetingId;\n\n            private readonly Func<List<MeetingFeeDto>, bool> _condition;\n\n            public GetMeetingFeesProbe(\n                IPaymentsModule paymentsModule,\n                Guid meetingId,\n                Func<List<MeetingFeeDto>, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n                _meetingId = meetingId;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(List<MeetingFeeDto> sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<List<MeetingFeeDto>> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetMeetingFeesQuery(_meetingId));\n            }\n\n            public string DescribeFailureTo()\n            {\n                return $\"Cannot get meeting fees for MeetingId: {_meetingId}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Payers/PayerSampleData.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Payers\n{\n    public struct PayerSampleData\n    {\n        public static Guid Id => Guid.Parse(\"ed2991be-a8d2-4b09-9c1f-0d76e27b96ef\");\n\n        public static string Login => \"jdoe\";\n\n        public static string Email => \"johndoe@mail.com\";\n\n        public static string FirstName => \"John\";\n\n        public static string LastName => \"Doe\";\n\n        public static string Name => \"John Doe\";\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Payers/PayerTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Payers.CreatePayer;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Payers.GetPayer;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Payers\n{\n    [NonParallelizable]\n    [TestFixture]\n    public class PayerTests : TestBase\n    {\n        [Test]\n        public async Task CreatePayer_Test()\n        {\n            var payerId = await PaymentsModule.ExecuteCommandAsync(\n                new CreatePayerCommand(\n                    Guid.NewGuid(),\n                    PayerSampleData.Id,\n                    PayerSampleData.Login,\n                    PayerSampleData.Email,\n                    PayerSampleData.FirstName,\n                    PayerSampleData.LastName,\n                    PayerSampleData.Name));\n\n            var payer = await GetEventually(\n                new GetPayerProbe(PaymentsModule, payerId),\n                5000);\n\n            Assert.That(payer.Id, Is.EqualTo(PayerSampleData.Id));\n            Assert.That(payer.Login, Is.EqualTo(PayerSampleData.Login));\n            Assert.That(payer.Name, Is.EqualTo(PayerSampleData.Name));\n            Assert.That(payer.FirstName, Is.EqualTo(PayerSampleData.FirstName));\n            Assert.That(payer.LastName, Is.EqualTo(PayerSampleData.LastName));\n            Assert.That(payer.Email, Is.EqualTo(PayerSampleData.Email));\n        }\n\n        private class GetPayerProbe : IProbe<PayerDto>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Guid _payerId;\n\n            public GetPayerProbe(\n                IPaymentsModule paymentsModule,\n                Guid payerId)\n            {\n                _paymentsModule = paymentsModule;\n\n                _payerId = payerId;\n            }\n\n            public bool IsSatisfied(PayerDto sample)\n            {\n                return sample != null;\n            }\n\n            public async Task<PayerDto> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetPayerQuery(_payerId));\n            }\n\n            public string DescribeFailureTo()\n            {\n                return $\"Cannot get payer for PayerId: {_payerId}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/PriceList/PriceListHelper.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.CreatePriceListItem;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.PriceList\n{\n    public static class PriceListHelper\n    {\n        public static async Task AddPriceListItems(IPaymentsModule paymentsModule)\n        {\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.Month.Code,\n                PriceListItemCategory.New.Code,\n                \"PL\",\n                60,\n                \"PLN\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.New.Code,\n                \"PL\",\n                320,\n                \"PLN\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.Month.Code,\n                PriceListItemCategory.New.Code,\n                \"US\",\n                15,\n                \"USD\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.New.Code,\n                \"US\",\n                80,\n                \"USD\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.Renewal.Code,\n                \"PL\",\n                320,\n                \"PLN\"));\n\n            await TestBase.GetEventually(new GetPriceListProbe(paymentsModule, x => x.Count == 5), 5000);\n        }\n\n        private class GetPriceListProbe : IProbe<List<PriceListItemDto>>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Func<List<PriceListItemDto>, bool> _condition;\n\n            public GetPriceListProbe(\n                IPaymentsModule paymentsModule,\n                Func<List<PriceListItemDto>, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(List<PriceListItemDto> sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<List<PriceListItemDto>> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetPriceListItemsQuery());\n            }\n\n            public string DescribeFailureTo()\n            {\n                return \"Cannot get price list for specified condition\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/SeedWork/EventsBusMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork\n{\n    public class EventsBusMock : IEventsBus\n    {\n        private readonly IList<IntegrationEvent> _publishedEvents;\n\n        public EventsBusMock()\n        {\n            _publishedEvents = new List<IntegrationEvent>();\n        }\n\n        public void Dispose()\n        {\n        }\n\n        public Task Publish<T>(T @event)\n            where T : IntegrationEvent\n        {\n            _publishedEvents.Add(@event);\n            return Task.CompletedTask;\n        }\n\n        public T GetLastPublishedEvent<T>()\n            where T : IntegrationEvent\n        {\n            return _publishedEvents.OfType<T>().Last();\n        }\n\n        public void Subscribe<T>(IIntegrationEventHandler<T> handler)\n            where T : IntegrationEvent\n        {\n        }\n\n        public void StartConsuming()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/SeedWork/OutboxMessagesHelper.cs",
    "content": "using System.Data;\nusing System.Reflection;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.CreateSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration.Processing.Outbox;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork\n{\n    public class OutboxMessagesHelper\n    {\n        public static async Task<List<OutboxMessageDto>> GetOutboxMessages(IDbConnection connection)\n        {\n            const string sql = \"\"\"\n                               SELECT\n                                   [OutboxMessage].[Id], \n                                   [OutboxMessage].[Type],\n                                   [OutboxMessage].[Data] \n                               FROM [payments].[OutboxMessages] AS [OutboxMessage] \n                               ORDER BY [OutboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            return messages.AsList();\n        }\n\n        public static T Deserialize<T>(OutboxMessageDto message)\n            where T : class, INotification\n        {\n            Type type = Assembly.GetAssembly(typeof(SubscriptionCreatedNotification)).GetType(message.Type);\n            return JsonConvert.DeserializeObject(message.Data, type) as T;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing Dapper;\nusing MediatR;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IPaymentsModule PaymentsModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        protected EmailsConfiguration EmailsConfiguration { get; private set; }\n\n        protected EventsBusMock EventsBus { get; private set; }\n\n        protected ExecutionContextMock ExecutionContext { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = new LoggerConfiguration()\n                .Enrich.FromLogContext()\n                .WriteTo.Console(\n                    outputTemplate:\n                    \"[{Timestamp:HH:mm:ss} {Level:u3}] [{Module}] [{Context}] {Message:lj}{NewLine}{Exception}\")\n                .CreateLogger();\n            EmailSender = Substitute.For<IEmailSender>();\n            EmailsConfiguration = new EmailsConfiguration(\"from@email.com\");\n            EventsBus = new EventsBusMock();\n            ExecutionContext = new ExecutionContextMock(Guid.NewGuid());\n\n            PaymentsStartup.Initialize(\n                ConnectionString,\n                ExecutionContext,\n                Logger,\n                EmailsConfiguration,\n                EventsBus,\n                true);\n\n            PaymentsModule = new PaymentsModule();\n        }\n\n        public static async Task<T> GetEventually<T>(IProbe<T> probe, int timeout)\n            where T : class\n        {\n            var poller = new Poller(timeout);\n\n            return await poller.GetAsync(probe);\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            PaymentsStartup.Stop();\n            SystemClock.Reset();\n        }\n\n        protected async Task<T> GetLastOutboxMessage<T>()\n            where T : class, INotification\n        {\n            using (var connection = new SqlConnection(ConnectionString))\n            {\n                var messages = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n                return OutboxMessagesHelper.Deserialize<T>(messages.Last());\n            }\n        }\n\n        protected static async Task AssertEventually(IProbe probe, int timeout)\n        {\n            await new Poller(timeout).CheckAsync(probe);\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [payments].[InboxMessages] \" +\n                               \"DELETE FROM [payments].[InternalCommands] \" +\n                               \"DELETE FROM [payments].[OutboxMessages] \" +\n                               \"DELETE FROM payments.Messages \" +\n                               \"DBCC CHECKIDENT ('payments.Messages', RESEED, 0); \" +\n                               \"DELETE FROM payments.Streams \" +\n                               \"DBCC CHECKIDENT ('payments.Streams', RESEED, 0); \" +\n                               \"DELETE FROM payments.SubscriptionDetails \" +\n                               \"DELETE FROM [payments].[SubscriptionCheckpoints] \" +\n                               \"DELETE FROM [payments].PriceListItems \" +\n                               \"DELETE FROM [payments].SubscriptionPayments \" +\n                               \"DELETE FROM [payments].MeetingFees \" +\n                               \"DELETE FROM [payments].[Payers] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Subscriptions/BuySubscriptionTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetPayerSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.PriceList;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Subscriptions\n{\n    [TestFixture]\n    public class BuySubscriptionTests : TestBase\n    {\n        [Test]\n        public async Task BuySubscription_Test()\n        {\n            await PriceListHelper.AddPriceListItems(PaymentsModule);\n\n            var subscriptionPaymentId = await PaymentsModule.ExecuteCommandAsync(\n                new BuySubscriptionCommand(\n                    SubscriptionPeriod.Month.Code,\n                    \"PL\",\n                    60,\n                    \"PLN\"));\n\n            var subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => true),\n                10000);\n\n            var subscriptionPayment = subscriptionPayments.Single(x => x.PaymentId == subscriptionPaymentId);\n\n            Assert.That(subscriptionPayment.Status, Is.EqualTo(SubscriptionPaymentStatus.WaitingForPayment.Code));\n\n            await PaymentsModule.ExecuteCommandAsync(\n                new MarkSubscriptionPaymentAsPaidCommand(subscriptionPaymentId));\n\n            var subscription = await GetEventually(\n                new GetPayerSubscriptionProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId),\n                10000);\n\n            Assert.That(subscription.Period, Is.EqualTo(SubscriptionPeriod.Month.Code));\n            Assert.That(subscription.Status, Is.EqualTo(SubscriptionStatus.Active.Code));\n        }\n\n        private class GetPayerSubscriptionProbe : IProbe<SubscriptionDetailsDto>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            public GetPayerSubscriptionProbe(\n                IPaymentsModule paymentsModule,\n                Guid payerId)\n            {\n                _paymentsModule = paymentsModule;\n            }\n\n            public bool IsSatisfied(SubscriptionDetailsDto sample)\n            {\n                return sample != null;\n            }\n\n            public async Task<SubscriptionDetailsDto> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetAuthenticatedPayerSubscriptionQuery());\n            }\n\n            public string DescribeFailureTo() => \"Subscription read model is not in expected state\";\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Subscriptions/GetSubscriptionPaymentsProbe.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Subscriptions\n{\n    internal class GetSubscriptionPaymentsProbe : IProbe<List<SubscriptionPaymentDto>>\n    {\n        private readonly IPaymentsModule _paymentsModule;\n\n        private readonly Guid _payerId;\n\n        private readonly Func<List<SubscriptionPaymentDto>, bool> _condition;\n\n        public GetSubscriptionPaymentsProbe(\n            IPaymentsModule paymentsModule,\n            Guid payerId,\n            Func<List<SubscriptionPaymentDto>, bool> condition)\n        {\n            _paymentsModule = paymentsModule;\n\n            _payerId = payerId;\n            _condition = condition;\n        }\n\n        public bool IsSatisfied(List<SubscriptionPaymentDto> sample)\n        {\n            return sample != null && _condition(sample);\n        }\n\n        public async Task<List<SubscriptionPaymentDto>> GetSampleAsync()\n        {\n            return await _paymentsModule.ExecuteQueryAsync(new GetSubscriptionPaymentsQuery(_payerId));\n        }\n\n        public string DescribeFailureTo()\n        {\n            return $\"Cannot get subscription payments for PayerId: {_payerId}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Subscriptions/SubscriptionLifecycleTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscriptionRenewal;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionRenewalPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.PriceList;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Subscriptions\n{\n    [NonParallelizable]\n    [TestFixture]\n    [Ignore(\"Sometimes fails, to check why\")]\n    public class SubscriptionLifecycleTests : TestBase\n    {\n        [Test]\n        public async Task Subscription_Buy_ThenRenew_ThenExpire_Test()\n        {\n            await PriceListHelper.AddPriceListItems(PaymentsModule);\n\n            DateTime referenceDate = new DateTime(2020, 6, 15);\n            SystemClock.Set(referenceDate);\n\n            var subscriptionPaymentId = await PaymentsModule.ExecuteCommandAsync(\n                new BuySubscriptionCommand(\n                    \"Month\",\n                    \"PL\",\n                    60,\n                    \"PLN\"));\n\n            var subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => true),\n                10000);\n\n            var subscriptionPayment = subscriptionPayments.Single(x => x.PaymentId == subscriptionPaymentId);\n\n            Assert.That(subscriptionPayment.Status, Is.EqualTo(SubscriptionPaymentStatus.WaitingForPayment.Code));\n\n            await PaymentsModule.ExecuteCommandAsync(\n                new MarkSubscriptionPaymentAsPaidCommand(subscriptionPaymentId));\n\n            subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => x.Any(y => y.Status == SubscriptionPaymentStatus.Paid.Code &&\n                                    y.SubscriptionId.HasValue)),\n                10000);\n\n            subscriptionPayment = subscriptionPayments.Single(x => x.PaymentId == subscriptionPaymentId);\n\n            var subscriptionId = subscriptionPayment.SubscriptionId.GetValueOrDefault();\n\n            var subscription = await GetEventually(\n                new GetSubscriptionDetailsProbe(\n                    PaymentsModule,\n                    subscriptionId,\n                    x => x.SubscriptionId == subscriptionId &&\n                         x.Status == SubscriptionStatus.Active.Code &&\n                         x.Period == SubscriptionPeriod.Month.Code),\n                5000);\n\n            Assert.That(subscriptionPayments[0].Status, Is.EqualTo(SubscriptionPaymentStatus.Paid.Code));\n            Assert.That(subscription.ExpirationDate, Is.EqualTo(referenceDate.AddMonths(1)));\n\n            var subscriptionRenewalPaymentId = await PaymentsModule.ExecuteCommandAsync(\n                new BuySubscriptionRenewalCommand(\n                    subscriptionId,\n                    \"HalfYear\",\n                    \"PL\",\n                    320,\n                    \"PLN\"));\n\n            subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => true),\n                10000);\n\n            var renewalPayment = subscriptionPayments\n                .Single(x => x.PaymentId == subscriptionRenewalPaymentId);\n\n            Assert.That(renewalPayment.Status, Is.EqualTo(SubscriptionRenewalPaymentStatus.WaitingForPayment.Code));\n\n            await PaymentsModule.ExecuteCommandAsync(\n                new MarkSubscriptionRenewalPaymentAsPaidCommand(subscriptionRenewalPaymentId));\n\n            subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => x.Any(y => y.PaymentId == subscriptionRenewalPaymentId)),\n                10000);\n\n            renewalPayment = subscriptionPayments\n                .Single(x => x.PaymentId == subscriptionRenewalPaymentId);\n\n            subscription = await GetEventually(\n                new GetSubscriptionDetailsProbe(\n                    PaymentsModule,\n                    subscriptionId,\n                    x => x.SubscriptionId == subscriptionId &&\n                         x.Period == SubscriptionPeriod.GetName(SubscriptionPeriod.HalfYear.Code) &&\n                         x.Status == SubscriptionStatus.Active.Code),\n                5000);\n\n            Assert.That(renewalPayment.Status, Is.EqualTo(SubscriptionRenewalPaymentStatus.Paid.Code));\n            Assert.That(subscription.ExpirationDate, Is.EqualTo(referenceDate.AddMonths(7)));\n\n            SystemClock.Set(referenceDate.AddMonths(7).AddDays(1));\n\n            await PaymentsModule.ExecuteCommandAsync(new ExpireSubscriptionsCommand());\n\n            subscription = await GetEventually(\n                new GetSubscriptionDetailsProbe(\n                    PaymentsModule,\n                    subscriptionId,\n                    x => x.SubscriptionId == subscriptionId && x.Status == SubscriptionStatus.Expired.Code),\n                10000);\n            Assert.That(subscription, Is.Not.Null);\n        }\n\n        private class GetSubscriptionDetailsProbe : IProbe<SubscriptionDetailsDto>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Guid _subscriptionId;\n\n            private readonly Func<SubscriptionDetailsDto, bool> _condition;\n\n            public GetSubscriptionDetailsProbe(\n                IPaymentsModule paymentsModule,\n                Guid subscriptionId,\n                Func<SubscriptionDetailsDto, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n                _subscriptionId = subscriptionId;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(SubscriptionDetailsDto sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<SubscriptionDetailsDto> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetSubscriptionDetailsQuery(_subscriptionId));\n            }\n\n            public string DescribeFailureTo() => \"Subscription read model is not in expected state\";\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/IntegrationTests/Subscriptions/SubscriptionPaymentsTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.ExpireSubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.PriceList;\nusing CompanyName.MyMeetings.Modules.Payments.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.IntegrationTests.Subscriptions\n{\n    [NonParallelizable]\n    [TestFixture]\n    public class SubscriptionPaymentsTests : TestBase\n    {\n        [Test]\n        public async Task SubscriptionPayment_Expiration_Test()\n        {\n            SystemClock.Set(new DateTime(2020, 6, 15, 10, 0, 0));\n\n            await PriceListHelper.AddPriceListItems(PaymentsModule);\n\n            await PaymentsModule.ExecuteCommandAsync(\n                new BuySubscriptionCommand(\n                \"Month\",\n                \"PL\",\n                60,\n                \"PLN\"));\n\n            var subscriptionPayments = await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => true),\n                10000);\n\n            Assert.That(subscriptionPayments[0].Status, Is.EqualTo(SubscriptionPaymentStatus.WaitingForPayment.Code));\n\n            SystemClock.Set(new DateTime(2020, 6, 15, 10, 21, 0));\n\n            await PaymentsModule.ExecuteCommandAsync(\n                new ExpireSubscriptionPaymentsCommand());\n\n            await GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    PaymentsModule,\n                    ExecutionContext.UserId,\n                    x => x.Any(y => y.Status == SubscriptionPaymentStatus.Expired.Code)),\n                10000);\n        }\n\n        private class GetSubscriptionPaymentsProbe : IProbe<List<SubscriptionPaymentDto>>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Guid _payerId;\n\n            private readonly Func<List<SubscriptionPaymentDto>, bool> _condition;\n\n            public GetSubscriptionPaymentsProbe(\n                IPaymentsModule paymentsModule,\n                Guid payerId,\n                Func<List<SubscriptionPaymentDto>, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n\n                _payerId = payerId;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(List<SubscriptionPaymentDto> sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<List<SubscriptionPaymentDto>> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetSubscriptionPaymentsQuery(_payerId));\n            }\n\n            public string DescribeFailureTo()\n            {\n                return $\"Cannot get subscription payments for PayerId: {_payerId}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/Payers/PayerTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Payers.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.Payers\n{\n    [TestFixture]\n    public class PayerTests : TestBase\n    {\n        [Test]\n        public void CreatePayer_IsSuccessful()\n        {\n            var payerId = Guid.NewGuid();\n            var payer = Payer.Create(\n                payerId,\n                \"payerLogin\",\n                \"payerEmail@mail.com\",\n                \"John\",\n                \"Doe\",\n                \"John Doe\");\n\n            var payerCreated = AssertPublishedDomainEvent<PayerCreatedDomainEvent>(payer);\n\n            Assert.That(payerCreated.PayerId, Is.EqualTo(payerId));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/PriceListItems/PriceListItemTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.PriceListItems\n{\n    [TestFixture]\n    public class PriceListItemTests : TestBase\n    {\n        [Test]\n        public void CreatePriceListItem_IsSuccessful()\n        {\n            // Act\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n\n            // Assert\n            var priceListItemCreated = AssertPublishedDomainEvent<PriceListItemCreatedDomainEvent>(priceListItem);\n\n            Assert.That(priceListItemCreated.PriceListItemId, Is.EqualTo(priceListItem.Id));\n        }\n\n        [Test]\n        public void ActivatePriceListItem_IsSuccessful()\n        {\n            // Arrange\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n            priceListItem.Deactivate();\n\n            // Act\n            priceListItem.Activate();\n\n            // Assert\n            var priceListItemActivated = AssertPublishedDomainEvent<PriceListItemActivatedDomainEvent>(priceListItem);\n\n            Assert.That(priceListItemActivated.PriceListItemId, Is.EqualTo(priceListItem.Id));\n        }\n\n        [Test]\n        public void ActivatePriceListItem_WhenItemIsActive_ThenActivationIgnored()\n        {\n            // Arrange\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n\n            // Act\n            priceListItem.Activate();\n\n            // Assert\n            AssertDomainEventNotPublished<PriceListItemActivatedDomainEvent>(priceListItem);\n        }\n\n        [Test]\n        public void DeactivatePriceListItem_IsSuccessful()\n        {\n            // Arrange\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n\n            // Act\n            priceListItem.Deactivate();\n\n            // Assert\n            var priceListItemActivated = AssertPublishedDomainEvent<PriceListItemDeactivatedDomainEvent>(priceListItem);\n\n            Assert.That(priceListItemActivated.PriceListItemId, Is.EqualTo(priceListItem.Id));\n        }\n\n        [Test]\n        public void DeactivatePriceListItem_WhenItemNotActive_ThenDeactivationIgnored()\n        {\n            // Arrange\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n            priceListItem.Deactivate();\n\n            // Act\n            priceListItem.Deactivate();\n\n            // Assert\n            var priceListItemActivatedEvents = AssertPublishedDomainEvents<PriceListItemDeactivatedDomainEvent>(priceListItem);\n\n            Assert.That(priceListItemActivatedEvents.Count, Is.EqualTo(1));\n        }\n\n        [Test]\n        public void ChangePriceListItem_IsSuccessful()\n        {\n            // Arrange\n            var priceListItem = PriceListItem.Create(\n                \"BRA\",\n                SubscriptionPeriod.Month,\n                PriceListItemCategory.New,\n                MoneyValue.Of(50, \"BRL\"));\n\n            // Act\n            priceListItem.ChangeAttributes(\n                \"ARG\",\n                SubscriptionPeriod.HalfYear,\n                PriceListItemCategory.Renewal,\n                MoneyValue.Of(25, \"ARS\"));\n\n            // Assert\n            var priceListItemAttributesChangedEvent = AssertPublishedDomainEvent<PriceListItemAttributesChangedDomainEvent>(priceListItem);\n\n            Assert.That(priceListItemAttributesChangedEvent.PriceListItemId, Is.EqualTo(priceListItem.Id));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SeedWork/DomainEventsTestHelper.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork\n{\n    public class DomainEventsTestHelper\n    {\n        public static List<IDomainEvent> GetAllDomainEvents(Entity aggregate)\n        {\n            List<IDomainEvent> domainEvents = [];\n\n            if (aggregate.DomainEvents != null)\n            {\n                domainEvents.AddRange(aggregate.DomainEvents);\n            }\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = typeof(Entity).IsAssignableFrom(field.FieldType);\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    domainEvents.AddRange(GetAllDomainEvents(entity).ToList());\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                domainEvents.AddRange(GetAllDomainEvents(entityItem));\n                            }\n                        }\n                    }\n                }\n            }\n\n            return domainEvents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SeedWork/TestBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        public static T AssertPublishedDomainEvent<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static T AssertPublishedDomainEvent<T>(AggregateRoot aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = aggregate.GetDomainEvents().OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static void AssertDomainEventNotPublished<T>(AggregateRoot aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = aggregate.GetDomainEvents().OfType<T>().SingleOrDefault();\n            Assert.That(domainEvent, Is.Null);\n        }\n\n        public static List<T> AssertPublishedDomainEvents<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvents = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().ToList();\n\n            if (!domainEvents.Any())\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvents;\n        }\n\n        public static List<T> AssertPublishedDomainEvents<T>(AggregateRoot aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvents = aggregate.GetDomainEvents().OfType<T>().ToList();\n\n            if (!domainEvents.Any())\n            {\n                throw new Exception($\"{typeof(T).Name} event was not published\");\n            }\n\n            return domainEvents;\n        }\n\n        public static void AssertBrokenRule<TRule>(TestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.Catch<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            SystemClock.Reset();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SubscriptionPayments/SubscriptionPaymentTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments.Rules;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SubscriptionPayments\n{\n    [TestFixture]\n    public class SubscriptionPaymentTests : SubscriptionPaymentTestsBase\n    {\n        [Test]\n        public void BuySubscription_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionPaymentTestData = CreateSubscriptionPaymentTestData();\n\n            // Act\n            var subscriptionPayment = SubscriptionPayment.Buy(\n                subscriptionPaymentTestData.PayerId,\n                SubscriptionPeriod.Month,\n                \"PL\",\n                MoneyValue.Of(60, \"PLN\"),\n                subscriptionPaymentTestData.PriceList);\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionPaymentCreatedDomainEvent>(subscriptionPayment);\n        }\n\n        [Test]\n        public void BuySubscriptionRenewal_WhenPriceDoesNotExist_IsNotPossible()\n        {\n            // Arrange\n            var subscriptionPaymentTestData = CreateSubscriptionPaymentTestData();\n\n            // Act & Assert\n            AssertBrokenRule<PriceOfferMustMatchPriceInPriceListRule>(() =>\n            {\n                SubscriptionPayment.Buy(\n                    subscriptionPaymentTestData.PayerId,\n                    SubscriptionPeriod.Month,\n                    \"PL\",\n                    MoneyValue.Of(50, \"PLN\"),\n                    subscriptionPaymentTestData.PriceList);\n            });\n        }\n\n        [Test]\n        public void PaySubscription_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionPaymentTestData = CreateSubscriptionPaymentTestData();\n\n            var subscriptionPayment = SubscriptionPayment.Buy(\n                subscriptionPaymentTestData.PayerId,\n                SubscriptionPeriod.Month,\n                \"PL\",\n                MoneyValue.Of(60, \"PLN\"),\n                subscriptionPaymentTestData.PriceList);\n\n            // Act\n            subscriptionPayment.MarkAsPaid();\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionPaymentPaidDomainEvent>(subscriptionPayment);\n        }\n\n        [Test]\n        public void ExpireSubscription_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionPaymentTestData = CreateSubscriptionPaymentTestData();\n\n            var subscriptionPayment = SubscriptionPayment.Buy(\n                subscriptionPaymentTestData.PayerId,\n                SubscriptionPeriod.Month,\n                \"PL\",\n                MoneyValue.Of(60, \"PLN\"),\n                subscriptionPaymentTestData.PriceList);\n\n            // Act\n            subscriptionPayment.Expire();\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionPaymentExpiredDomainEvent>(subscriptionPayment);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SubscriptionPayments/SubscriptionPaymentTestsBase.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SubscriptionPayments\n{\n    public class SubscriptionPaymentTestsBase : TestBase\n    {\n        protected class SubscriptionPaymentTestData\n        {\n            public SubscriptionPaymentTestData(PriceList priceList, PayerId payerId, SubscriptionId subscriptionId)\n            {\n                PriceList = priceList;\n                PayerId = payerId;\n                SubscriptionId = subscriptionId;\n            }\n\n            internal PriceList PriceList { get; }\n\n            internal PayerId PayerId { get; }\n\n            internal SubscriptionId SubscriptionId { get; }\n        }\n\n        protected SubscriptionPaymentTestData CreateSubscriptionPaymentTestData()\n        {\n            var payerId = new PayerId(Guid.NewGuid());\n            var subscriptionId = new SubscriptionId(Guid.NewGuid());\n            var priceList = CreatePriceList();\n\n            var subscriptionPaymentTestData = new SubscriptionPaymentTestData(\n                priceList,\n                payerId,\n                subscriptionId);\n\n            return subscriptionPaymentTestData;\n        }\n\n        private PriceList CreatePriceList()\n        {\n            var priceListItem = new PriceListItemData(\n                \"PL\",\n                SubscriptionPeriod.Month,\n                MoneyValue.Of(60, \"PLN\"),\n                PriceListItemCategory.New);\n\n            List<PriceListItemData> priceListItems = [priceListItem];\n            var priceList = PriceList.Create(priceListItems, new DirectValueFromPriceListPricingStrategy(priceListItems));\n\n            return priceList;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SubscriptionRenewalPayments/SubscriptionRenewalPaymentTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments.Rules;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SubscriptionRenewalPayments\n{\n    [TestFixture]\n    public class SubscriptionRenewalPaymentTests : SubscriptionRenewalPaymentTestsBase\n    {\n        [Test]\n        public void BuySubscriptionRenewal_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionRenewalPaymentTestData = CreateSubscriptionRenewalPaymentTestData();\n\n            // Act\n            var subscriptionRenewalPayment = SubscriptionRenewalPayment.Buy(\n                subscriptionRenewalPaymentTestData.PayerId,\n                subscriptionRenewalPaymentTestData.SubscriptionId,\n                SubscriptionPeriod.Month,\n                \"PL\",\n                MoneyValue.Of(60, \"PLN\"),\n                subscriptionRenewalPaymentTestData.PriceList);\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionRenewalPaymentCreatedDomainEvent>(subscriptionRenewalPayment);\n        }\n\n        [Test]\n        public void BuySubscriptionRenewal_WhenPriceDoesNotExist_IsNotPossible()\n        {\n            // Arrange\n            var subscriptionRenewalPaymentTestData = CreateSubscriptionRenewalPaymentTestData();\n\n            // Act & Assert\n            AssertBrokenRule<PriceOfferMustMatchPriceInPriceListRule>(() =>\n            {\n                SubscriptionRenewalPayment.Buy(\n                    subscriptionRenewalPaymentTestData.PayerId,\n                    subscriptionRenewalPaymentTestData.SubscriptionId,\n                    SubscriptionPeriod.Month,\n                    \"PL\",\n                    MoneyValue.Of(50, \"PLN\"),\n                    subscriptionRenewalPaymentTestData.PriceList);\n            });\n        }\n\n        [Test]\n        public void PaySubscriptionRenewal_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionRenewalPaymentTestData = CreateSubscriptionRenewalPaymentTestData();\n\n            var subscriptionRenewalPayment = SubscriptionRenewalPayment.Buy(\n                subscriptionRenewalPaymentTestData.PayerId,\n                subscriptionRenewalPaymentTestData.SubscriptionId,\n                SubscriptionPeriod.Month,\n                \"PL\",\n                MoneyValue.Of(60, \"PLN\"),\n                subscriptionRenewalPaymentTestData.PriceList);\n\n            // Act\n            subscriptionRenewalPayment.MarkRenewalAsPaid();\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionRenewalPaymentPaidDomainEvent>(subscriptionRenewalPayment);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/SubscriptionRenewalPayments/SubscriptionRenewalPaymentTestsBase.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems.PricingStrategies;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SubscriptionRenewalPayments\n{\n    public class SubscriptionRenewalPaymentTestsBase : TestBase\n    {\n        protected class SubscriptionRenewalPaymentTestData\n        {\n            public SubscriptionRenewalPaymentTestData(PriceList priceList, PayerId payerId, SubscriptionId subscriptionId)\n            {\n                PriceList = priceList;\n                PayerId = payerId;\n                SubscriptionId = subscriptionId;\n            }\n\n            internal PriceList PriceList { get; }\n\n            internal PayerId PayerId { get; }\n\n            internal SubscriptionId SubscriptionId { get; }\n        }\n\n        protected SubscriptionRenewalPaymentTestData CreateSubscriptionRenewalPaymentTestData()\n        {\n            var payerId = new PayerId(Guid.NewGuid());\n            var subscriptionId = new SubscriptionId(Guid.NewGuid());\n            var priceList = CreatePriceList();\n\n            var subscriptionRenewalPaymentTestData = new SubscriptionRenewalPaymentTestData(\n                priceList,\n                payerId,\n                subscriptionId);\n\n            return subscriptionRenewalPaymentTestData;\n        }\n\n        private PriceList CreatePriceList()\n        {\n            var priceListItem = new PriceListItemData(\n                \"PL\",\n                SubscriptionPeriod.Month,\n                MoneyValue.Of(60, \"PLN\"),\n                PriceListItemCategory.Renewal);\n\n            List<PriceListItemData> priceListItems = [priceListItem];\n            var priceList = PriceList.Create(priceListItems, new DirectValueFromPriceListPricingStrategy(priceListItems));\n\n            return priceList;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/Subscriptions/SubscriptionDateExpirationCalculatorTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.Subscriptions\n{\n    [TestFixture]\n    public class SubscriptionDateExpirationCalculatorTests\n    {\n        [Test]\n        public void CalculateForNew_WhenPeriodMonthIsSelected_Test()\n        {\n            // Arrange\n            SubscriptionPeriod period = SubscriptionPeriod.Month;\n            SystemClock.Set(new DateTime(2020, 5, 11));\n\n            // Act\n            DateTime expirationDate = SubscriptionDateExpirationCalculator.CalculateForNew(period);\n\n            // Assert\n            Assert.That(expirationDate, Is.EqualTo(new DateTime(2020, 6, 11)));\n        }\n\n        [Test]\n        public void CalculateForNew_WhenPeriodHalfYearIsSelected_Test()\n        {\n            // Arrange\n            SubscriptionPeriod period = SubscriptionPeriod.HalfYear;\n            SystemClock.Set(new DateTime(2020, 5, 11));\n\n            // Act\n            DateTime expirationDate = SubscriptionDateExpirationCalculator.CalculateForNew(period);\n\n            // Assert\n            Assert.That(expirationDate, Is.EqualTo(new DateTime(2020, 11, 11)));\n        }\n\n        [Test]\n        public void CalculateForRenewal_WhenPeriodMonthIsSelected_AndExpireDateIsInTheFuture_ThenMonthsAreAddedToExpireDate()\n        {\n            // Arrange\n            SubscriptionPeriod period = SubscriptionPeriod.Month;\n            SystemClock.Set(new DateTime(2020, 5, 11));\n            DateTime expirationDate = new DateTime(2020, 7, 1);\n\n            // Act\n            expirationDate = SubscriptionDateExpirationCalculator.CalculateForRenewal(expirationDate, period);\n\n            // Assert\n            Assert.That(expirationDate, Is.EqualTo(new DateTime(2020, 8, 1)));\n        }\n\n        [Test]\n        public void CalculateForRenewal_WhenPeriodMonthIsSelected_AndExpireDatePassed_ThenMonthsAreAddedToNow()\n        {\n            // Arrange\n            SubscriptionPeriod period = SubscriptionPeriod.Month;\n            SystemClock.Set(new DateTime(2020, 5, 11));\n            DateTime expirationDate = new DateTime(2020, 4, 1);\n\n            // Act\n            expirationDate = SubscriptionDateExpirationCalculator.CalculateForRenewal(expirationDate, period);\n\n            // Assert\n            Assert.That(expirationDate, Is.EqualTo(new DateTime(2020, 6, 11)));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Payments/Tests/UnitTests/Subscriptions/SubscriptionTests.cs",
    "content": "using CompanyName.MyMeetings.Modules.Payments.Domain.Payers;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SeedWork;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.SubscriptionRenewalPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions.Events;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Payments.Domain.UnitTests.Subscriptions\n{\n    [TestFixture]\n    public class SubscriptionTests : TestBase\n    {\n        [Test]\n        public void CreateSubscription_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionPaymentSnapshot = new SubscriptionPaymentSnapshot(\n                new SubscriptionPaymentId(Guid.NewGuid()),\n                new PayerId(Guid.NewGuid()),\n                SubscriptionPeriod.Month,\n                \"PL\");\n\n            // Act\n            var subscription = Subscription.Create(subscriptionPaymentSnapshot);\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionCreatedDomainEvent>(subscription);\n        }\n\n        [Test]\n        public void RenewSubscription_IsSuccessful()\n        {\n            // Arrange\n            var subscriptionPaymentSnapshot = new SubscriptionPaymentSnapshot(\n                new SubscriptionPaymentId(Guid.NewGuid()),\n                new PayerId(Guid.NewGuid()),\n                SubscriptionPeriod.Month,\n                \"PL\");\n\n            var subscription = Subscription.Create(subscriptionPaymentSnapshot);\n\n            var subscriptionRenewalPaymentSnapshot = new SubscriptionRenewalPaymentSnapshot(\n                new SubscriptionRenewalPaymentId(Guid.NewGuid()),\n                new PayerId(Guid.NewGuid()),\n                SubscriptionPeriod.Month,\n                \"PL\");\n\n            // Act\n            subscription.Renew(subscriptionRenewalPaymentSnapshot);\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionRenewedDomainEvent>(subscription);\n        }\n\n        [Test]\n        public void ExpireSubscription_IsSuccessful()\n        {\n            // Arrange\n            var referenceDate = DateTime.UtcNow;\n\n            SystemClock.Set(referenceDate);\n\n            var subscriptionPaymentSnapshot = new SubscriptionPaymentSnapshot(\n                new SubscriptionPaymentId(Guid.NewGuid()),\n                new PayerId(Guid.NewGuid()),\n                SubscriptionPeriod.Month,\n                \"PL\");\n\n            var subscription = Subscription.Create(subscriptionPaymentSnapshot);\n\n            SystemClock.Set(referenceDate.AddMonths(1).AddMilliseconds(1));\n\n            // Act\n            subscription.Expire();\n\n            // Assert\n            AssertPublishedDomainEvent<SubscriptionExpiredDomainEvent>(subscription);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/CompanyName.MyMeetings.Modules.Registrations.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\BuildingBlocks\\Application\\CompanyName.MyMeetings.BuildingBlocks.Application.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/Registrations/Application/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Configuration/Queries/IQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Queries\n{\n    public interface IQueryHandler<in TQuery, TResult> :\n        IRequestHandler<TQuery, TResult>\n        where TQuery : IQuery<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/CommandBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public abstract class CommandBase : ICommand\n    {\n        public Guid Id { get; }\n\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n\n    public abstract class CommandBase<TResult> : ICommand<TResult>\n    {\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/CustomClaimTypes.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public class CustomClaimTypes\n    {\n        public const string Roles = \"roles\";\n        public const string Email = \"email\";\n        public const string Name = \"name\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/ICommand.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public interface ICommand<out TResult> : IRequest<TResult>\n    {\n        Guid Id { get; }\n    }\n\n    public interface ICommand : IRequest\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/IQuery.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public interface IQuery<out TResult> : IRequest<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/IRegistrationsModule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public interface IRegistrationsModule\n    {\n        Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n        Task ExecuteCommandAsync(ICommand command);\n\n        Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/QueryBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public abstract class QueryBase<TResult> : IQuery<TResult>\n    {\n        public Guid Id { get; }\n\n        protected QueryBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected QueryBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/Contracts/Roles.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.Contracts\n{\n    public class Roles\n    {\n        public const string Admin = \"Admin\";\n        public const string User = \"User\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/ConfirmUserRegistration/ConfirmUserRegistrationCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration\n{\n    public class ConfirmUserRegistrationCommand : CommandBase\n    {\n        public ConfirmUserRegistrationCommand(Guid userRegistrationId)\n        {\n            UserRegistrationId = userRegistrationId;\n        }\n\n        public Guid UserRegistrationId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/ConfirmUserRegistration/ConfirmUserRegistrationCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration\n{\n    internal class ConfirmUserRegistrationCommandHandler : ICommandHandler<ConfirmUserRegistrationCommand>\n    {\n        private readonly IUserRegistrationRepository _userRegistrationRepository;\n\n        public ConfirmUserRegistrationCommandHandler(IUserRegistrationRepository userRegistrationRepository)\n        {\n            _userRegistrationRepository = userRegistrationRepository;\n        }\n\n        public async Task Handle(ConfirmUserRegistrationCommand request, CancellationToken cancellationToken)\n        {\n            var userRegistration =\n                await _userRegistrationRepository.GetByIdAsync(new UserRegistrationId(request.UserRegistrationId));\n\n            userRegistration.Confirm();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/ConfirmUserRegistration/IUserCreator.cs",
    "content": "namespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\n\npublic interface IUserCreator\n{\n    public Task Create(\n        Guid userRegistrationId,\n        string login,\n        string password,\n        string email,\n        string firstName,\n        string lastName);\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/ConfirmUserRegistration/UserRegistrationConfirmedNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\n\npublic class UserRegistrationConfirmedNotification : DomainNotificationBase<UserRegistrationConfirmedDomainEvent>\n{\n    public UserRegistrationConfirmedNotification(UserRegistrationConfirmedDomainEvent domainEvent, Guid id)\n        : base(domainEvent, id)\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/ConfirmUserRegistration/UserRegistrationConfirmedNotificationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\n\npublic class UserRegistrationConfirmedNotificationHandler : INotificationHandler<UserRegistrationConfirmedNotification>\n{\n    private readonly IUserCreator _userCreator;\n\n    private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n    public UserRegistrationConfirmedNotificationHandler(IUserCreator userCreator, ISqlConnectionFactory sqlConnectionFactory)\n    {\n        _userCreator = userCreator;\n        _sqlConnectionFactory = sqlConnectionFactory;\n    }\n\n    public async Task Handle(UserRegistrationConfirmedNotification notification, CancellationToken cancellationToken)\n    {\n        var connection = _sqlConnectionFactory.GetOpenConnection();\n\n        var registration = await UserRegistrationProvider.GetById(\n            connection,\n            notification.DomainEvent.UserRegistrationId.Value);\n\n        await _userCreator.Create(\n            registration.Id,\n            registration.Login,\n            registration.Password,\n            registration.Email,\n            registration.FirstName,\n            registration.LastName);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/GetUserRegistration/GetUserRegistrationQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration\n{\n    public class GetUserRegistrationQuery : QueryBase<UserRegistrationDto>\n    {\n        public GetUserRegistrationQuery(Guid userRegistrationId)\n        {\n            UserRegistrationId = userRegistrationId;\n        }\n\n        public Guid UserRegistrationId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/GetUserRegistration/GetUserRegistrationQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Queries;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration\n{\n    internal class GetUserRegistrationQueryHandler : IQueryHandler<GetUserRegistrationQuery, UserRegistrationDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetUserRegistrationQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public Task<UserRegistrationDto> Handle(GetUserRegistrationQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            return UserRegistrationProvider.GetById(connection, query.UserRegistrationId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/GetUserRegistration/UserRegistrationDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration\n{\n    public class UserRegistrationDto\n    {\n        public Guid Id { get; set; }\n\n        public string Login { get; set; }\n\n        public string Email { get; set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public string Name { get; set; }\n\n        public string StatusCode { get; set; }\n\n        public string Password { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/GetUserRegistration/UserRegistrationProvider.cs",
    "content": "﻿using System.Data;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration;\n\ninternal static class UserRegistrationProvider\n{\n    internal static async Task<UserRegistrationDto> GetById(\n        IDbConnection connection,\n        Guid userRegistrationId)\n    {\n        const string sql = $\"\"\"\n                            SELECT\n                                [UserRegistration].[Id] as [{nameof(UserRegistrationDto.Id)}],\n                                [UserRegistration].[Login] as [{nameof(UserRegistrationDto.Login)}],\n                                [UserRegistration].[Email] as [{nameof(UserRegistrationDto.Email)}],\n                                [UserRegistration].[FirstName] as [{nameof(UserRegistrationDto.FirstName)}],\n                                [UserRegistration].[LastName] as [{nameof(UserRegistrationDto.LastName)}],\n                                [UserRegistration].[Name] as [{nameof(UserRegistrationDto.Name)}],\n                                [UserRegistration].[StatusCode] as [{nameof(UserRegistrationDto.StatusCode)}],\n                                [UserRegistration].[Password] as [{nameof(UserRegistrationDto.Password)}]\n                            FROM [registrations].[v_UserRegistrations] AS [UserRegistration]\n                            WHERE [UserRegistration].[Id] = @UserRegistrationId\n                            \"\"\";\n\n        return await connection.QuerySingleAsync<UserRegistrationDto>(\n            sql,\n            new\n            {\n                userRegistrationId\n            });\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/NewUserRegisteredEnqueueEmailConfirmationHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.SendUserRegistrationConfirmationEmail;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    public class NewUserRegisteredEnqueueEmailConfirmationHandler : INotificationHandler<NewUserRegisteredNotification>\n    {\n        private readonly ICommandsScheduler _commandsScheduler;\n\n        public NewUserRegisteredEnqueueEmailConfirmationHandler(ICommandsScheduler commandsScheduler)\n        {\n            _commandsScheduler = commandsScheduler;\n        }\n\n        public async Task Handle(NewUserRegisteredNotification notification, CancellationToken cancellationToken)\n        {\n            await _commandsScheduler.EnqueueAsync(new SendUserRegistrationConfirmationEmailCommand(\n                Guid.NewGuid(),\n                notification.DomainEvent.UserRegistrationId,\n                notification.DomainEvent.Email,\n                notification.DomainEvent.ConfirmLink));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/NewUserRegisteredNotification.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    public class NewUserRegisteredNotification : DomainNotificationBase<NewUserRegisteredDomainEvent>\n    {\n        [JsonConstructor]\n        public NewUserRegisteredNotification(NewUserRegisteredDomainEvent domainEvent, Guid id)\n            : base(domainEvent, id)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/NewUserRegisteredPublishEventHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    public class NewUserRegisteredPublishEventHandler : INotificationHandler<NewUserRegisteredNotification>\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public NewUserRegisteredPublishEventHandler(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        public async Task Handle(NewUserRegisteredNotification notification, CancellationToken cancellationToken)\n        {\n            await _eventsBus.Publish(new NewUserRegisteredIntegrationEvent(\n                notification.Id,\n                notification.DomainEvent.OccurredOn,\n                notification.DomainEvent.UserRegistrationId.Value,\n                notification.DomainEvent.Login,\n                notification.DomainEvent.Email,\n                notification.DomainEvent.FirstName,\n                notification.DomainEvent.LastName,\n                notification.DomainEvent.Name));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/PasswordManager.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Security.Cryptography;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    public class PasswordManager\n    {\n        public static string HashPassword(string password)\n        {\n            byte[] salt;\n            byte[] buffer2;\n            if (password == null)\n            {\n                throw new ArgumentNullException(nameof(password));\n            }\n\n            using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8, HashAlgorithmName.SHA256))\n            {\n                salt = bytes.Salt;\n                buffer2 = bytes.GetBytes(0x20);\n            }\n\n            byte[] dst = new byte[0x31];\n            Buffer.BlockCopy(salt, 0, dst, 1, 0x10);\n            Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);\n            return Convert.ToBase64String(dst);\n        }\n\n        public static bool VerifyHashedPassword(string hashedPassword, string password)\n        {\n            byte[] buffer4;\n            if (hashedPassword == null)\n            {\n                return false;\n            }\n\n            if (password == null)\n            {\n                throw new ArgumentNullException(nameof(password));\n            }\n\n            byte[] src = Convert.FromBase64String(hashedPassword);\n            if ((src.Length != 0x31) || (src[0] != 0))\n            {\n                return false;\n            }\n\n            byte[] dst = new byte[0x10];\n            Buffer.BlockCopy(src, 1, dst, 0, 0x10);\n            byte[] buffer3 = new byte[0x20];\n            Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);\n            using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 0x3e8, HashAlgorithmName.SHA256))\n            {\n                buffer4 = bytes.GetBytes(0x20);\n            }\n\n            return ByteArraysEqual(buffer3, buffer4);\n        }\n\n        [MethodImpl(MethodImplOptions.NoOptimization)]\n        private static bool ByteArraysEqual(byte[] a, byte[] b)\n        {\n            if (ReferenceEquals(a, b))\n            {\n                return true;\n            }\n\n            if (a == null || b == null || a.Length != b.Length)\n            {\n                return false;\n            }\n\n            var areSame = true;\n            for (var i = 0; i < a.Length; i++)\n            {\n                areSame &= a[i] == b[i];\n            }\n\n            return areSame;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/RegisterNewUserCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    public class RegisterNewUserCommand : CommandBase<Guid>\n    {\n        public RegisterNewUserCommand(\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName,\n            string confirmLink)\n        {\n            Login = login;\n            Password = password;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            ConfirmLink = confirmLink;\n        }\n\n        public string Login { get; }\n\n        public string Password { get; }\n\n        public string Email { get; }\n\n        public string FirstName { get; }\n\n        public string LastName { get; }\n\n        public string ConfirmLink { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/RegisterNewUser/RegisterNewUserCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser\n{\n    internal class RegisterNewUserCommandHandler : ICommandHandler<RegisterNewUserCommand, Guid>\n    {\n        private readonly IUserRegistrationRepository _userRegistrationRepository;\n        private readonly IUsersCounter _usersCounter;\n\n        public RegisterNewUserCommandHandler(\n            IUserRegistrationRepository userRegistrationRepository,\n            IUsersCounter usersCounter)\n        {\n            _userRegistrationRepository = userRegistrationRepository;\n            _usersCounter = usersCounter;\n        }\n\n        public async Task<Guid> Handle(RegisterNewUserCommand command, CancellationToken cancellationToken)\n        {\n            var password = PasswordManager.HashPassword(command.Password);\n\n            var userRegistration = UserRegistration.RegisterNewUser(\n                command.Login,\n                password,\n                command.Email,\n                command.FirstName,\n                command.LastName,\n                _usersCounter,\n                command.ConfirmLink);\n\n            await _userRegistrationRepository.AddAsync(userRegistration);\n\n            return userRegistration.Id.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/SendUserRegistrationConfirmationEmail/SendUserRegistrationConfirmationEmailCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.SendUserRegistrationConfirmationEmail\n{\n    public class SendUserRegistrationConfirmationEmailCommand : InternalCommandBase\n    {\n        [JsonConstructor]\n        public SendUserRegistrationConfirmationEmailCommand(\n            Guid id,\n            UserRegistrationId userRegistrationId,\n            string email,\n            string confirmLink)\n            : base(id)\n        {\n            UserRegistrationId = userRegistrationId;\n            Email = email;\n            ConfirmLink = confirmLink;\n        }\n\n        internal UserRegistrationId UserRegistrationId { get; }\n\n        internal string Email { get; }\n\n        internal string ConfirmLink { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/SendUserRegistrationConfirmationEmail/SendUserRegistrationConfirmationEmailCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.SendUserRegistrationConfirmationEmail\n{\n    internal class SendUserRegistrationConfirmationEmailCommandHandler : ICommandHandler<SendUserRegistrationConfirmationEmailCommand>\n    {\n        private readonly IEmailSender _emailSender;\n\n        public SendUserRegistrationConfirmationEmailCommandHandler(\n            IEmailSender emailSender)\n        {\n            _emailSender = emailSender;\n        }\n\n        public async Task Handle(SendUserRegistrationConfirmationEmailCommand command, CancellationToken cancellationToken)\n        {\n            string link = $\"<a href=\\\"{command.ConfirmLink}{command.UserRegistrationId.Value}\\\">link</a>\";\n\n            string content = $\"Welcome to MyMeetings application! Please confirm your registration using this {link}.\";\n\n            var emailMessage = new EmailMessage(\n                command.Email,\n                \"MyMeetings - Please confirm your registration\",\n                content);\n\n            await _emailSender.SendEmail(emailMessage);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Application/UserRegistrations/UsersCounter.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations\n{\n    public class UsersCounter : IUsersCounter\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public UsersCounter(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public int CountUsersWithLogin(string login)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = \"\"\"\n                                SELECT COUNT(*) \n                                FROM [registrations].[v_UserRegistrations] AS [UserRegistration]\n                                WHERE [UserRegistration].[Login] = @Login\n                                \"\"\";\n            return connection.QuerySingle<int>(\n                sql,\n                new\n                {\n                    login\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/CompanyName.MyMeetings.Modules.Registrations.Domain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Events/NewUserRegisteredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events\n{\n    public class NewUserRegisteredDomainEvent : DomainEventBase\n    {\n        public UserRegistrationId UserRegistrationId { get; }\n\n        public string Login { get; }\n\n        public string Email { get; }\n\n        public string FirstName { get; }\n\n        public string LastName { get; }\n\n        public string Name { get; }\n\n        public DateTime RegisterDate { get; }\n\n        public string ConfirmLink { get; }\n\n        public NewUserRegisteredDomainEvent(\n            UserRegistrationId userRegistrationId,\n            string login,\n            string email,\n            string firstName,\n            string lastName,\n            string name,\n            DateTime registerDate,\n            string confirmLink)\n        {\n            UserRegistrationId = userRegistrationId;\n            Login = login;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n            RegisterDate = registerDate;\n            ConfirmLink = confirmLink;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Events/UserRegistrationConfirmedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events\n{\n    public class UserRegistrationConfirmedDomainEvent : DomainEventBase\n    {\n        public UserRegistrationConfirmedDomainEvent(UserRegistrationId userRegistrationId)\n        {\n            UserRegistrationId = userRegistrationId;\n        }\n\n        public UserRegistrationId UserRegistrationId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Events/UserRegistrationExpiredDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events\n{\n    public class UserRegistrationExpiredDomainEvent : DomainEventBase\n    {\n        public UserRegistrationExpiredDomainEvent(UserRegistrationId userRegistrationId)\n        {\n            UserRegistrationId = userRegistrationId;\n        }\n\n        public UserRegistrationId UserRegistrationId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/IUserRegistrationRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations\n{\n    public interface IUserRegistrationRepository\n    {\n        Task AddAsync(UserRegistration userRegistration);\n\n        Task<UserRegistration> GetByIdAsync(UserRegistrationId userRegistrationId);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/IUsersCounter.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations\n{\n    public interface IUsersCounter\n    {\n        int CountUsersWithLogin(string login);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Rules/UserCannotBeCreatedWhenRegistrationIsNotConfirmedRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules\n{\n    public class UserCannotBeCreatedWhenRegistrationIsNotConfirmedRule : IBusinessRule\n    {\n        private readonly UserRegistrationStatus _actualRegistrationStatus;\n\n        internal UserCannotBeCreatedWhenRegistrationIsNotConfirmedRule(UserRegistrationStatus actualRegistrationStatus)\n        {\n            this._actualRegistrationStatus = actualRegistrationStatus;\n        }\n\n        public bool IsBroken() => _actualRegistrationStatus != UserRegistrationStatus.Confirmed;\n\n        public string Message => \"User cannot be created when registration is not confirmed\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Rules/UserLoginMustBeUniqueRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules\n{\n    public class UserLoginMustBeUniqueRule : IBusinessRule\n    {\n        private readonly IUsersCounter _usersCounter;\n        private readonly string _login;\n\n        internal UserLoginMustBeUniqueRule(IUsersCounter usersCounter, string login)\n        {\n            _usersCounter = usersCounter;\n            _login = login;\n        }\n\n        public bool IsBroken() => _usersCounter.CountUsersWithLogin(_login) > 0;\n\n        public string Message => \"User Login must be unique\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Rules/UserRegistrationCannotBeConfirmedAfterExpirationRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules\n{\n    public class UserRegistrationCannotBeConfirmedAfterExpirationRule : IBusinessRule\n    {\n        private readonly UserRegistrationStatus _actualRegistrationStatus;\n\n        internal UserRegistrationCannotBeConfirmedAfterExpirationRule(UserRegistrationStatus actualRegistrationStatus)\n        {\n            this._actualRegistrationStatus = actualRegistrationStatus;\n        }\n\n        public bool IsBroken() => _actualRegistrationStatus == UserRegistrationStatus.Expired;\n\n        public string Message => \"User Registration cannot be confirmed because it is expired\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Rules/UserRegistrationCannotBeConfirmedMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules\n{\n    public class UserRegistrationCannotBeConfirmedMoreThanOnceRule : IBusinessRule\n    {\n        private readonly UserRegistrationStatus _actualRegistrationStatus;\n\n        internal UserRegistrationCannotBeConfirmedMoreThanOnceRule(UserRegistrationStatus actualRegistrationStatus)\n        {\n            this._actualRegistrationStatus = actualRegistrationStatus;\n        }\n\n        public bool IsBroken() => _actualRegistrationStatus == UserRegistrationStatus.Confirmed;\n\n        public string Message => \"User Registration cannot be confirmed more than once\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/Rules/UserRegistrationCannotBeExpiredMoreThanOnceRule.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules\n{\n    public class UserRegistrationCannotBeExpiredMoreThanOnceRule : IBusinessRule\n    {\n        private readonly UserRegistrationStatus _actualRegistrationStatus;\n\n        internal UserRegistrationCannotBeExpiredMoreThanOnceRule(UserRegistrationStatus actualRegistrationStatus)\n        {\n            this._actualRegistrationStatus = actualRegistrationStatus;\n        }\n\n        public bool IsBroken() => _actualRegistrationStatus == UserRegistrationStatus.Expired;\n\n        public string Message => \"User Registration cannot be expired more than once\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/UserRegistration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations\n{\n    public class UserRegistration : Entity, IAggregateRoot\n    {\n        public UserRegistrationId Id { get; private set; }\n\n        private string _login;\n\n        private string _password;\n\n        private string _email;\n\n        private string _firstName;\n\n        private string _lastName;\n\n        private string _name;\n\n        private DateTime _registerDate;\n\n        private UserRegistrationStatus _status;\n\n        private DateTime? _confirmedDate;\n\n        private UserRegistration()\n        {\n            // Only EF.\n        }\n\n        public static UserRegistration RegisterNewUser(\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName,\n            IUsersCounter usersCounter,\n            string confirmLink)\n        {\n            return new UserRegistration(login, password, email, firstName, lastName, usersCounter, confirmLink);\n        }\n\n        private UserRegistration(\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName,\n            IUsersCounter usersCounter,\n            string confirmLink)\n        {\n            this.CheckRule(new UserLoginMustBeUniqueRule(usersCounter, login));\n\n            this.Id = new UserRegistrationId(Guid.NewGuid());\n            _login = login;\n            _password = password;\n            _email = email;\n            _firstName = firstName;\n            _lastName = lastName;\n            _name = $\"{firstName} {lastName}\";\n            _registerDate = DateTime.UtcNow;\n            _status = UserRegistrationStatus.WaitingForConfirmation;\n\n            this.AddDomainEvent(new NewUserRegisteredDomainEvent(\n                this.Id,\n                _login,\n                _email,\n                _firstName,\n                _lastName,\n                _name,\n                _registerDate,\n                confirmLink));\n        }\n\n        public void Confirm()\n        {\n            this.CheckRule(new UserRegistrationCannotBeConfirmedMoreThanOnceRule(_status));\n            this.CheckRule(new UserRegistrationCannotBeConfirmedAfterExpirationRule(_status));\n\n            _status = UserRegistrationStatus.Confirmed;\n            _confirmedDate = DateTime.UtcNow;\n\n            this.AddDomainEvent(new UserRegistrationConfirmedDomainEvent(this.Id));\n        }\n\n        public void Expire()\n        {\n            this.CheckRule(new UserRegistrationCannotBeExpiredMoreThanOnceRule(_status));\n\n            _status = UserRegistrationStatus.Expired;\n\n            this.AddDomainEvent(new UserRegistrationExpiredDomainEvent(this.Id));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/UserRegistrationId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations\n{\n    public class UserRegistrationId : TypedIdValueBase\n    {\n        public UserRegistrationId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Domain/UserRegistrations/UserRegistrationStatus.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations\n{\n    public class UserRegistrationStatus : ValueObject\n    {\n        public static UserRegistrationStatus WaitingForConfirmation =>\n            new UserRegistrationStatus(nameof(WaitingForConfirmation));\n\n        public static UserRegistrationStatus Confirmed => new UserRegistrationStatus(nameof(Confirmed));\n\n        public static UserRegistrationStatus Expired => new UserRegistrationStatus(nameof(Expired));\n\n        public string Value { get; }\n\n        private UserRegistrationStatus(string value)\n        {\n            Value = value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/CompanyName.MyMeetings.Modules.Registrations.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\UserAccess\\Application\\CompanyName.MyMeetings.Modules.UserAccess.Application.csproj\" />\n    <ProjectReference Include=\"..\\..\\UserAccess\\Infrastructure\\CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/AllConstructorFinder.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing Autofac.Core.Activators.Reflection;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration\n{\n    internal class AllConstructorFinder : IConstructorFinder\n    {\n        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =\n            new ConcurrentDictionary<Type, ConstructorInfo[]>();\n\n        public ConstructorInfo[] FindConstructors(Type targetType)\n        {\n            var result = Cache.GetOrAdd(\n                targetType,\n                t => t.GetTypeInfo().DeclaredConstructors.ToArray());\n\n            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType, this);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Assemblies.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration\n{\n    internal static class Assemblies\n    {\n        public static readonly Assembly Application = typeof(IRegistrationsModule).Assembly;\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/DataAccess/DataAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.DataAccess\n{\n    internal class DataAccessModule : Autofac.Module\n    {\n        private readonly string _databaseConnectionString;\n        private readonly ILoggerFactory _loggerFactory;\n\n        internal DataAccessModule(string databaseConnectionString, ILoggerFactory loggerFactory)\n        {\n            _databaseConnectionString = databaseConnectionString;\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlConnectionFactory>()\n                .As<ISqlConnectionFactory>()\n                .WithParameter(\"connectionString\", _databaseConnectionString)\n                .InstancePerLifetimeScope();\n\n            builder\n                .Register(c =>\n                {\n                    var dbContextOptionsBuilder = new DbContextOptionsBuilder<RegistrationsContext>();\n                    dbContextOptionsBuilder.UseSqlServer(_databaseConnectionString);\n\n                    dbContextOptionsBuilder\n                        .ReplaceService<IValueConverterSelector, StronglyTypedIdValueConverterSelector>();\n\n                    return new RegistrationsContext(dbContextOptionsBuilder.Options, _loggerFactory);\n                })\n                .AsSelf()\n                .As<DbContext>()\n                .InstancePerLifetimeScope();\n\n            var infrastructureAssembly = typeof(RegistrationsContext).Assembly;\n\n            builder.RegisterAssemblyTypes(infrastructureAssembly)\n                .Where(type => type.Name.EndsWith(\"Repository\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Domain/DomainModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Users;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Domain\n{\n    internal class DomainModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<UsersCounter>()\n                .As<IUsersCounter>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<UserAccessGateway>()\n                .As<IUserCreator>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Email/EmailModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Email\n{\n    internal class EmailModule : Module\n    {\n        private readonly IEmailSender _emailSender;\n        private readonly EmailsConfiguration _configuration;\n\n        public EmailModule(\n            EmailsConfiguration configuration,\n            IEmailSender emailSender)\n        {\n            _configuration = configuration;\n            _emailSender = emailSender;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_emailSender != null)\n            {\n                builder.RegisterInstance(_emailSender);\n            }\n            else\n            {\n                builder.RegisterType<EmailSender>()\n                    .As<IEmailSender>()\n                    .WithParameter(\"configuration\", _configuration)\n                    .InstancePerLifetimeScope();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/EventsBus/EventsBusModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.EventsBus\n{\n    internal class EventsBusModule : Autofac.Module\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public EventsBusModule(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_eventsBus != null)\n            {\n                builder.RegisterInstance(_eventsBus).SingleInstance();\n            }\n            else\n            {\n                builder.RegisterType<InMemoryEventBusClient>()\n                    .As<IEventsBus>()\n                    .SingleInstance();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/EventsBus/EventsBusStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.EventsBus\n{\n    public static class EventsBusStartup\n    {\n        public static void Initialize(\n            ILogger logger)\n        {\n            SubscribeToIntegrationEvents(logger);\n        }\n\n        private static void SubscribeToIntegrationEvents(ILogger logger)\n        {\n            var eventBus = RegistrationsCompositionRoot.BeginLifetimeScope().Resolve<IEventsBus>();\n\n            //// SubscribeToIntegrationEvent<MemberCreatedIntegrationEvent>(eventBus, logger);\n        }\n\n        private static void SubscribeToIntegrationEvent<T>(IEventsBus eventBus, ILogger logger)\n            where T : IntegrationEvent\n        {\n            logger.Information(\"Subscribe to {@IntegrationEvent}\", typeof(T).FullName);\n            eventBus.Subscribe(\n                new IntegrationEventGenericHandler<T>());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/EventsBus/IntegrationEventGenericHandler.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.EventsBus\n{\n    internal class IntegrationEventGenericHandler<T> : IIntegrationEventHandler<T>\n        where T : IntegrationEvent\n    {\n        public async Task Handle(T @event)\n        {\n            using (var scope = RegistrationsCompositionRoot.BeginLifetimeScope())\n            {\n                using (var connection = scope.Resolve<ISqlConnectionFactory>().GetOpenConnection())\n                {\n                    string type = @event.GetType().FullName;\n                    var data = JsonConvert.SerializeObject(@event, new JsonSerializerSettings\n                    {\n                        ContractResolver = new AllPropertiesContractResolver()\n                    });\n\n                    var sql = \"INSERT INTO [registrations].[InboxMessages] (Id, OccurredOn, Type, Data) \" +\n                              \"VALUES (@Id, @OccurredOn, @Type, @Data)\";\n\n                    await connection.ExecuteScalarAsync(sql, new\n                    {\n                        @event.Id,\n                        @event.OccurredOn,\n                        type,\n                        data\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Logging/LoggingModule.cs",
    "content": "﻿using Autofac;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Logging\n{\n    internal class LoggingModule : Autofac.Module\n    {\n        private readonly ILogger _logger;\n\n        internal LoggingModule(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterInstance(_logger)\n                .As<ILogger>()\n                .SingleInstance();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Mediation/MediatorModule.cs",
    "content": "﻿using System.Reflection;\nusing Autofac;\nusing Autofac.Core;\nusing Autofac.Features.Variance;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing FluentValidation;\nusing MediatR;\nusing MediatR.Pipeline;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Mediation\n{\n    public class MediatorModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<ServiceProviderWrapper>()\n            .As<IServiceProvider>()\n            .InstancePerDependency()\n            .IfNotRegistered(typeof(IServiceProvider));\n\n            builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope();\n\n            var mediatorOpenTypes = new[]\n            {\n                typeof(IRequestHandler<,>),\n                typeof(INotificationHandler<>),\n                typeof(IValidator<>),\n                typeof(IRequestPreProcessor<>),\n                typeof(IRequestHandler<>),\n                typeof(IStreamRequestHandler<,>),\n                typeof(IRequestPostProcessor<,>),\n                typeof(IRequestExceptionHandler<,,>),\n                typeof(IRequestExceptionAction<,>),\n                typeof(ICommandHandler<>),\n                typeof(ICommandHandler<,>),\n            };\n            builder.RegisterSource(new ScopedContravariantRegistrationSource(\n                mediatorOpenTypes));\n            foreach (var mediatorOpenType in mediatorOpenTypes)\n            {\n                builder\n                    .RegisterAssemblyTypes(Assemblies.Application, ThisAssembly)\n                    .AsClosedTypesOf(mediatorOpenType)\n                    .AsImplementedInterfaces()\n                    .FindConstructorsWith(new AllConstructorFinder());\n            }\n\n            builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n            builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n        }\n\n        private class ScopedContravariantRegistrationSource : IRegistrationSource\n        {\n            private readonly ContravariantRegistrationSource _source = new();\n            private readonly List<Type> _types = new();\n\n            public ScopedContravariantRegistrationSource(params Type[] types)\n            {\n                ArgumentNullException.ThrowIfNull(types);\n\n                if (!types.All(x => x.IsGenericTypeDefinition))\n                {\n                    throw new ArgumentException(\"Supplied types should be generic type definitions\");\n                }\n\n                _types.AddRange(types);\n            }\n\n            public IEnumerable<IComponentRegistration> RegistrationsFor(\n                Service service,\n                Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)\n            {\n                var components = _source.RegistrationsFor(service, registrationAccessor);\n                foreach (var c in components)\n                {\n                    var defs = c.Target.Services\n                        .OfType<TypedService>()\n                        .Select(x => x.ServiceType.GetGenericTypeDefinition());\n\n                    if (defs.Any(_types.Contains))\n                    {\n                        yield return c;\n                    }\n                }\n            }\n\n            public bool IsAdapterForIndividualComponents => _source.IsAdapterForIndividualComponents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/CommandsExecutor.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal static class CommandsExecutor\n    {\n        internal static async Task Execute(ICommand command)\n        {\n            using (var scope = RegistrationsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                await mediator.Send(command);\n            }\n        }\n\n        internal static async Task<TResult> Execute<TResult>(ICommand<TResult> command)\n        {\n            using (var scope = RegistrationsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                return await mediator.Send(command);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Inbox/InboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Inbox\n{\n    public class InboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Inbox\n{\n    public class ProcessInboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Inbox\n{\n    internal class ProcessInboxCommandHandler : ICommandHandler<ProcessInboxCommand>\n    {\n        private readonly IMediator _mediator;\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public ProcessInboxCommandHandler(IMediator mediator, ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _mediator = mediator;\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(ProcessInboxCommand command, CancellationToken cancellationToken)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n            const string sql = $\"\"\"\n                               SELECT \n                                  [InboxMessage].[Id] AS [{nameof(InboxMessageDto.Id)}], \n                                  [InboxMessage].[Type] AS [{nameof(InboxMessageDto.Type)}], \n                                  [InboxMessage].[Data] AS [{nameof(InboxMessageDto.Data)}] \n                               FROM [registrations].[InboxMessages] AS [InboxMessage] \n                               WHERE [InboxMessage].[ProcessedDate] IS NULL \n                               ORDER BY [InboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<InboxMessageDto>(sql);\n\n            const string sqlUpdateProcessedDate = \"\"\"\n                                                  UPDATE [registrations].[InboxMessages] \n                                                  SET [ProcessedDate] = @Date \n                                                  WHERE [Id] = @Id\n                                                  \"\"\";\n\n            foreach (var message in messages)\n            {\n                var messageAssembly = AppDomain.CurrentDomain.GetAssemblies()\n                    .SingleOrDefault(assembly => message.Type.Contains(assembly.GetName().Name));\n\n                Type type = messageAssembly.GetType(message.Type);\n                var request = JsonConvert.DeserializeObject(message.Data, type);\n\n                try\n                {\n                    await _mediator.Publish((INotification)request, cancellationToken);\n                }\n                catch (Exception e)\n                {\n                    Console.WriteLine(e);\n                    throw;\n                }\n\n                await connection.ExecuteAsync(sqlUpdateProcessedDate, new\n                {\n                    Date = DateTime.UtcNow,\n                    message.Id\n                });\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Inbox/ProcessInboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Inbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/InternalCommands/CommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands\n{\n    public class CommandsScheduler : ICommandsScheduler\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public CommandsScheduler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task EnqueueAsync(ICommand command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [registrations].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n\n        public async Task EnqueueAsync<T>(ICommand<T> command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [registrations].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing Dapper;\nusing Newtonsoft.Json;\nusing Polly;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommandHandler : ICommandHandler<ProcessInternalCommandsCommand>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public ProcessInternalCommandsCommandHandler(\n            ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task Handle(ProcessInternalCommandsCommand command, CancellationToken cancellationToken)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [Command].[Id] AS [{nameof(InternalCommandDto.Id)}], \n                                    [Command].[Type] AS [{nameof(InternalCommandDto.Type)}], \n                                    [Command].[Data] AS [{nameof(InternalCommandDto.Data)}] \n                                FROM [registrations].[InternalCommands] AS [Command] \n                                WHERE [Command].[ProcessedDate] IS NULL \n                                ORDER BY [Command].[EnqueueDate]\n                                \"\"\";\n            var commands = await connection.QueryAsync<InternalCommandDto>(sql);\n\n            var internalCommandsList = commands.AsList();\n\n            var policy = Policy\n                .Handle<Exception>()\n                .WaitAndRetryAsync(new[]\n                {\n                    TimeSpan.FromSeconds(1),\n                    TimeSpan.FromSeconds(2),\n                    TimeSpan.FromSeconds(3)\n                });\n\n            foreach (var internalCommand in internalCommandsList)\n            {\n                var result = await policy.ExecuteAndCaptureAsync(() => ProcessCommand(\n                    internalCommand));\n\n                if (result.Outcome == OutcomeType.Failure)\n                {\n                    await connection.ExecuteScalarAsync(\n                        \"\"\"\n                        UPDATE [registrations].[InternalCommands] \n                        SET \n                            ProcessedDate = @NowDate, \n                            Error = @Error \n                        WHERE [Id] = @Id\n                        \"\"\",\n                        new\n                        {\n                            NowDate = DateTime.UtcNow,\n                            Error = result.FinalException.ToString(),\n                            internalCommand.Id\n                        });\n                }\n            }\n        }\n\n        private async Task ProcessCommand(\n            InternalCommandDto internalCommand)\n        {\n            Type type = Assemblies.Application.GetType(internalCommand.Type);\n            dynamic commandToProcess = JsonConvert.DeserializeObject(internalCommand.Data, type);\n\n            await CommandsExecutor.Execute(commandToProcess);\n        }\n\n        private class InternalCommandDto\n        {\n            public Guid Id { get; set; }\n\n            public string Type { get; set; }\n\n            public string Data { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInternalCommandsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInternalCommandsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/LoggingCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T> _decorated;\n\n        public LoggingCommandHandlerDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                 await _decorated.Handle(command, cancellationToken);\n\n                 return;\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {Command}\",\n                        command.GetType().Name);\n\n                    await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand _command;\n\n            public CommandLogEnricher(ICommand command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/LoggingCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public LoggingCommandHandlerWithResultDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T, TResult> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                return await _decorated.Handle(command, cancellationToken);\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {@Command}\",\n                        command);\n\n                    var result = await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command processed successful, result {Result}\", result);\n\n                    return result;\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command processing failed\");\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand<TResult> _command;\n\n            public CommandLogEnricher(ICommand<TResult> command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\n                    \"Context\",\n                    new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\n                        \"CorrelationId\",\n                        new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Outbox/OutboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox\n{\n    public class OutboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Outbox/OutboxModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Outbox;\nusing Module = Autofac.Module;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class OutboxModule : Module\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public OutboxModule(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<OutboxAccessor>()\n                .As<IOutbox>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .InstancePerLifetimeScope();\n\n            CheckMappings();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"domainNotificationsMap\", _domainNotificationsMap)\n                .SingleInstance();\n        }\n\n        private void CheckMappings()\n        {\n            var domainEventNotifications = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.GetInterfaces().Contains(typeof(IDomainEventNotification)))\n                .ToList();\n\n            List<Type> notMappedNotifications = [];\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                _domainNotificationsMap.TryGetBySecond(domainEventNotification, out var name);\n\n                if (name == null)\n                {\n                    notMappedNotifications.Add(domainEventNotification);\n                }\n            }\n\n            if (notMappedNotifications.Any())\n            {\n                throw new ApplicationException($\"Domain Event Notifications {notMappedNotifications.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox\n{\n    public class ProcessOutboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class ProcessOutboxCommandHandler : ICommandHandler<ProcessOutboxCommand>\n    {\n        private readonly IMediator _mediator;\n\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\n\n        public ProcessOutboxCommandHandler(\n            IMediator mediator,\n            ISqlConnectionFactory sqlConnectionFactory,\n            IDomainNotificationsMapper domainNotificationsMapper)\n        {\n            _mediator = mediator;\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _domainNotificationsMapper = domainNotificationsMapper;\n        }\n\n        public async Task Handle(ProcessOutboxCommand command, CancellationToken cancellationToken)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n            const string sql = $\"\"\"\n                               SELECT \n                                   [OutboxMessage].[Id] AS [{nameof(OutboxMessageDto.Id)}], \n                                   [OutboxMessage].[Type] AS [{nameof(OutboxMessageDto.Type)}], \n                                   [OutboxMessage].[Data] AS [{nameof(OutboxMessageDto.Data)}] \n                               FROM [registrations].[OutboxMessages] AS [OutboxMessage] \n                               WHERE [OutboxMessage].[ProcessedDate] IS NULL \n                               ORDER BY [OutboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            var messagesList = messages.AsList();\n\n            const string sqlUpdateProcessedDate = \"\"\"\n                                                  UPDATE [registrations].[OutboxMessages] \n                                                  SET [ProcessedDate] = @Date \n                                                  WHERE [Id] = @Id\n                                                  \"\"\";\n            if (messagesList.Count > 0)\n            {\n                foreach (var message in messagesList)\n                {\n                    var type = _domainNotificationsMapper.GetType(message.Type);\n                    var @event = JsonConvert.DeserializeObject(message.Data, type) as IDomainEventNotification;\n\n                    using (LogContext.Push(new OutboxMessageContextEnricher(@event)))\n                    {\n                        await this._mediator.Publish(@event, cancellationToken);\n\n                        await connection.ExecuteAsync(sqlUpdateProcessedDate, new\n                        {\n                            Date = DateTime.UtcNow,\n                            message.Id\n                        });\n                    }\n                }\n            }\n        }\n\n        private class OutboxMessageContextEnricher : ILogEventEnricher\n        {\n            private readonly IDomainEventNotification _notification;\n\n            public OutboxMessageContextEnricher(IDomainEventNotification notification)\n            {\n                _notification = notification;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"OutboxMessage:{_notification.Id.ToString()}\")));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessOutboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessOutboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/ProcessingModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class ProcessingModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<DomainEventsDispatcher>()\n                .As<IDomainEventsDispatcher>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainEventsAccessor>()\n                .As<IDomainEventsAccessor>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<UnitOfWork>()\n                .As<IUnitOfWork>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<CommandsScheduler>()\n                .As<ICommandsScheduler>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerDecorator<>),\n                typeof(IRequestHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerWithResultDecorator<,>),\n                typeof(IRequestHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(DomainEventsDispatcherNotificationHandlerDecorator<>),\n                typeof(INotificationHandler<>));\n\n            builder.RegisterAssemblyTypes(Assemblies.Application)\n                .AsClosedTypesOf(typeof(IDomainEventNotification<>))\n                .InstancePerDependency()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly ICommandHandler<T> _decorated;\n        private readonly IUnitOfWork _unitOfWork;\n        private readonly RegistrationsContext _registrationsContext;\n\n        public UnitOfWorkCommandHandlerDecorator(\n            ICommandHandler<T> decorated,\n            IUnitOfWork unitOfWork,\n            RegistrationsContext registrationsContext)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n            _registrationsContext = registrationsContext;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            await this._decorated.Handle(command, cancellationToken);\n\n            if (command is InternalCommandBase)\n            {\n                var internalCommand = await _registrationsContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\n\n                if (internalCommand != null)\n                {\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\n                }\n            }\n\n            await this._unitOfWork.CommitAsync(cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ICommandHandler<T, TResult> _decorated;\n        private readonly IUnitOfWork _unitOfWork;\n        private readonly RegistrationsContext _registrationsContext;\n\n        public UnitOfWorkCommandHandlerWithResultDecorator(\n            ICommandHandler<T, TResult> decorated,\n            IUnitOfWork unitOfWork,\n            RegistrationsContext registrationsContext)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n            _registrationsContext = registrationsContext;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var result = await this._decorated.Handle(command, cancellationToken);\n\n            if (command is InternalCommandBase<TResult>)\n            {\n                var internalCommand = await _registrationsContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\n\n                if (internalCommand != null)\n                {\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\n                }\n            }\n\n            await this._unitOfWork.CommitAsync(cancellationToken);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T> _decorated;\n\n        public ValidationCommandHandlerDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            await _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly IList<IValidator<T>> _validators;\n\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Quartz/QuartzModule.cs",
    "content": "﻿using Autofac;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Quartz\n{\n    public class QuartzModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterAssemblyTypes(ThisAssembly)\n                .Where(x => typeof(IJob).IsAssignableFrom(x)).InstancePerDependency();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Quartz/QuartzStartup.cs",
    "content": "﻿using System.Collections.Specialized;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Inbox;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox;\nusing Quartz;\nusing Quartz.Impl;\nusing Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Quartz\n{\n    internal static class QuartzStartup\n    {\n        internal static void Initialize(ILogger logger, long? internalProcessingPoolingInterval = null)\n        {\n            logger.Information(\"Quartz starting...\");\n\n            var schedulerConfiguration = new NameValueCollection();\n            schedulerConfiguration.Add(\"quartz.scheduler.instanceName\", \"Registrations\");\n\n            ISchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerConfiguration);\n            IScheduler scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult();\n\n            LogProvider.SetCurrentLogProvider(new SerilogLogProvider(logger));\n\n            scheduler.Start().GetAwaiter().GetResult();\n\n            var processOutboxJob = JobBuilder.Create<ProcessOutboxJob>().Build();\n            ITrigger trigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processOutboxJob, trigger)\n                .GetAwaiter().GetResult();\n\n            var processInboxJob = JobBuilder.Create<ProcessInboxJob>().Build();\n\n            ITrigger processInboxTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processInboxJob, processInboxTrigger)\n                .GetAwaiter().GetResult();\n\n            var processInternalCommandsJob = JobBuilder.Create<ProcessInternalCommandsJob>().Build();\n\n            ITrigger processInternalCommandsTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInternalCommandsTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInternalCommandsTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler.ScheduleJob(processInternalCommandsJob, processInternalCommandsTrigger).GetAwaiter().GetResult();\n\n            logger.Information(\"Quartz started.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/Quartz/SerilogLogProvider.cs",
    "content": "﻿using Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Quartz\n{\n    internal class SerilogLogProvider : ILogProvider\n    {\n        private readonly ILogger _logger;\n\n        internal SerilogLogProvider(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public Logger GetLogger(string name)\n        {\n            return (level, func, exception, parameters) =>\n            {\n                if (func == null)\n                {\n                    return true;\n                }\n\n                if (level == LogLevel.Debug || level == LogLevel.Trace)\n                {\n                    _logger.Debug(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Info)\n                {\n                    _logger.Information(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Warn)\n                {\n                    _logger.Warning(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Error)\n                {\n                    _logger.Error(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Fatal)\n                {\n                    _logger.Fatal(exception, func(), parameters);\n                }\n\n                return true;\n            };\n        }\n\n        public IDisposable OpenNestedContext(string message)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, string value)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, object value, bool destructure = false)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/RegistrationsCompositionRoot.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration\n{\n    internal static class RegistrationsCompositionRoot\n    {\n        private static IContainer _container;\n\n        internal static void SetContainer(IContainer container)\n        {\n            _container = container;\n        }\n\n        internal static ILifetimeScope BeginLifetimeScope()\n        {\n            return _container.BeginLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/RegistrationsStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.DataAccess;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Domain;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Email;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.EventsBus;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Logging;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Mediation;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Quartz;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.UserAccess;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration\n{\n    public class RegistrationsStartup\n    {\n        private static IContainer _container;\n\n        public static void Initialize(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            string textEncryptionKey,\n            IEmailSender emailSender,\n            IEventsBus eventsBus,\n            long? internalProcessingPoolingInterval = null)\n        {\n            var moduleLogger = logger.ForContext(\"Module\", \"Registrations\");\n\n            ConfigureCompositionRoot(\n                connectionString,\n                executionContextAccessor,\n                logger,\n                emailsConfiguration,\n                textEncryptionKey,\n                emailSender,\n                eventsBus);\n\n            QuartzStartup.Initialize(moduleLogger, internalProcessingPoolingInterval);\n\n            EventsBusStartup.Initialize(moduleLogger);\n        }\n\n        private static void ConfigureCompositionRoot(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            string textEncryptionKey,\n            IEmailSender emailSender,\n            IEventsBus eventsBus)\n        {\n            var containerBuilder = new ContainerBuilder();\n\n            containerBuilder.RegisterModule(new LoggingModule(logger.ForContext(\"Module\", \"Registrations\")));\n\n            var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(logger);\n            containerBuilder.RegisterModule(new DataAccessModule(connectionString, loggerFactory));\n            containerBuilder.RegisterModule(new ProcessingModule());\n            containerBuilder.RegisterModule(new EventsBusModule(eventsBus));\n            containerBuilder.RegisterModule(new MediatorModule());\n            containerBuilder.RegisterModule(new UserAccessAutofacModule());\n\n            var domainNotificationsMap = new BiDictionary<string, Type>();\n            domainNotificationsMap.Add(\"NewUserRegisteredNotification\", typeof(NewUserRegisteredNotification));\n            domainNotificationsMap.Add(\"UserRegistrationConfirmedNotification\", typeof(UserRegistrationConfirmedNotification));\n            containerBuilder.RegisterModule(new OutboxModule(domainNotificationsMap));\n\n            containerBuilder.RegisterModule(new QuartzModule());\n            containerBuilder.RegisterModule(new DomainModule());\n            containerBuilder.RegisterModule(new EmailModule(emailsConfiguration, emailSender));\n            //// containerBuilder.RegisterModule(new SecurityModule(textEncryptionKey));\n\n            containerBuilder.RegisterInstance(executionContextAccessor);\n\n            _container = containerBuilder.Build();\n\n            RegistrationsCompositionRoot.SetContainer(_container);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Configuration/UserAccess/UserAccessAutofacModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.UserAccess\n{\n    public class UserAccessAutofacModule : Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<UserAccessModule>()\n                .As<IUserAccessModule>()\n                .InstancePerLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Domain/UserRegistrations/UserRegistrationEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Domain.UserRegistrations\n{\n    internal class UserRegistrationEntityTypeConfiguration : IEntityTypeConfiguration<UserRegistration>\n    {\n        public void Configure(EntityTypeBuilder<UserRegistration> builder)\n        {\n            builder.ToTable(\"UserRegistrations\", \"registrations\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_login\").HasColumnName(\"Login\");\n            builder.Property<string>(\"_email\").HasColumnName(\"Email\");\n            builder.Property<string>(\"_password\").HasColumnName(\"Password\");\n            builder.Property<string>(\"_firstName\").HasColumnName(\"FirstName\");\n            builder.Property<string>(\"_lastName\").HasColumnName(\"LastName\");\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n            builder.Property<DateTime>(\"_registerDate\").HasColumnName(\"RegisterDate\");\n            builder.Property<DateTime?>(\"_confirmedDate\").HasColumnName(\"ConfirmedDate\");\n\n            builder.OwnsOne<UserRegistrationStatus>(\"_status\", b =>\n                {\n                    b.Property(x => x.Value).HasColumnName(\"StatusCode\");\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Domain/UserRegistrations/UserRegistrationRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Domain.UserRegistrations\n{\n    public class UserRegistrationRepository : IUserRegistrationRepository\n    {\n        private readonly RegistrationsContext _context;\n\n        public UserRegistrationRepository(RegistrationsContext context)\n        {\n            _context = context;\n        }\n\n        public async Task AddAsync(UserRegistration userRegistration)\n        {\n            await _context.AddAsync(userRegistration);\n        }\n\n        public async Task<UserRegistration> GetByIdAsync(UserRegistrationId userRegistrationId)\n        {\n            return await _context.UserRegistrations.FirstOrDefaultAsync(x => x.Id == userRegistrationId);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/InternalCommands/InternalCommandEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.InternalCommands\n{\n    internal class InternalCommandEntityTypeConfiguration : IEntityTypeConfiguration<InternalCommand>\n    {\n        public void Configure(EntityTypeBuilder<InternalCommand> builder)\n        {\n            builder.ToTable(\"InternalCommands\", \"registrations\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Outbox/OutboxAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Outbox\n{\n    public class OutboxAccessor : IOutbox\n    {\n        private readonly RegistrationsContext _userAccessContext;\n\n        public OutboxAccessor(RegistrationsContext userAccessContext)\n        {\n            _userAccessContext = userAccessContext;\n        }\n\n        public void Add(OutboxMessage message)\n        {\n            _userAccessContext.OutboxMessages.Add(message);\n        }\n\n        public Task Save()\n        {\n            return Task.CompletedTask; // Save is done automatically using EF Core Change Tracking mechanism during SaveChanges.\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Outbox/OutboxMessageEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Outbox\n{\n    internal class OutboxMessageEntityTypeConfiguration : IEntityTypeConfiguration<OutboxMessage>\n    {\n        public void Configure(EntityTypeBuilder<OutboxMessage> builder)\n        {\n            builder.ToTable(\"OutboxMessages\", \"registrations\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/RegistrationsContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Domain.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure\n{\n    public class RegistrationsContext : DbContext\n    {\n        public DbSet<UserRegistration> UserRegistrations { get; set; }\n\n        public DbSet<OutboxMessage> OutboxMessages { get; set; }\n\n        public DbSet<InternalCommand> InternalCommands { get; set; }\n\n        private readonly ILoggerFactory _loggerFactory;\n\n        public RegistrationsContext(DbContextOptions options, ILoggerFactory loggerFactory)\n            : base(options)\n        {\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.ApplyConfiguration(new UserRegistrationEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new OutboxMessageEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new InternalCommandEntityTypeConfiguration());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/RegistrationsModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure\n{\n    public class RegistrationsModule : IRegistrationsModule\n    {\n        public async Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command)\n        {\n            return await CommandsExecutor.Execute(command);\n        }\n\n        public async Task ExecuteCommandAsync(ICommand command)\n        {\n            await CommandsExecutor.Execute(command);\n        }\n\n        public async Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)\n        {\n            using (var scope = RegistrationsCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n\n                return await mediator.Send(query);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Infrastructure/Users/UserAccessGateway.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.CreateUser;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Users;\n\npublic class UserAccessGateway : IUserCreator\n{\n    private readonly IUserAccessModule _userAccessModule;\n\n    public UserAccessGateway(IUserAccessModule userAccessModule)\n    {\n        _userAccessModule = userAccessModule;\n    }\n\n    public async Task Create(\n        Guid userRegistrationId,\n        string login,\n        string password,\n        string email,\n        string firstName,\n        string lastName)\n    {\n        await _userAccessModule.ExecuteCommandAsync(new CreateUserCommand(\n            userRegistrationId,\n            login,\n            email,\n            firstName,\n            lastName,\n            password));\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/IntegrationEvents/Class1.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents;\n\npublic class Class1\n{\n}"
  },
  {
    "path": "src/Modules/Registrations/IntegrationEvents/CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/Registrations/IntegrationEvents/NewUserRegisteredIntegrationEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.IntegrationEvents\n{\n    public class NewUserRegisteredIntegrationEvent : IntegrationEvent\n    {\n        public Guid UserId { get; }\n\n        public string Login { get; }\n\n        public string Email { get; }\n\n        public string FirstName { get; }\n\n        public string LastName { get; }\n\n        public string Name { get; }\n\n        public NewUserRegisteredIntegrationEvent(Guid id, DateTime occurredOn, Guid userId, string login, string email, string firstName, string lastName, string name)\n            : base(id, occurredOn)\n        {\n            UserId = userId;\n            Login = login;\n            Email = email;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/Registrations/Tests/ArchTests/Application/ApplicationTests.cs",
    "content": "using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.ArchTests.SeedWork;\nusing FluentValidation;\nusing MediatR;\nusing NetArchTest.Rules;\nusing Newtonsoft.Json;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.ArchTests.Application\n{\n    [TestFixture]\n    public class ApplicationTests : TestBase\n    {\n        [Test]\n        public void Command_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(CommandBase))\n                .Or()\n                .Inherit(typeof(CommandBase<>))\n                .Or()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .Or()\n                .ImplementInterface(typeof(ICommand))\n                .Or()\n                .ImplementInterface(typeof(ICommand<>))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Query_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(typeof(IQuery<>)).GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void CommandHandler_Should_Have_Name_EndingWith_CommandHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(ICommandHandler<>))\n                    .Or()\n                .ImplementInterface(typeof(ICommandHandler<,>))\n                .And()\n                .DoNotHaveNameMatching(\".*Decorator.*\").Should()\n                .HaveNameEndingWith(\"CommandHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void QueryHandler_Should_Have_Name_EndingWith_QueryHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(IQueryHandler<,>))\n                .Should()\n                .HaveNameEndingWith(\"QueryHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Command_And_Query_Handlers_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                    .ImplementInterface(typeof(IQueryHandler<,>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<,>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void Validator_Should_Have_Name_EndingWith_Validator()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should()\n                .HaveNameEndingWith(\"Validator\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Validators_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void InternalCommand_Should_Have_JsonConstructorAttribute()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n\n            foreach (var type in types)\n            {\n                bool hasJsonConstructorDefined = false;\n                var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var jsonConstructorAttribute = constructorInfo.GetCustomAttributes(typeof(JsonConstructorAttribute), false);\n                    if (jsonConstructorAttribute.Length > 0)\n                    {\n                        hasJsonConstructorDefined = true;\n                        break;\n                    }\n                }\n\n                if (!hasJsonConstructorDefined)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void MediatR_RequestHandler_Should_NotBe_Used_Directly()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().DoNotHaveName(\"ICommandHandler`1\")\n                .Should().ImplementInterface(typeof(IRequestHandler<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                bool isCommandHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));\n                bool isCommandWithResultHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<,>));\n                bool isQueryHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(IQueryHandler<,>));\n                if (!isCommandHandler && !isCommandWithResultHandler && !isQueryHandler)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Command_With_Result_Should_Not_Return_Unit()\n        {\n            Type commandWithResultHandlerType = typeof(ICommandHandler<,>);\n            IEnumerable<Type> types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(commandWithResultHandlerType)\n                .GetTypes().ToList();\n\n            List<Type> failingTypes = [];\n            foreach (Type type in types)\n            {\n                Type interfaceType = type.GetInterface(commandWithResultHandlerType.Name);\n                if (interfaceType?.GenericTypeArguments[1] == typeof(Unit))\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/ArchTests/CompanyName.MyMeetings.Modules.Registrations.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Registrations/Tests/ArchTests/Domain/DomainTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.Registrations.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.ArchTests.Domain\n{\n    public class DomainTests : TestBase\n    {\n        [Test]\n        public void DomainEvent_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                    .Inherit(typeof(DomainEventBase))\n                        .Or()\n                    .ImplementInterface(typeof(IDomainEvent))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void ValueObject_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Entity_Which_Is_Not_Aggregate_Root_Cannot_Have_Public_Members()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity))\n                .And().DoNotImplementInterface(typeof(IAggregateRoot)).GetTypes();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.Public |\n                                              BindingFlags.Instance |\n                                              BindingFlags.Static;\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                var publicFields = type.GetFields(bindingFlags);\n                var publicProperties = type.GetProperties(bindingFlags);\n                var publicMethods = type.GetMethods(bindingFlags);\n\n                if (publicFields.Any() || publicProperties.Any() || publicMethods.Any())\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Cannot_Have_Reference_To_Other_AggregateRoot()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            var aggregateRoots = Types.InAssembly(DomainAssembly)\n                .That().ImplementInterface(typeof(IAggregateRoot)).GetTypes().ToList();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.NonPublic |\n                                              BindingFlags.Instance;\n\n            List<Type> failingTypes = [];\n            foreach (var type in entityTypes)\n            {\n                var fields = type.GetFields(bindingFlags);\n\n                foreach (var field in fields)\n                {\n                    if (aggregateRoots.Contains(field.FieldType) ||\n                        field.FieldType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n\n                var properties = type.GetProperties(bindingFlags);\n                foreach (var property in properties)\n                {\n                    if (aggregateRoots.Contains(property.PropertyType) ||\n                        property.PropertyType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Should_Have_Parameterless_Private_Constructor()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in entityTypes)\n            {\n                bool hasPrivateParameterlessConstructor = false;\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (constructorInfo.IsPrivate && constructorInfo.GetParameters().Length == 0)\n                    {\n                        hasPrivateParameterlessConstructor = true;\n                    }\n                }\n\n                if (!hasPrivateParameterlessConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Domain_Object_Should_Have_Only_Private_Constructors()\n        {\n            var domainObjectTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                        .Inherit(typeof(Entity))\n                    .Or()\n                        .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var domainObjectType in domainObjectTypes)\n            {\n                var constructors = domainObjectType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (!constructorInfo.IsPrivate)\n                    {\n                        failingTypes.Add(domainObjectType);\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void ValueObject_Should_Have_Private_Constructor_With_Parameters_For_His_State()\n        {\n            var valueObjects = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in valueObjects)\n            {\n                bool hasExpectedConstructor = false;\n\n                const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                                  BindingFlags.Public |\n                                                  BindingFlags.Instance;\n                var names = entityType.GetFields(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                var propertyNames = entityType.GetProperties(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                names.AddRange(propertyNames);\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var parameters = constructorInfo.GetParameters().Select(x => x.Name.ToLower()).ToList();\n\n                    if (names.Intersect(parameters).Count() == names.Count)\n                    {\n                        hasExpectedConstructor = true;\n                        break;\n                    }\n                }\n\n                if (!hasExpectedConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void DomainEvent_Should_Have_DomainEventPostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(DomainEventBase))\n                .Or()\n                .ImplementInterface(typeof(IDomainEvent))\n                .Should().HaveNameEndingWith(\"DomainEvent\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void BusinessRule_Should_Have_RulePostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .ImplementInterface(typeof(IBusinessRule))\n                .Should().HaveNameEndingWith(\"Rule\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/ArchTests/Module/LayersTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.ArchTests.Module\n{\n    [TestFixture]\n    public class LayersTests : TestBase\n    {\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToApplicationLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void ApplicationLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .Should()\n                .NotHaveDependencyOn(InfrastructureAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApplicationAssembly => typeof(CommandBase).Assembly;\n\n        protected static Assembly DomainAssembly => typeof(UserRegistration).Assembly;\n\n        protected static Assembly InfrastructureAssembly => typeof(RegistrationsContext).Assembly;\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; private set; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n\n        public void SetUserId(Guid userId)\n        {\n            this.UserId = userId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/SeedWork/OutboxMessagesHelper.cs",
    "content": "﻿using System.Data;\nusing System.Reflection;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration.Processing.Outbox;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork\n{\n    public class OutboxMessagesHelper\n    {\n        public static async Task<List<OutboxMessageDto>> GetOutboxMessages(IDbConnection connection)\n        {\n            const string sql = $\"\"\"\n                               SELECT \n                                   [OutboxMessage].[Id] as [{nameof(OutboxMessageDto.Id)}], \n                                   [OutboxMessage].[Type] as [{nameof(OutboxMessageDto.Type)}], \n                                   [OutboxMessage].[Data] as [{nameof(OutboxMessageDto.Data)}] \n                               FROM [registrations].[OutboxMessages] AS [OutboxMessage] \n                               ORDER BY [OutboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            return messages.AsList();\n        }\n\n        public static T Deserialize<T>(OutboxMessageDto message)\n            where T : class, INotification\n        {\n            Type type = Assembly.GetAssembly(typeof(CommandBase)).GetType(typeof(T).FullName);\n            return JsonConvert.DeserializeObject(message.Data, type) as T;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration;\nusing Dapper;\nusing MediatR;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IRegistrationsModule RegistrationsModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = Substitute.For<ILogger>();\n            EmailSender = Substitute.For<IEmailSender>();\n\n            RegistrationsStartup.Initialize(\n                ConnectionString,\n                new ExecutionContextMock(Guid.NewGuid()),\n                Logger,\n                new EmailsConfiguration(\"from@email.com\"),\n                \"key\",\n                EmailSender,\n                null);\n\n            RegistrationsModule = new RegistrationsModule();\n        }\n\n        protected async Task<T> GetLastOutboxMessage<T>()\n            where T : class, INotification\n        {\n            using (var connection = new SqlConnection(ConnectionString))\n            {\n                var messages = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n                return OutboxMessagesHelper.Deserialize<T>(messages.Last());\n            }\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [registrations].[InboxMessages] \" +\n                               \"DELETE FROM [registrations].[InternalCommands] \" +\n                               \"DELETE FROM [registrations].[OutboxMessages] \" +\n                               \"DELETE FROM [registrations].[UserRegistrations] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/UserRegistrations/ConfirmUserRegistrationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.UserRegistrations\n{\n    [TestFixture]\n    public class ConfirmUserRegistrationTests : TestBase\n    {\n        [Test]\n        public async Task ConfirmUserRegistration_Test()\n        {\n            var registrationId = await RegistrationsModule.ExecuteCommandAsync(new RegisterNewUserCommand(\n                UserRegistrationSampleData.Login,\n                UserRegistrationSampleData.Password,\n                UserRegistrationSampleData.Email,\n                UserRegistrationSampleData.FirstName,\n                UserRegistrationSampleData.LastName,\n                \"confirmLink\"));\n\n            await RegistrationsModule.ExecuteCommandAsync(new ConfirmUserRegistrationCommand(registrationId));\n\n            var userRegistration = await RegistrationsModule.ExecuteQueryAsync(new GetUserRegistrationQuery(registrationId));\n\n            Assert.That(userRegistration.StatusCode, Is.EqualTo(UserRegistrationStatus.Confirmed.Value));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/UserRegistrations/SendUserRegistrationConfirmationEmailTests.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.SendUserRegistrationConfirmationEmail;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork;\nusing NSubstitute.ReceivedExtensions;\nusing NUnit.Framework;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.UserRegistrations\n{\n    [TestFixture]\n    public class SendUserRegistrationConfirmationEmailTests : TestBase\n    {\n        [Test]\n        public async Task SendUserRegistrationConfirmationEmail_Test()\n        {\n            var registrationId = Guid.NewGuid();\n\n            var confirmLink = \"confirmLink/\";\n            await RegistrationsModule.ExecuteCommandAsync(new SendUserRegistrationConfirmationEmailCommand(\n                Guid.NewGuid(),\n                new UserRegistrationId(registrationId),\n                UserRegistrationSampleData.Email,\n                confirmLink));\n            string link = $\"<a href=\\\"{confirmLink}{registrationId}\\\">link</a>\";\n            var content = $\"Welcome to MyMeetings application! Please confirm your registration using this {link}.\";\n            var email = new EmailMessage(\n                UserRegistrationSampleData.Email,\n                \"MyMeetings - Please confirm your registration\",\n                content);\n\n            await EmailSender.Received(Quantity.Exactly(1)).SendEmail(email);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/UserRegistrations/UserRegistrationSampleData.cs",
    "content": "﻿namespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.UserRegistrations\n{\n    public struct UserRegistrationSampleData\n    {\n        public static string Login => \"jdoe\";\n\n        public static string Email => \"jdoe@mail.com\";\n\n        public static string FirstName => \"John\";\n\n        public static string LastName => \"Doe\";\n\n        public static string Password => \"qwerty\";\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/IntegrationTests/UserRegistrations/UserRegistrationTests.cs",
    "content": "﻿using System.Data.SqlClient;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.GetUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser;\nusing CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyNames.MyMeetings.Modules.Registrations.IntegrationTests.UserRegistrations\n{\n    [TestFixture]\n    public class UserRegistrationTests : TestBase\n    {\n        [Test]\n        public async Task RegisterNewUserCommand_Test()\n        {\n            var registrationId = await RegistrationsModule.ExecuteCommandAsync(new RegisterNewUserCommand(\n                UserRegistrationSampleData.Login,\n                UserRegistrationSampleData.Password,\n                UserRegistrationSampleData.Email,\n                UserRegistrationSampleData.FirstName,\n                UserRegistrationSampleData.LastName,\n                \"confirmLink\"));\n\n            var userRegistration = await RegistrationsModule.ExecuteQueryAsync(new GetUserRegistrationQuery(registrationId));\n\n            Assert.That(userRegistration.Email, Is.EqualTo(UserRegistrationSampleData.Email));\n            Assert.That(userRegistration.Login, Is.EqualTo(UserRegistrationSampleData.Login));\n            Assert.That(userRegistration.FirstName, Is.EqualTo(UserRegistrationSampleData.FirstName));\n            Assert.That(userRegistration.LastName, Is.EqualTo(UserRegistrationSampleData.LastName));\n\n            var connection = new SqlConnection(ConnectionString);\n            var messagesList = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n            Assert.That(messagesList.Count, Is.EqualTo(1));\n\n            var newUserRegisteredNotification =\n                await GetLastOutboxMessage<NewUserRegisteredNotification>();\n\n            Assert.That(newUserRegisteredNotification.DomainEvent.Login, Is.EqualTo(UserRegistrationSampleData.Login));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/UnitTests/CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/Registrations/Tests/UnitTests/SeedWork/DomainEventsTestHelper.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.SeedWork\n{\n    public class DomainEventsTestHelper\n    {\n        public static List<IDomainEvent> GetAllDomainEvents(Entity aggregate)\n        {\n            List<IDomainEvent> domainEvents = [];\n\n            if (aggregate.DomainEvents != null)\n            {\n                domainEvents.AddRange(aggregate.DomainEvents);\n            }\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = typeof(Entity).IsAssignableFrom(field.FieldType);\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    domainEvents.AddRange(GetAllDomainEvents(entity).ToList());\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                domainEvents.AddRange(GetAllDomainEvents(entityItem));\n                            }\n                        }\n                    }\n                }\n            }\n\n            return domainEvents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/UnitTests/SeedWork/TestBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        public static T AssertPublishedDomainEvent<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static void AssertBrokenRule<TRule>(TestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.Catch<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/Registrations/Tests/UnitTests/UserRegistrations/UserRegistrationTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.SeedWork;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Events;\nusing CompanyName.MyMeetings.Modules.Registrations.Domain.UserRegistrations.Rules;\nusing NSubstitute;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.Registrations.Domain.UnitTests.UserRegistrations\n{\n    [TestFixture]\n    public class UserRegistrationTests : TestBase\n    {\n        [Test]\n        public void NewUserRegistration_WithUniqueLogin_IsSuccessful()\n        {\n            // Arrange\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            // Act\n            var userRegistration =\n                UserRegistration.RegisterNewUser(\n                    \"login\",\n                    \"password\",\n                    \"test@email\",\n                    \"firstName\",\n                    \"lastName\",\n                    usersCounter,\n                    \"confirmLink\");\n\n            // Assert\n            var newUserRegisteredDomainEvent =\n                AssertPublishedDomainEvent<NewUserRegisteredDomainEvent>(userRegistration);\n            Assert.That(newUserRegisteredDomainEvent.UserRegistrationId, Is.EqualTo(userRegistration.Id));\n        }\n\n        [Test]\n        public void NewUserRegistration_WithoutUniqueLogin_BreaksUserLoginMustBeUniqueRule()\n        {\n            // Arrange\n            var usersCounter = Substitute.For<IUsersCounter>();\n            usersCounter.CountUsersWithLogin(\"login\").Returns(x => 1);\n\n            // Assert\n            AssertBrokenRule<UserLoginMustBeUniqueRule>(() =>\n            {\n                // Act\n                UserRegistration.RegisterNewUser(\n                    \"login\",\n                    \"password\",\n                    \"test@email\",\n                    \"firstName\",\n                    \"lastName\",\n                    usersCounter,\n                    \"confirmLink\");\n            });\n        }\n\n        [Test]\n        public void ConfirmingUserRegistration_WhenWaitingForConfirmation_IsSuccessful()\n        {\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            var registration = UserRegistration.RegisterNewUser(\n                \"login\",\n                \"password\",\n                \"test@email\",\n                \"firstName\",\n                \"lastName\",\n                usersCounter,\n                \"confirmLink\");\n\n            registration.Confirm();\n\n            var userRegistrationConfirmedDomainEvent =\n                AssertPublishedDomainEvent<UserRegistrationConfirmedDomainEvent>(registration);\n\n            Assert.That(userRegistrationConfirmedDomainEvent.UserRegistrationId, Is.EqualTo(registration.Id));\n        }\n\n        [Test]\n        public void UserRegistration_WhenIsConfirmed_CannotBeConfirmedAgain()\n        {\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            var registration = UserRegistration.RegisterNewUser(\n                \"login\",\n                \"password\",\n                \"test@email\",\n                \"firstName\",\n                \"lastName\",\n                usersCounter,\n                \"confirmLink\");\n\n            registration.Confirm();\n\n            AssertBrokenRule<UserRegistrationCannotBeConfirmedMoreThanOnceRule>(() => { registration.Confirm(); });\n        }\n\n        [Test]\n        public void UserRegistration_WhenIsExpired_CannotBeConfirmed()\n        {\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            var registration = UserRegistration.RegisterNewUser(\n                \"login\",\n                \"password\",\n                \"test@email\",\n                \"firstName\",\n                \"lastName\",\n                usersCounter,\n                \"confirmLink\");\n\n            registration.Expire();\n\n            AssertBrokenRule<UserRegistrationCannotBeConfirmedAfterExpirationRule>(() => { registration.Confirm(); });\n        }\n\n        [Test]\n        public void ExpiringUserRegistration_WhenWaitingForConfirmation_IsSuccessful()\n        {\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            var registration = UserRegistration.RegisterNewUser(\n                \"login\",\n                \"password\",\n                \"test@email\",\n                \"firstName\",\n                \"lastName\",\n                usersCounter,\n                \"confirmLink\");\n\n            registration.Expire();\n\n            var userRegistrationExpired = AssertPublishedDomainEvent<UserRegistrationExpiredDomainEvent>(registration);\n\n            Assert.That(userRegistrationExpired.UserRegistrationId, Is.EqualTo(registration.Id));\n        }\n\n        [Test]\n        public void UserRegistration_WhenIsExpired_CannotBeExpiredAgain()\n        {\n            var usersCounter = Substitute.For<IUsersCounter>();\n\n            var registration = UserRegistration.RegisterNewUser(\n                \"login\",\n                \"password\",\n                \"test@email\",\n                \"firstName\",\n                \"lastName\",\n                usersCounter,\n                \"confirmLink\");\n\n            registration.Expire();\n\n            AssertBrokenRule<UserRegistrationCannotBeExpiredMoreThanOnceRule>(() => { registration.Expire(); });\n        }\n\n        // [Test]\n        // public void CreateUser_WhenRegistrationIsConfirmed_IsSuccessful()\n        // {\n        //     var usersCounter = Substitute.For<IUsersCounter>();\n        //\n        //     var registration = UserRegistration.RegisterNewUser(\n        //         \"login\",\n        //         \"password\",\n        //         \"test@email\",\n        //         \"firstName\",\n        //         \"lastName\",\n        //         usersCounter,\n        //         \"confirmLink\");\n        //\n        //     registration.Confirm();\n        //\n        //     var user = registration.CreateUser();\n        //\n        //     var userCreated = AssertPublishedDomainEvent<UserCreatedDomainEvent>(user);\n        //\n        //     Assert.That(user.Id, Is.EqualTo(registration.Id));\n        //     Assert.That(userCreated.Id, Is.EqualTo(registration.Id));\n        //// }\n\n        // [Test]\n        // public void UserCreation_WhenRegistrationIsNotConfirmed_IsNotPossible()\n        // {\n        //     var usersCounter = Substitute.For<IUsersCounter>();\n        //\n        //     var registration = UserRegistration.RegisterNewUser(\n        //         \"login\",\n        //         \"password\",\n        //         \"test@email\",\n        //         \"firstName\",\n        //         \"lastName\",\n        //         usersCounter,\n        //         \"confirmLink\");\n        //\n        //     AssertBrokenRule<UserCannotBeCreatedWhenRegistrationIsNotConfirmedRule>(\n        //         () => { registration.CreateUser(); });\n        // }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/AuthenticateCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    public class AuthenticateCommand : CommandBase<AuthenticationResult>\n    {\n        public AuthenticateCommand(string login, string password)\n        {\n            Login = login;\n            Password = password;\n        }\n\n        public string Login { get; }\n\n        public string Password { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/AuthenticateCommandHandler.cs",
    "content": "﻿using System.Security.Claims;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    internal class AuthenticateCommandHandler : ICommandHandler<AuthenticateCommand, AuthenticationResult>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        internal AuthenticateCommandHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<AuthenticationResult> Handle(AuthenticateCommand request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                   [User].[Id] as [{nameof(UserDto.Id)}],\n                                   [User].[Login] as [{nameof(UserDto.Login)}],\n                                   [User].[Name] as [{nameof(UserDto.Name)}],\n                                   [User].[Email] as [{nameof(UserDto.Email)}],\n                                   [User].[IsActive] as [{nameof(UserDto.IsActive)}],\n                                   [User].[Password]  as [{nameof(UserDto.Password)}]\n                               FROM [users].[v_Users] AS [User] \n                               WHERE [User].[Login] = @Login\n                               \"\"\";\n\n            var user = await connection.QuerySingleOrDefaultAsync<UserDto>(\n                sql,\n                new\n                {\n                    request.Login,\n                });\n\n            if (user == null)\n            {\n                return new AuthenticationResult(\"Incorrect login or password\");\n            }\n\n            if (!user.IsActive)\n            {\n                return new AuthenticationResult(\"User is not active\");\n            }\n\n            if (!PasswordManager.VerifyHashedPassword(user.Password, request.Password))\n            {\n                return new AuthenticationResult(\"Incorrect login or password\");\n            }\n\n            user.Claims =\n            [\n                new Claim(CustomClaimTypes.Name, user.Name),\n                new Claim(CustomClaimTypes.Email, user.Email)\n            ];\n\n            return new AuthenticationResult(user);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/AuthenticateCommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    internal class AuthenticateCommandValidator : AbstractValidator<AuthenticateCommand>\n    {\n        public AuthenticateCommandValidator()\n        {\n            this.RuleFor(x => x.Login).NotEmpty().WithMessage(\"Login cannot be empty\");\n            this.RuleFor(x => x.Password).NotEmpty().WithMessage(\"Password cannot be empty\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/AuthenticationResult.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    public class AuthenticationResult\n    {\n        public AuthenticationResult(string authenticationError)\n        {\n            IsAuthenticated = false;\n            AuthenticationError = authenticationError;\n        }\n\n        public AuthenticationResult(UserDto user)\n        {\n            this.IsAuthenticated = true;\n            this.User = user;\n        }\n\n        public bool IsAuthenticated { get; }\n\n        public string AuthenticationError { get; }\n\n        public UserDto User { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/PasswordManager.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Security.Cryptography;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    public class PasswordManager\n    {\n        public static string HashPassword(string password)\n        {\n            byte[] salt;\n            byte[] buffer2;\n            if (password == null)\n            {\n                throw new ArgumentNullException(nameof(password));\n            }\n\n            using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8, HashAlgorithmName.SHA256))\n            {\n                salt = bytes.Salt;\n                buffer2 = bytes.GetBytes(0x20);\n            }\n\n            byte[] dst = new byte[0x31];\n            Buffer.BlockCopy(salt, 0, dst, 1, 0x10);\n            Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);\n            return Convert.ToBase64String(dst);\n        }\n\n        public static bool VerifyHashedPassword(string hashedPassword, string password)\n        {\n            byte[] buffer4;\n            if (hashedPassword == null)\n            {\n                return false;\n            }\n\n            if (password == null)\n            {\n                throw new ArgumentNullException(nameof(password));\n            }\n\n            byte[] src = Convert.FromBase64String(hashedPassword);\n            if ((src.Length != 0x31) || (src[0] != 0))\n            {\n                return false;\n            }\n\n            byte[] dst = new byte[0x10];\n            Buffer.BlockCopy(src, 1, dst, 0, 0x10);\n            byte[] buffer3 = new byte[0x20];\n            Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);\n            using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 0x3e8, HashAlgorithmName.SHA256))\n            {\n                buffer4 = bytes.GetBytes(0x20);\n            }\n\n            return ByteArraysEqual(buffer3, buffer4);\n        }\n\n        [MethodImpl(MethodImplOptions.NoOptimization)]\n        private static bool ByteArraysEqual(byte[] a, byte[] b)\n        {\n            if (ReferenceEquals(a, b))\n            {\n                return true;\n            }\n\n            if (a == null || b == null || a.Length != b.Length)\n            {\n                return false;\n            }\n\n            var areSame = true;\n            for (var i = 0; i < a.Length; i++)\n            {\n                areSame &= a[i] == b[i];\n            }\n\n            return areSame;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authentication/Authenticate/UserDto.cs",
    "content": "﻿using System.Security.Claims;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate\n{\n    public class UserDto\n    {\n        public Guid Id { get; set; }\n\n        public string Login { get; set; }\n\n        public bool IsActive { get; set; }\n\n        public string Name { get; set; }\n\n        public string Email { get; set; }\n\n        public List<Claim> Claims { get; set; }\n\n        public string Password { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authorization/GetAuthenticatedUserPermissions/GetAuthenticatedUserPermissionsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetAuthenticatedUserPermissions\n{\n    public class GetAuthenticatedUserPermissionsQuery : QueryBase<List<UserPermissionDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authorization/GetAuthenticatedUserPermissions/GetAuthenticatedUserPermissionsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetAuthenticatedUserPermissions\n{\n    internal class GetAuthenticatedUserPermissionsQueryHandler : IQueryHandler<GetAuthenticatedUserPermissionsQuery, List<UserPermissionDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public GetAuthenticatedUserPermissionsQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _executionContextAccessor = executionContextAccessor;\n        }\n\n        public async Task<List<UserPermissionDto>> Handle(GetAuthenticatedUserPermissionsQuery request, CancellationToken cancellationToken)\n        {\n            if (!_executionContextAccessor.IsAvailable)\n            {\n                return [];\n            }\n\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\" \n                               SELECT [UserPermission].[PermissionCode] AS [{nameof(UserPermissionDto.Code)}]\n                               FROM [users].[v_UserPermissions] AS [UserPermission] \n                               WHERE [UserPermission].UserId = @UserId\n                               \"\"\";\n\n            var permissions = await connection.QueryAsync<UserPermissionDto>(\n                sql,\n                new { _executionContextAccessor.UserId });\n\n            return permissions.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authorization/GetUserPermissions/GetUserPermissionsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions\n{\n    public class GetUserPermissionsQuery : QueryBase<List<UserPermissionDto>>\n    {\n        public GetUserPermissionsQuery(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authorization/GetUserPermissions/GetUserPermissionsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions\n{\n    internal class GetUserPermissionsQueryHandler : IQueryHandler<GetUserPermissionsQuery, List<UserPermissionDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetUserPermissionsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<UserPermissionDto>> Handle(GetUserPermissionsQuery request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT [UserPermission].[PermissionCode] AS [{nameof(UserPermissionDto.Code)}]\n                                FROM [users].[v_UserPermissions] AS [UserPermission] \n                                WHERE [UserPermission].UserId = @UserId\n                                \"\"\";\n            var permissions = await connection.QueryAsync<UserPermissionDto>(sql, new { request.UserId });\n\n            return permissions.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Authorization/GetUserPermissions/UserPermissionDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Authorization.GetUserPermissions\n{\n    public class UserPermissionDto\n    {\n        public string Code { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/CompanyName.MyMeetings.Modules.UserAccess.Application.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Meetings\\IntegrationEvents\\CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Modules/UserAccess/Application/Configuration/Commands/ICommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands\n{\n    public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>\n        where TCommand : ICommand\n    {\n    }\n\n    public interface ICommandHandler<in TCommand, TResult> :\n        IRequestHandler<TCommand, TResult>\n        where TCommand : ICommand<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Configuration/Commands/ICommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands\n{\n    public interface ICommandsScheduler\n    {\n        Task EnqueueAsync(ICommand command);\n\n        Task EnqueueAsync<T>(ICommand<T> command);\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Configuration/Commands/InternalCommandBase.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands\n{\n    public abstract class InternalCommandBase : ICommand\n    {\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n\n    public abstract class InternalCommandBase<TResult> : ICommand<TResult>\n    {\n        protected InternalCommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected InternalCommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Configuration/Queries/IQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries\n{\n    public interface IQueryHandler<in TQuery, TResult> :\n        IRequestHandler<TQuery, TResult>\n        where TQuery : IQuery<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/CommandBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public abstract class CommandBase : ICommand\n    {\n        public Guid Id { get; }\n\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n\n    public abstract class CommandBase<TResult> : ICommand<TResult>\n    {\n        protected CommandBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected CommandBase(Guid id)\n        {\n            Id = id;\n        }\n\n        public Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/CustomClaimTypes.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public class CustomClaimTypes\n    {\n        public const string Roles = \"roles\";\n        public const string Email = \"email\";\n        public const string Name = \"name\";\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/ICommand.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public interface ICommand<out TResult> : IRequest<TResult>\n    {\n        Guid Id { get; }\n    }\n\n    public interface ICommand : IRequest\n    {\n        Guid Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/IQuery.cs",
    "content": "﻿using MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public interface IQuery<out TResult> : IRequest<TResult>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/IUserAccessModule.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public interface IUserAccessModule\n    {\n        Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command);\n\n        Task ExecuteCommandAsync(ICommand command);\n\n        Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/QueryBase.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public abstract class QueryBase<TResult> : IQuery<TResult>\n    {\n        public Guid Id { get; }\n\n        protected QueryBase()\n        {\n            Id = Guid.NewGuid();\n        }\n\n        protected QueryBase(Guid id)\n        {\n            Id = id;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Contracts/Roles.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts\n{\n    public class Roles\n    {\n        public const string Admin = \"Admin\";\n        public const string User = \"User\";\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Emails/EmailDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Emails\n{\n    public class EmailDto\n    {\n        public Guid Id { get; set; }\n\n        public string From { get; set; }\n\n        public string To { get; set; }\n\n        public string Subject { get; set; }\n\n        public string Content { get; set; }\n\n        public DateTime Date { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Emails/GetAllEmailsQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Emails\n{\n    public class GetAllEmailsQuery : QueryBase<List<EmailDto>>\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Emails/GetAllEmailsQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Emails\n{\n    internal class GetAllEmailsQueryHandler : IQueryHandler<GetAllEmailsQuery, List<EmailDto>>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetAllEmailsQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<List<EmailDto>> Handle(GetAllEmailsQuery query, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                       SELECT \n                           [Email].[Id] AS [{nameof(EmailDto.Id)}], \n                           [Email].[From] AS [{nameof(EmailDto.From)}], \n                           [Email].[To] AS [{nameof(EmailDto.To)}],\n                           [Email].[Subject] AS [{nameof(EmailDto.Subject)}],\n                           [Email].[Content] AS [{nameof(EmailDto.Content)}],\n                           [Email].[Date] AS [{nameof(EmailDto.Date)}] \n                       FROM [app].[Emails] AS [Email] \n                       ORDER BY [Email].[Date] DESC\n                       \"\"\";\n            var result = await connection.QueryAsync<EmailDto>(sql);\n            return result.AsList();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/AddAdminUser/AddAdminUserCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.AddAdminUser\n{\n    public class AddAdminUserCommand : CommandBase\n    {\n        public AddAdminUserCommand(\n            string login,\n            string password,\n            string firstName,\n            string lastName,\n            string name,\n            string email)\n        {\n            Login = login;\n            Password = password;\n            FirstName = firstName;\n            LastName = lastName;\n            Name = name;\n            Email = email;\n        }\n\n        public string Login { get; }\n\n        public string FirstName { get; }\n\n        public string LastName { get; }\n\n        public string Name { get; }\n\n        public string Email { get; }\n\n        public string Password { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/AddAdminUser/AddAdminUserCommandHandler.cs",
    "content": "using CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.AddAdminUser\r\n{\r\n    internal class AddAdminUserCommandHandler : ICommandHandler<AddAdminUserCommand>\r\n    {\r\n        private readonly IUserRepository _userRepository;\r\n\r\n        public AddAdminUserCommandHandler(IUserRepository userRepository)\r\n        {\r\n            _userRepository = userRepository;\r\n        }\r\n\r\n        public async Task Handle(AddAdminUserCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var password = PasswordManager.HashPassword(command.Password);\r\n\r\n            var user = User.CreateAdmin(\r\n                command.Login,\r\n                password,\r\n                command.Email,\r\n                command.FirstName,\r\n                command.LastName,\r\n                command.Name);\r\n\r\n            await _userRepository.AddAsync(user);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/CreateUser/CreateUserCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.CreateUser;\n\npublic class CreateUserCommand : CommandBase\n{\n    public CreateUserCommand(\n        Guid userId,\n        string login,\n        string email,\n        string firstName,\n        string lastName,\n        string password)\n    {\n        UserId = userId;\n        Login = login;\n        Email = email;\n        FirstName = firstName;\n        LastName = lastName;\n        Password = password;\n    }\n\n    public Guid UserId { get; }\n\n    public string Login { get; }\n\n    public string Email { get; }\n\n    public string FirstName { get; }\n\n    public string LastName { get; }\n\n    public string Password { get; }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/CreateUser/CreateUserCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.CreateUser;\n\ninternal class CreateUserCommandHandler : ICommandHandler<CreateUserCommand>\n{\n    private readonly IUserRepository _userRepository;\n\n    public CreateUserCommandHandler(IUserRepository userRepository)\n    {\n        _userRepository = userRepository;\n    }\n\n    public async Task Handle(CreateUserCommand command, CancellationToken cancellationToken)\n    {\n        var user = User.CreateUser(\n            command.UserId,\n            command.Login,\n            command.Password,\n            command.Email,\n            command.FirstName,\n            command.LastName);\n\n        await _userRepository.AddAsync(user);\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/GetAuthenticatedUser/GetAuthenticatedUserQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetAuthenticatedUser\n{\n    public class GetAuthenticatedUserQuery : QueryBase<UserDto>\n    {\n        public GetAuthenticatedUserQuery()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/GetAuthenticatedUser/GetAuthenticatedUserQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetAuthenticatedUser\n{\n    internal class GetAuthenticatedUserQueryHandler : IQueryHandler<GetAuthenticatedUserQuery, UserDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n\n        public GetAuthenticatedUserQueryHandler(\n            ISqlConnectionFactory sqlConnectionFactory,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n            _executionContextAccessor = executionContextAccessor;\n        }\n\n        public async Task<UserDto> Handle(GetAuthenticatedUserQuery request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [User].[Id] as [{nameof(UserDto.Id)}], \n                                    [User].[IsActive] as [{nameof(UserDto.IsActive)}],\n                                    [User].[Login] as [{nameof(UserDto.Login)}],\n                                    [User].[Email] as [{nameof(UserDto.Email)}],\n                                    [User].[Name] as [{nameof(UserDto.Name)}]\n                                FROM [users].[v_Users] AS [User]\n                                WHERE [User].[Id] = @UserId\n                                \"\"\";\n\n            return await connection.QuerySingleAsync<UserDto>(sql, new\n            {\n                _executionContextAccessor.UserId\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/GetUser/GetUserQuery.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser\n{\n    public class GetUserQuery : QueryBase<UserDto>\n    {\n        public GetUserQuery(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/GetUser/GetUserQueryHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser\n{\n    internal class GetUserQueryHandler : IQueryHandler<GetUserQuery, UserDto>\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public GetUserQueryHandler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task<UserDto> Handle(GetUserQuery request, CancellationToken cancellationToken)\n        {\n            var connection = _sqlConnectionFactory.GetOpenConnection();\n\n            const string sql = $\"\"\"\n                                SELECT \n                                    [User].[Id] as [{nameof(UserDto.Id)}], \n                                    [User].[IsActive] as [{nameof(UserDto.IsActive)}], \n                                    [User].[Login] as [{nameof(UserDto.Login)}], \n                                    [User].[Email] as [{nameof(UserDto.Email)}], \n                                    [User].[Name] as [{nameof(UserDto.Name)}] \n                                FROM [users].[v_Users] AS [User] \n                                WHERE [User].[Id] = @UserId\n                                \"\"\";\n\n            return await connection.QuerySingleAsync<UserDto>(sql, new\n            {\n                request.UserId\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Application/Users/GetUser/UserDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser\n{\n    public class UserDto\n    {\n        public Guid Id { get; set; }\n\n        public bool IsActive { get; set; }\n\n        public string Name { get; set; }\n\n        public string Login { get; set; }\n\n        public string Email { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Domain/CompanyName.MyMeetings.Modules.UserAccess.Domain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/UserAccess/Domain/Users/Events/UserCreatedDomainEvent.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.Users.Events\n{\n    public class UserCreatedDomainEvent : DomainEventBase\n    {\n        public UserCreatedDomainEvent(UserId id)\n        {\n            Id = id;\n        }\n\n        public new UserId Id { get; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Domain/Users/IUserRepository.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Domain.Users\n{\n    public interface IUserRepository\n    {\n        Task AddAsync(User user);\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Domain/Users/User.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users.Events;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.Users\n{\n    public class User : Entity, IAggregateRoot\n    {\n        public UserId Id { get; private set; }\n\n        private string _login;\n\n        private string _password;\n\n        private string _email;\n\n#pragma warning disable CS0414 // Field is assigned but its value is never used\n        private bool _isActive;\n#pragma warning restore CS0414 // Field is assigned but its value is never used\n\n        private string _firstName;\n\n        private string _lastName;\n\n        private string _name;\n\n        private List<UserRole> _roles;\n\n        private User()\n        {\n            // Only for EF.\n        }\n\n        public static User CreateAdmin(\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName,\n            string name)\n        {\n            return new User(\n                Guid.NewGuid(),\n                login,\n                password,\n                email,\n                firstName,\n                lastName,\n                name,\n                UserRole.Administrator);\n        }\n\n        public static User CreateUser(\n            Guid userId,\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName)\n        {\n            return new User(\n                userId,\n                login,\n                password,\n                email,\n                firstName,\n                lastName,\n                $\"{firstName} {lastName}\",\n                UserRole.Member);\n        }\n\n        private User(\n            Guid id,\n            string login,\n            string password,\n            string email,\n            string firstName,\n            string lastName,\n            string name,\n            UserRole role)\n        {\n            this.Id = new UserId(id);\n            _login = login;\n            _password = password;\n            _email = email;\n            _firstName = firstName;\n            _lastName = lastName;\n            _name = name;\n\n            _isActive = true;\n\n            _roles = [role];\n\n            this.AddDomainEvent(new UserCreatedDomainEvent(this.Id));\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Domain/Users/UserId.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.Users\n{\n    public class UserId : TypedIdValueBase\n    {\n        public UserId(Guid value)\n            : base(value)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Domain/Users/UserRole.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.Users\n{\n    public class UserRole : ValueObject\n    {\n        public static UserRole Member => new UserRole(nameof(Member));\n\n        public static UserRole Administrator => new UserRole(nameof(Administrator));\n\n        public string Value { get; }\n\n        private UserRole(string value)\n        {\n            this.Value = value;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <ItemGroup>\n    <PackageReference Include=\"IdentityServer4\" Version=\"4.1.2\" />\n    <PackageReference Include=\"IdentityServer4.AccessTokenValidation\" Version=\"3.0.1\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/AllConstructorFinder.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing Autofac.Core.Activators.Reflection;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration\n{\n    internal class AllConstructorFinder : IConstructorFinder\n    {\n        private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =\n            new ConcurrentDictionary<Type, ConstructorInfo[]>();\n\n        public ConstructorInfo[] FindConstructors(Type targetType)\n        {\n            var result = Cache.GetOrAdd(\n                targetType,\n                t => t.GetTypeInfo().DeclaredConstructors.ToArray());\n\n            return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType, this);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Assemblies.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration\n{\n    internal static class Assemblies\n    {\n        public static readonly Assembly Application = typeof(IUserAccessModule).Assembly;\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/DataAccess/DataAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.DataAccess\n{\n    internal class DataAccessModule : Autofac.Module\n    {\n        private readonly string _databaseConnectionString;\n        private readonly ILoggerFactory _loggerFactory;\n\n        internal DataAccessModule(string databaseConnectionString, ILoggerFactory loggerFactory)\n        {\n            _databaseConnectionString = databaseConnectionString;\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<SqlConnectionFactory>()\n                .As<ISqlConnectionFactory>()\n                .WithParameter(\"connectionString\", _databaseConnectionString)\n                .InstancePerLifetimeScope();\n\n            builder\n                .Register(c =>\n                {\n                    var dbContextOptionsBuilder = new DbContextOptionsBuilder<UserAccessContext>();\n                    dbContextOptionsBuilder.UseSqlServer(_databaseConnectionString);\n\n                    dbContextOptionsBuilder\n                        .ReplaceService<IValueConverterSelector, StronglyTypedIdValueConverterSelector>();\n\n                    return new UserAccessContext(dbContextOptionsBuilder.Options, _loggerFactory);\n                })\n                .AsSelf()\n                .As<DbContext>()\n                .InstancePerLifetimeScope();\n\n            var infrastructureAssembly = typeof(UserAccessContext).Assembly;\n\n            builder.RegisterAssemblyTypes(infrastructureAssembly)\n                .Where(type => type.Name.EndsWith(\"Repository\"))\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Email/EmailModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Email\n{\n    internal class EmailModule : Module\n    {\n        private readonly IEmailSender _emailSender;\n        private readonly EmailsConfiguration _configuration;\n\n        public EmailModule(\n            EmailsConfiguration configuration,\n            IEmailSender emailSender)\n        {\n            _configuration = configuration;\n            _emailSender = emailSender;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_emailSender != null)\n            {\n                builder.RegisterInstance(_emailSender);\n            }\n            else\n            {\n                builder.RegisterType<EmailSender>()\n                    .As<IEmailSender>()\n                    .WithParameter(\"configuration\", _configuration)\n                    .InstancePerLifetimeScope();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/EventsBus/EventsBusModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.EventsBus\n{\n    internal class EventsBusModule : Autofac.Module\n    {\n        private readonly IEventsBus _eventsBus;\n\n        public EventsBusModule(IEventsBus eventsBus)\n        {\n            _eventsBus = eventsBus;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            if (_eventsBus != null)\n            {\n                builder.RegisterInstance(_eventsBus).SingleInstance();\n            }\n            else\n            {\n                builder.RegisterType<InMemoryEventBusClient>()\n                    .As<IEventsBus>()\n                    .SingleInstance();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/EventsBus/EventsBusStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Meetings.IntegrationEvents;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.EventsBus\n{\n    public static class EventsBusStartup\n    {\n        public static void Initialize(\n            ILogger logger)\n        {\n            SubscribeToIntegrationEvents(logger);\n        }\n\n        private static void SubscribeToIntegrationEvents(ILogger logger)\n        {\n            var eventBus = UserAccessCompositionRoot.BeginLifetimeScope().Resolve<IEventsBus>();\n\n            SubscribeToIntegrationEvent<MemberCreatedIntegrationEvent>(eventBus, logger);\n        }\n\n        private static void SubscribeToIntegrationEvent<T>(IEventsBus eventBus, ILogger logger)\n            where T : IntegrationEvent\n        {\n            logger.Information(\"Subscribe to {@IntegrationEvent}\", typeof(T).FullName);\n            eventBus.Subscribe(\n                new IntegrationEventGenericHandler<T>());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/EventsBus/IntegrationEventGenericHandler.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.EventsBus\n{\n    internal class IntegrationEventGenericHandler<T> : IIntegrationEventHandler<T>\n        where T : IntegrationEvent\n    {\n        public async Task Handle(T @event)\n        {\n            using (var scope = UserAccessCompositionRoot.BeginLifetimeScope())\n            {\n                using (var connection = scope.Resolve<ISqlConnectionFactory>().GetOpenConnection())\n                {\n                    string type = @event.GetType().FullName;\n                    var data = JsonConvert.SerializeObject(@event, new JsonSerializerSettings\n                    {\n                        ContractResolver = new AllPropertiesContractResolver()\n                    });\n\n                    var sql = \"INSERT INTO [users].[InboxMessages] (Id, OccurredOn, Type, Data) \" +\n                              \"VALUES (@Id, @OccurredOn, @Type, @Data)\";\n\n                    await connection.ExecuteScalarAsync(sql, new\n                    {\n                        @event.Id,\n                        @event.OccurredOn,\n                        type,\n                        data\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Identity/IdentityConfiguration.cs",
    "content": "using CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.IdentityServer;\nusing IdentityServer4.AccessTokenValidation;\nusing IdentityServer4.Validation;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Identity;\n\npublic static class IdentityConfiguration\n{\n    public static IServiceCollection ConfigureIdentityService(this IServiceCollection services)\n    {\n        services.AddIdentityServer()\n            .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())\n            .AddInMemoryApiScopes(IdentityServerConfig.GetApiScopes())\n            .AddInMemoryApiResources(IdentityServerConfig.GetApis())\n            .AddInMemoryClients(IdentityServerConfig.GetClients())\n            .AddInMemoryPersistedGrants()\n            .AddProfileService<ProfileService>()\n            .AddDeveloperSigningCredential();\n\n        services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();\n\n        services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)\n            .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, x =>\n            {\n                x.Authority = \"http://localhost:5000\";\n                x.ApiName = \"myMeetingsAPI\";\n                x.RequireHttpsMetadata = false;\n            });\n\n        return services;\n    }\n\n    public static IApplicationBuilder AddIdentityService(this IApplicationBuilder app)\n    {\n        app.UseIdentityServer();\n        return app;\n    }\n}\n"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Logging/LoggingModule.cs",
    "content": "﻿using Autofac;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Logging\n{\n    internal class LoggingModule : Autofac.Module\n    {\n        private readonly ILogger _logger;\n\n        internal LoggingModule(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterInstance(_logger)\n                .As<ILogger>()\n                .SingleInstance();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Mediation/MediatorModule.cs",
    "content": "﻿using System.Reflection;\nusing Autofac;\nusing Autofac.Core;\nusing Autofac.Features.Variance;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing FluentValidation;\nusing MediatR;\nusing MediatR.Pipeline;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Mediation\n{\n    public class MediatorModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<ServiceProviderWrapper>()\n            .As<IServiceProvider>()\n            .InstancePerDependency()\n            .IfNotRegistered(typeof(IServiceProvider));\n\n            builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)\n                .AsImplementedInterfaces()\n                .InstancePerLifetimeScope();\n\n            var mediatorOpenTypes = new[]\n            {\n                typeof(IRequestHandler<,>),\n                typeof(INotificationHandler<>),\n                typeof(IValidator<>),\n                typeof(IRequestPreProcessor<>),\n                typeof(IRequestHandler<>),\n                typeof(IStreamRequestHandler<,>),\n                typeof(IRequestPostProcessor<,>),\n                typeof(IRequestExceptionHandler<,,>),\n                typeof(IRequestExceptionAction<,>),\n                typeof(ICommandHandler<>),\n                typeof(ICommandHandler<,>),\n            };\n            builder.RegisterSource(new ScopedContravariantRegistrationSource(\n                mediatorOpenTypes));\n            foreach (var mediatorOpenType in mediatorOpenTypes)\n            {\n                builder\n                    .RegisterAssemblyTypes(Assemblies.Application, ThisAssembly)\n                    .AsClosedTypesOf(mediatorOpenType)\n                    .AsImplementedInterfaces()\n                    .FindConstructorsWith(new AllConstructorFinder());\n            }\n\n            builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n            builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));\n        }\n\n        private class ScopedContravariantRegistrationSource : IRegistrationSource\n        {\n            private readonly ContravariantRegistrationSource _source = new();\n            private readonly List<Type> _types = new();\n\n            public ScopedContravariantRegistrationSource(params Type[] types)\n            {\n                ArgumentNullException.ThrowIfNull(types);\n\n                if (!types.All(x => x.IsGenericTypeDefinition))\n                {\n                    throw new ArgumentException(\"Supplied types should be generic type definitions\");\n                }\n\n                _types.AddRange(types);\n            }\n\n            public IEnumerable<IComponentRegistration> RegistrationsFor(\n                Service service,\n                Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)\n            {\n                var components = _source.RegistrationsFor(service, registrationAccessor);\n                foreach (var c in components)\n                {\n                    var defs = c.Target.Services\n                        .OfType<TypedService>()\n                        .Select(x => x.ServiceType.GetGenericTypeDefinition());\n\n                    if (defs.Any(_types.Contains))\n                    {\n                        yield return c;\n                    }\n                }\n            }\n\n            public bool IsAdapterForIndividualComponents => _source.IsAdapterForIndividualComponents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/CommandsExecutor.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal static class CommandsExecutor\n    {\n        internal static async Task Execute(ICommand command)\n        {\n            using (var scope = UserAccessCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                await mediator.Send(command);\n            }\n        }\n\n        internal static async Task<TResult> Execute<TResult>(ICommand<TResult> command)\n        {\n            using (var scope = UserAccessCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n                return await mediator.Send(command);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/IRecurringCommand.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    public interface IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Inbox/InboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Inbox\n{\n    public class InboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Inbox\n{\n    public class ProcessInboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Inbox/ProcessInboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Inbox\r\n{\r\n    internal class ProcessInboxCommandHandler : ICommandHandler<ProcessInboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInboxCommandHandler(IMediator mediator, ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                               SELECT \r\n                                  [InboxMessage].[Id] AS [{nameof(InboxMessageDto.Id)}], \r\n                                  [InboxMessage].[Type] AS [{nameof(InboxMessageDto.Type)}], \r\n                                  [InboxMessage].[Data] AS [{nameof(InboxMessageDto.Data)}] \r\n                               FROM [users].[InboxMessages] AS [InboxMessage] \r\n                               WHERE [InboxMessage].[ProcessedDate] IS NULL \r\n                               ORDER BY [InboxMessage].[OccurredOn]\r\n                               \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<InboxMessageDto>(sql);\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [users].[InboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n\r\n            foreach (var message in messages)\r\n            {\r\n                var messageAssembly = AppDomain.CurrentDomain.GetAssemblies()\r\n                    .SingleOrDefault(assembly => message.Type.Contains(assembly.GetName().Name));\r\n\r\n                Type type = messageAssembly.GetType(message.Type);\r\n                var request = JsonConvert.DeserializeObject(message.Data, type);\r\n\r\n                try\r\n                {\r\n                    await _mediator.Publish((INotification)request, cancellationToken);\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    Console.WriteLine(e);\r\n                    throw;\r\n                }\r\n\r\n                await connection.ExecuteAsync(sqlUpdateProcessedDate, new\r\n                {\r\n                    Date = DateTime.UtcNow,\r\n                    message.Id\r\n                });\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Inbox/ProcessInboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Inbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/InternalCommands/CommandsScheduler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Serialization;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Dapper;\nusing Newtonsoft.Json;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands\n{\n    public class CommandsScheduler : ICommandsScheduler\n    {\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\n\n        public CommandsScheduler(ISqlConnectionFactory sqlConnectionFactory)\n        {\n            _sqlConnectionFactory = sqlConnectionFactory;\n        }\n\n        public async Task EnqueueAsync(ICommand command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [users].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n\n        public async Task EnqueueAsync<T>(ICommand<T> command)\n        {\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\n\n            const string sqlInsert = \"INSERT INTO [users].[InternalCommands] ([Id], [EnqueueDate] , [Type], [Data]) VALUES \" +\n                                     \"(@Id, @EnqueueDate, @Type, @Data)\";\n\n            await connection.ExecuteAsync(sqlInsert, new\n            {\n                command.Id,\n                EnqueueDate = DateTime.UtcNow,\n                Type = command.GetType().FullName,\n                Data = JsonConvert.SerializeObject(command, new JsonSerializerSettings\n                {\n                    ContractResolver = new AllPropertiesContractResolver()\n                })\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands\n{\n    internal class ProcessInternalCommandsCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing Newtonsoft.Json;\r\nusing Polly;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands\r\n{\r\n    internal class ProcessInternalCommandsCommandHandler : ICommandHandler<ProcessInternalCommandsCommand>\r\n    {\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        public ProcessInternalCommandsCommandHandler(\r\n            ISqlConnectionFactory sqlConnectionFactory)\r\n        {\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n        }\r\n\r\n        public async Task Handle(ProcessInternalCommandsCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n\r\n            const string sql = $\"\"\"\r\n                                SELECT \r\n                                    [Command].[Id] AS [{nameof(InternalCommandDto.Id)}], \r\n                                    [Command].[Type] AS [{nameof(InternalCommandDto.Type)}], \r\n                                    [Command].[Data] AS [{nameof(InternalCommandDto.Data)}] \r\n                                FROM [users].[InternalCommands] AS [Command] \r\n                                WHERE [Command].[ProcessedDate] IS NULL \r\n                                ORDER BY [Command].[EnqueueDate]\r\n                                \"\"\";\r\n            var commands = await connection.QueryAsync<InternalCommandDto>(sql);\r\n\r\n            var internalCommandsList = commands.AsList();\r\n\r\n            var policy = Policy\r\n                .Handle<Exception>()\r\n                .WaitAndRetryAsync(new[]\r\n                {\r\n                    TimeSpan.FromSeconds(1),\r\n                    TimeSpan.FromSeconds(2),\r\n                    TimeSpan.FromSeconds(3)\r\n                });\r\n\r\n            foreach (var internalCommand in internalCommandsList)\r\n            {\r\n                var result = await policy.ExecuteAndCaptureAsync(() => ProcessCommand(\r\n                    internalCommand));\r\n\r\n                if (result.Outcome == OutcomeType.Failure)\r\n                {\r\n                    await connection.ExecuteScalarAsync(\r\n                        \"\"\"\r\n                        UPDATE [users].[InternalCommands] \r\n                        SET \r\n                            ProcessedDate = @NowDate, \r\n                            Error = @Error \r\n                        WHERE [Id] = @Id\r\n                        \"\"\",\r\n                        new\r\n                        {\r\n                            NowDate = DateTime.UtcNow,\r\n                            Error = result.FinalException.ToString(),\r\n                            internalCommand.Id\r\n                        });\r\n                }\r\n            }\r\n        }\r\n\r\n        private async Task ProcessCommand(\r\n            InternalCommandDto internalCommand)\r\n        {\r\n            Type type = Assemblies.Application.GetType(internalCommand.Type);\r\n            dynamic commandToProcess = JsonConvert.DeserializeObject(internalCommand.Data, type);\r\n\r\n            await CommandsExecutor.Execute(commandToProcess);\r\n        }\r\n\r\n        private class InternalCommandDto\r\n        {\r\n            public Guid Id { get; set; }\r\n\r\n            public string Type { get; set; }\r\n\r\n            public string Data { get; set; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/InternalCommands/ProcessInternalCommandsJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands\n{\n    [DisallowConcurrentExecution]\n    public class ProcessInternalCommandsJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessInternalCommandsCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/LoggingCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\r\nusing Serilog;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\r\n{\r\n    internal class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ILogger _logger;\r\n        private readonly IExecutionContextAccessor _executionContextAccessor;\r\n        private readonly ICommandHandler<T> _decorated;\r\n\r\n        public LoggingCommandHandlerDecorator(\r\n            ILogger logger,\r\n            IExecutionContextAccessor executionContextAccessor,\r\n            ICommandHandler<T> decorated)\r\n        {\r\n            _logger = logger;\r\n            _executionContextAccessor = executionContextAccessor;\r\n            _decorated = decorated;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            if (command is IRecurringCommand)\r\n            {\r\n                 await _decorated.Handle(command, cancellationToken);\r\n\r\n                 return;\r\n            }\r\n\r\n            using (\r\n                LogContext.Push(\r\n                    new RequestLogEnricher(_executionContextAccessor),\r\n                    new CommandLogEnricher(command)))\r\n            {\r\n                try\r\n                {\r\n                    this._logger.Information(\r\n                        \"Executing command {Command}\",\r\n                        command.GetType().Name);\r\n\r\n                    await _decorated.Handle(command, cancellationToken);\r\n\r\n                    this._logger.Information(\"Command {Command} processed successful\", command.GetType().Name);\r\n                }\r\n                catch (Exception exception)\r\n                {\r\n                    this._logger.Error(exception, \"Command {Command} processing failed\", command.GetType().Name);\r\n                    throw;\r\n                }\r\n            }\r\n        }\r\n\r\n        private class CommandLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly ICommand _command;\r\n\r\n            public CommandLogEnricher(ICommand command)\r\n            {\r\n                _command = command;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"Command:{_command.Id.ToString()}\")));\r\n            }\r\n        }\r\n\r\n        private class RequestLogEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IExecutionContextAccessor _executionContextAccessor;\r\n\r\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\r\n            {\r\n                _executionContextAccessor = executionContextAccessor;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                if (_executionContextAccessor.IsAvailable)\r\n                {\r\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\"CorrelationId\", new ScalarValue(_executionContextAccessor.CorrelationId)));\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/LoggingCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Serilog;\nusing Serilog.Context;\nusing Serilog.Core;\nusing Serilog.Events;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal class LoggingCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ILogger _logger;\n        private readonly IExecutionContextAccessor _executionContextAccessor;\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public LoggingCommandHandlerWithResultDecorator(\n            ILogger logger,\n            IExecutionContextAccessor executionContextAccessor,\n            ICommandHandler<T, TResult> decorated)\n        {\n            _logger = logger;\n            _executionContextAccessor = executionContextAccessor;\n            _decorated = decorated;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            if (command is IRecurringCommand)\n            {\n                return await _decorated.Handle(command, cancellationToken);\n            }\n\n            using (\n                LogContext.Push(\n                    new RequestLogEnricher(_executionContextAccessor),\n                    new CommandLogEnricher(command)))\n            {\n                try\n                {\n                    this._logger.Information(\n                        \"Executing command {@Command}\",\n                        command);\n\n                    var result = await _decorated.Handle(command, cancellationToken);\n\n                    this._logger.Information(\"Command processed successful, result {Result}\", result);\n\n                    return result;\n                }\n                catch (Exception exception)\n                {\n                    this._logger.Error(exception, \"Command processing failed\");\n                    throw;\n                }\n            }\n        }\n\n        private class CommandLogEnricher : ILogEventEnricher\n        {\n            private readonly ICommand<TResult> _command;\n\n            public CommandLogEnricher(ICommand<TResult> command)\n            {\n                _command = command;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\n                    \"Context\",\n                    new ScalarValue($\"Command:{_command.Id.ToString()}\")));\n            }\n        }\n\n        private class RequestLogEnricher : ILogEventEnricher\n        {\n            private readonly IExecutionContextAccessor _executionContextAccessor;\n\n            public RequestLogEnricher(IExecutionContextAccessor executionContextAccessor)\n            {\n                _executionContextAccessor = executionContextAccessor;\n            }\n\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\n            {\n                if (_executionContextAccessor.IsAvailable)\n                {\n                    logEvent.AddOrUpdateProperty(new LogEventProperty(\n                        \"CorrelationId\",\n                        new ScalarValue(_executionContextAccessor.CorrelationId)));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Outbox/OutboxMessageDto.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox\n{\n    public class OutboxMessageDto\n    {\n        public Guid Id { get; set; }\n\n        public string Type { get; set; }\n\n        public string Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Outbox/OutboxModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Outbox;\nusing Module = Autofac.Module;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox\n{\n    internal class OutboxModule : Module\n    {\n        private readonly BiDictionary<string, Type> _domainNotificationsMap;\n\n        public OutboxModule(BiDictionary<string, Type> domainNotificationsMap)\n        {\n            _domainNotificationsMap = domainNotificationsMap;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<OutboxAccessor>()\n                .As<IOutbox>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .InstancePerLifetimeScope();\n\n            CheckMappings();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .FindConstructorsWith(new AllConstructorFinder())\n                .WithParameter(\"domainNotificationsMap\", _domainNotificationsMap)\n                .SingleInstance();\n        }\n\n        private void CheckMappings()\n        {\n            var domainEventNotifications = Assemblies.Application\n                .GetTypes()\n                .Where(x => x.GetInterfaces().Contains(typeof(IDomainEventNotification)))\n                .ToList();\n\n            List<Type> notMappedNotifications = [];\n            foreach (var domainEventNotification in domainEventNotifications)\n            {\n                _domainNotificationsMap.TryGetBySecond(domainEventNotification, out var name);\n\n                if (name == null)\n                {\n                    notMappedNotifications.Add(domainEventNotification);\n                }\n            }\n\n            if (notMappedNotifications.Any())\n            {\n                throw new ApplicationException($\"Domain Event Notifications {notMappedNotifications.Select(x => x.FullName).Aggregate((x, y) => x + \",\" + y)} not mapped\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommand.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox\n{\n    public class ProcessOutboxCommand : CommandBase, IRecurringCommand\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxCommandHandler.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Data;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\r\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing Dapper;\r\nusing MediatR;\r\nusing Newtonsoft.Json;\r\nusing Serilog.Context;\r\nusing Serilog.Core;\r\nusing Serilog.Events;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox\r\n{\r\n    internal class ProcessOutboxCommandHandler : ICommandHandler<ProcessOutboxCommand>\r\n    {\r\n        private readonly IMediator _mediator;\r\n\r\n        private readonly ISqlConnectionFactory _sqlConnectionFactory;\r\n\r\n        private readonly IDomainNotificationsMapper _domainNotificationsMapper;\r\n\r\n        public ProcessOutboxCommandHandler(\r\n            IMediator mediator,\r\n            ISqlConnectionFactory sqlConnectionFactory,\r\n            IDomainNotificationsMapper domainNotificationsMapper)\r\n        {\r\n            _mediator = mediator;\r\n            _sqlConnectionFactory = sqlConnectionFactory;\r\n            _domainNotificationsMapper = domainNotificationsMapper;\r\n        }\r\n\r\n        public async Task Handle(ProcessOutboxCommand command, CancellationToken cancellationToken)\r\n        {\r\n            var connection = this._sqlConnectionFactory.GetOpenConnection();\r\n            const string sql = $\"\"\"\r\n                               SELECT \r\n                                   [OutboxMessage].[Id] AS [{nameof(OutboxMessageDto.Id)}], \r\n                                   [OutboxMessage].[Type] AS [{nameof(OutboxMessageDto.Type)}], \r\n                                   [OutboxMessage].[Data] AS [{nameof(OutboxMessageDto.Data)}] \r\n                               FROM [users].[OutboxMessages] AS [OutboxMessage] \r\n                               WHERE [OutboxMessage].[ProcessedDate] IS NULL \r\n                               ORDER BY [OutboxMessage].[OccurredOn]\r\n                               \"\"\";\r\n\r\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\r\n            var messagesList = messages.AsList();\r\n\r\n            const string sqlUpdateProcessedDate = \"\"\"\r\n                                                  UPDATE [users].[OutboxMessages] \r\n                                                  SET [ProcessedDate] = @Date \r\n                                                  WHERE [Id] = @Id\r\n                                                  \"\"\";\r\n            if (messagesList.Count > 0)\r\n            {\r\n                foreach (var message in messagesList)\r\n                {\r\n                    var type = _domainNotificationsMapper.GetType(message.Type);\r\n                    var @event = JsonConvert.DeserializeObject(message.Data, type) as IDomainEventNotification;\r\n\r\n                    using (LogContext.Push(new OutboxMessageContextEnricher(@event)))\r\n                    {\r\n                        await this._mediator.Publish(@event, cancellationToken);\r\n\r\n                        await connection.ExecuteAsync(sqlUpdateProcessedDate, new\r\n                        {\r\n                            Date = DateTime.UtcNow,\r\n                            message.Id\r\n                        });\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private class OutboxMessageContextEnricher : ILogEventEnricher\r\n        {\r\n            private readonly IDomainEventNotification _notification;\r\n\r\n            public OutboxMessageContextEnricher(IDomainEventNotification notification)\r\n            {\r\n                _notification = notification;\r\n            }\r\n\r\n            public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)\r\n            {\r\n                logEvent.AddOrUpdateProperty(new LogEventProperty(\"Context\", new ScalarValue($\"OutboxMessage:{_notification.Id.ToString()}\")));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/Outbox/ProcessOutboxJob.cs",
    "content": "﻿using Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox\n{\n    [DisallowConcurrentExecution]\n    public class ProcessOutboxJob : IJob\n    {\n        public async Task Execute(IJobExecutionContext context)\n        {\n            await CommandsExecutor.Execute(new ProcessOutboxCommand());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/ProcessingModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Events;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.DomainEventsDispatching;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal class ProcessingModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<DomainEventsDispatcher>()\n                .As<IDomainEventsDispatcher>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainNotificationsMapper>()\n                .As<IDomainNotificationsMapper>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<DomainEventsAccessor>()\n                .As<IDomainEventsAccessor>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<UnitOfWork>()\n                .As<IUnitOfWork>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterType<CommandsScheduler>()\n                .As<ICommandsScheduler>()\n                .InstancePerLifetimeScope();\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerDecorator<>),\n                typeof(ICommandHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(ValidationCommandHandlerWithResultDecorator<,>),\n                typeof(ICommandHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerDecorator<>),\n                typeof(IRequestHandler<>));\n\n            builder.RegisterGenericDecorator(\n                typeof(LoggingCommandHandlerWithResultDecorator<,>),\n                typeof(IRequestHandler<,>));\n\n            builder.RegisterGenericDecorator(\n                typeof(DomainEventsDispatcherNotificationHandlerDecorator<>),\n                typeof(INotificationHandler<>));\n\n            builder.RegisterAssemblyTypes(Assemblies.Application)\n                .AsClosedTypesOf(typeof(IDomainEventNotification<>))\n                .InstancePerDependency()\n                .FindConstructorsWith(new AllConstructorFinder());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\r\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\r\nusing Microsoft.EntityFrameworkCore;\r\n\r\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\r\n{\r\n    internal class UnitOfWorkCommandHandlerDecorator<T> : ICommandHandler<T>\r\n        where T : ICommand\r\n    {\r\n        private readonly ICommandHandler<T> _decorated;\r\n        private readonly IUnitOfWork _unitOfWork;\r\n        private readonly UserAccessContext _userAccessContext;\r\n\r\n        public UnitOfWorkCommandHandlerDecorator(\r\n            ICommandHandler<T> decorated,\r\n            IUnitOfWork unitOfWork,\r\n            UserAccessContext userAccessContext)\r\n        {\r\n            _decorated = decorated;\r\n            _unitOfWork = unitOfWork;\r\n            _userAccessContext = userAccessContext;\r\n        }\r\n\r\n        public async Task Handle(T command, CancellationToken cancellationToken)\r\n        {\r\n            await this._decorated.Handle(command, cancellationToken);\r\n\r\n            if (command is InternalCommandBase)\r\n            {\r\n                var internalCommand = await _userAccessContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\r\n\r\n                if (internalCommand != null)\r\n                {\r\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\r\n                }\r\n            }\r\n\r\n            await this._unitOfWork.CommitAsync(cancellationToken);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/UnitOfWorkCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal class UnitOfWorkCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly ICommandHandler<T, TResult> _decorated;\n        private readonly IUnitOfWork _unitOfWork;\n        private readonly UserAccessContext _userAccessContext;\n\n        public UnitOfWorkCommandHandlerWithResultDecorator(\n            ICommandHandler<T, TResult> decorated,\n            IUnitOfWork unitOfWork,\n            UserAccessContext userAccessContext)\n        {\n            _decorated = decorated;\n            _unitOfWork = unitOfWork;\n            _userAccessContext = userAccessContext;\n        }\n\n        public async Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var result = await this._decorated.Handle(command, cancellationToken);\n\n            if (command is InternalCommandBase<TResult>)\n            {\n                var internalCommand = await _userAccessContext.InternalCommands.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken: cancellationToken);\n\n                if (internalCommand != null)\n                {\n                    internalCommand.ProcessedDate = DateTime.UtcNow;\n                }\n            }\n\n            await this._unitOfWork.CommitAsync(cancellationToken);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/ValidationCommandHandlerDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerDecorator<T> : ICommandHandler<T>\n        where T : ICommand\n    {\n        private readonly IList<IValidator<T>> _validators;\n        private readonly ICommandHandler<T> _decorated;\n\n        public ValidationCommandHandlerDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public async Task Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            await _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Processing/ValidationCommandHandlerWithResultDecorator.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing FluentValidation;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing\n{\n    internal class ValidationCommandHandlerWithResultDecorator<T, TResult> : ICommandHandler<T, TResult>\n        where T : ICommand<TResult>\n    {\n        private readonly IList<IValidator<T>> _validators;\n\n        private readonly ICommandHandler<T, TResult> _decorated;\n\n        public ValidationCommandHandlerWithResultDecorator(\n            IList<IValidator<T>> validators,\n            ICommandHandler<T, TResult> decorated)\n        {\n            this._validators = validators;\n            _decorated = decorated;\n        }\n\n        public Task<TResult> Handle(T command, CancellationToken cancellationToken)\n        {\n            var errors = _validators\n                .Select(v => v.Validate(command))\n                .SelectMany(result => result.Errors)\n                .Where(error => error != null)\n                .ToList();\n\n            if (errors.Any())\n            {\n                throw new InvalidCommandException(errors.Select(x => x.ErrorMessage).ToList());\n            }\n\n            return _decorated.Handle(command, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Quartz/QuartzModule.cs",
    "content": "﻿using Autofac;\nusing Quartz;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Quartz\n{\n    public class QuartzModule : Autofac.Module\n    {\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterAssemblyTypes(ThisAssembly)\n                .Where(x => typeof(IJob).IsAssignableFrom(x)).InstancePerDependency();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Quartz/QuartzStartup.cs",
    "content": "﻿using System.Collections.Specialized;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Inbox;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.InternalCommands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox;\nusing Quartz;\nusing Quartz.Impl;\nusing Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Quartz\n{\n    internal static class QuartzStartup\n    {\n        internal static void Initialize(ILogger logger, long? internalProcessingPoolingInterval = null)\n        {\n            logger.Information(\"Quartz starting...\");\n\n            var schedulerConfiguration = new NameValueCollection();\n            schedulerConfiguration.Add(\"quartz.scheduler.instanceName\", \"Meetings\");\n\n            ISchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerConfiguration);\n            IScheduler scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult();\n\n            LogProvider.SetCurrentLogProvider(new SerilogLogProvider(logger));\n\n            scheduler.Start().GetAwaiter().GetResult();\n\n            var processOutboxJob = JobBuilder.Create<ProcessOutboxJob>().Build();\n            ITrigger trigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                trigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processOutboxJob, trigger)\n                .GetAwaiter().GetResult();\n\n            var processInboxJob = JobBuilder.Create<ProcessInboxJob>().Build();\n\n            ITrigger processInboxTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInboxTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler\n                .ScheduleJob(processInboxJob, processInboxTrigger)\n                .GetAwaiter().GetResult();\n\n            var processInternalCommandsJob = JobBuilder.Create<ProcessInternalCommandsJob>().Build();\n\n            ITrigger processInternalCommandsTrigger;\n            if (internalProcessingPoolingInterval.HasValue)\n            {\n                processInternalCommandsTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithSimpleSchedule(x =>\n                            x.WithInterval(TimeSpan.FromMilliseconds(internalProcessingPoolingInterval.Value))\n                                .RepeatForever())\n                        .Build();\n            }\n            else\n            {\n                processInternalCommandsTrigger =\n                    TriggerBuilder\n                        .Create()\n                        .StartNow()\n                        .WithCronSchedule(\"0/2 * * ? * *\")\n                        .Build();\n            }\n\n            scheduler.ScheduleJob(processInternalCommandsJob, processInternalCommandsTrigger).GetAwaiter().GetResult();\n\n            logger.Information(\"Quartz started.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Quartz/SerilogLogProvider.cs",
    "content": "﻿using Quartz.Logging;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Quartz\n{\n    internal class SerilogLogProvider : ILogProvider\n    {\n        private readonly ILogger _logger;\n\n        internal SerilogLogProvider(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public Logger GetLogger(string name)\n        {\n            return (level, func, exception, parameters) =>\n            {\n                if (func == null)\n                {\n                    return true;\n                }\n\n                if (level == LogLevel.Debug || level == LogLevel.Trace)\n                {\n                    _logger.Debug(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Info)\n                {\n                    _logger.Information(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Warn)\n                {\n                    _logger.Warning(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Error)\n                {\n                    _logger.Error(exception, func(), parameters);\n                }\n\n                if (level == LogLevel.Fatal)\n                {\n                    _logger.Fatal(exception, func(), parameters);\n                }\n\n                return true;\n            };\n        }\n\n        public IDisposable OpenNestedContext(string message)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, string value)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IDisposable OpenMappedContext(string key, object value, bool destructure = false)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Security/AesDataProtector.cs",
    "content": "﻿using System.Security.Cryptography;\nusing System.Text;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Security\n{\n    public class AesDataProtector : IDataProtector\n    {\n        private readonly string _encryptionKey;\n\n        public AesDataProtector(string encryptionKey)\n        {\n            _encryptionKey = encryptionKey;\n        }\n\n        public string Encrypt(string plainText)\n        {\n            var key = Encoding.UTF8.GetBytes(_encryptionKey);\n\n            using var aesAlg = Aes.Create();\n            using var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV);\n            using var msEncrypt = new MemoryStream();\n            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))\n            {\n                using var swEncrypt = new StreamWriter(csEncrypt);\n                swEncrypt.Write(plainText);\n            }\n\n            var iv = aesAlg.IV;\n\n            var decryptedContent = msEncrypt.ToArray();\n\n            var result = new byte[iv.Length + decryptedContent.Length];\n\n            Buffer.BlockCopy(iv, 0, result, 0, iv.Length);\n            Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);\n\n            return Convert.ToBase64String(result);\n        }\n\n        public string Decrypt(string encryptedText)\n        {\n            var fullCipher = Convert.FromBase64String(encryptedText);\n\n            var iv = new byte[16];\n            var cipher = new byte[fullCipher.Length - iv.Length];\n\n            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);\n            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, fullCipher.Length - iv.Length);\n            var key = Encoding.UTF8.GetBytes(_encryptionKey);\n\n            using var aesAlg = Aes.Create();\n            using var decryptor = aesAlg.CreateDecryptor(key, iv);\n            string result;\n            using (var msDecrypt = new MemoryStream(cipher))\n            {\n                using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);\n                using var srDecrypt = new StreamReader(csDecrypt);\n                result = srDecrypt.ReadToEnd();\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Security/IDataProtector.cs",
    "content": "﻿namespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Security\n{\n    public interface IDataProtector\n    {\n        string Encrypt(string plainText);\n\n        string Decrypt(string encryptedText);\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/Security/SecurityModule.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Security\n{\n    internal class SecurityModule : Module\n    {\n        private readonly string _encryptionKey;\n\n        public SecurityModule(string encryptionKey)\n        {\n            _encryptionKey = encryptionKey;\n        }\n\n        protected override void Load(ContainerBuilder builder)\n        {\n            builder.RegisterType<AesDataProtector>()\n                .As<IDataProtector>()\n                .WithParameter(\"encryptionKey\", _encryptionKey);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/UserAccessCompositionRoot.cs",
    "content": "﻿using Autofac;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration\n{\n    internal static class UserAccessCompositionRoot\n    {\n        private static IContainer _container;\n\n        internal static void SetContainer(IContainer container)\n        {\n            _container = container;\n        }\n\n        internal static ILifetimeScope BeginLifetimeScope()\n        {\n            return _container.BeginLifetimeScope();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Configuration/UserAccessStartup.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.DataAccess;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Email;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.EventsBus;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Logging;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Mediation;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Quartz;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Security;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration\n{\n    public class UserAccessStartup\n    {\n        private static IContainer _container;\n\n        public static void Initialize(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            string textEncryptionKey,\n            IEmailSender emailSender,\n            IEventsBus eventsBus,\n            long? internalProcessingPoolingInterval = null)\n        {\n            var moduleLogger = logger.ForContext(\"Module\", \"UserAccess\");\n\n            ConfigureCompositionRoot(\n                connectionString,\n                executionContextAccessor,\n                logger,\n                emailsConfiguration,\n                textEncryptionKey,\n                emailSender,\n                eventsBus);\n\n            QuartzStartup.Initialize(moduleLogger, internalProcessingPoolingInterval);\n\n            EventsBusStartup.Initialize(moduleLogger);\n        }\n\n        private static void ConfigureCompositionRoot(\n            string connectionString,\n            IExecutionContextAccessor executionContextAccessor,\n            ILogger logger,\n            EmailsConfiguration emailsConfiguration,\n            string textEncryptionKey,\n            IEmailSender emailSender,\n            IEventsBus eventsBus)\n        {\n            var containerBuilder = new ContainerBuilder();\n\n            containerBuilder.RegisterModule(new LoggingModule(logger.ForContext(\"Module\", \"UserAccess\")));\n\n            var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(logger);\n            containerBuilder.RegisterModule(new DataAccessModule(connectionString, loggerFactory));\n            containerBuilder.RegisterModule(new ProcessingModule());\n            containerBuilder.RegisterModule(new EventsBusModule(eventsBus));\n            containerBuilder.RegisterModule(new MediatorModule());\n            containerBuilder.RegisterModule(new OutboxModule(new BiDictionary<string, Type>()));\n\n            containerBuilder.RegisterModule(new QuartzModule());\n            containerBuilder.RegisterModule(new EmailModule(emailsConfiguration, emailSender));\n            containerBuilder.RegisterModule(new SecurityModule(textEncryptionKey));\n\n            containerBuilder.RegisterInstance(executionContextAccessor);\n\n            _container = containerBuilder.Build();\n\n            UserAccessCompositionRoot.SetContainer(_container);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Domain/Users/UserEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Domain.Users\n{\n    internal class UserEntityTypeConfiguration : IEntityTypeConfiguration<User>\n    {\n        public void Configure(EntityTypeBuilder<User> builder)\n        {\n            builder.ToTable(\"Users\", \"users\");\n\n            builder.HasKey(x => x.Id);\n\n            builder.Property<string>(\"_login\").HasColumnName(\"Login\");\n            builder.Property<string>(\"_email\").HasColumnName(\"Email\");\n            builder.Property<string>(\"_password\").HasColumnName(\"Password\");\n            builder.Property<bool>(\"_isActive\").HasColumnName(\"IsActive\");\n            builder.Property<string>(\"_firstName\").HasColumnName(\"FirstName\");\n            builder.Property<string>(\"_lastName\").HasColumnName(\"LastName\");\n            builder.Property<string>(\"_name\").HasColumnName(\"Name\");\n\n            builder.OwnsMany<UserRole>(\"_roles\", b =>\n            {\n                b.WithOwner().HasForeignKey(\"UserId\");\n                b.ToTable(\"UserRoles\", \"users\");\n                b.Property<UserId>(\"UserId\");\n                b.Property<string>(\"Value\").HasColumnName(\"RoleCode\");\n                b.HasKey(\"UserId\", \"Value\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Domain/Users/UserRepository.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Domain.Users\n{\n    public class UserRepository : IUserRepository\n    {\n        private readonly UserAccessContext _userAccessContext;\n\n        public UserRepository(UserAccessContext userAccessContext)\n        {\n            _userAccessContext = userAccessContext;\n        }\n\n        public async Task AddAsync(User user)\n        {\n            await _userAccessContext.Users.AddAsync(user);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/IdentityServer/IdentityServerConfig.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing IdentityServer4;\nusing IdentityServer4.Models;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.IdentityServer\n{\n    internal class IdentityServerConfig\n    {\n        public static IEnumerable<ApiScope> GetApiScopes()\n        {\n            return new List<ApiScope>\n            {\n                new(\"all\", \"Can Do All\")\n            };\n        }\n\n        public static IEnumerable<ApiResource> GetApis()\n        {\n            return new List<ApiResource>\n            {\n                new(\"myMeetingsAPI\", \"My Meetings API\")\n                {\n                    Scopes = { \"all\" }\n                }\n            };\n        }\n\n        public static IEnumerable<IdentityResource> GetIdentityResources()\n        {\n            return new IdentityResource[]\n            {\n                new IdentityResources.OpenId(),\n                new IdentityResources.Profile(),\n                new IdentityResource(CustomClaimTypes.Roles, new List<string>\n                {\n                    CustomClaimTypes.Roles\n                })\n            };\n        }\n\n        public static IEnumerable<Client> GetClients()\n        {\n            return new List<Client>\n            {\n                new Client\n                {\n                    ClientId = \"ro.client\",\n                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,\n\n                    ClientSecrets =\n                    {\n                        new Secret(\"secret\".Sha256())\n                    },\n                    AllowedScopes =\n                    {\n                        \"all\",\n                        IdentityServerConstants.StandardScopes.OpenId,\n                        IdentityServerConstants.StandardScopes.Profile\n                    }\n                }\n            };\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/IdentityServer/ProfileService.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing IdentityServer4.Models;\nusing IdentityServer4.Services;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.IdentityServer\n{\n    internal class ProfileService : IProfileService\n    {\n        public Task GetProfileDataAsync(ProfileDataRequestContext context)\n        {\n            context.IssuedClaims.AddRange(context.Subject.Claims.Where(x => x.Type == CustomClaimTypes.Roles).ToList());\n            context.IssuedClaims.Add(context.Subject.Claims.Single(x => x.Type == CustomClaimTypes.Name));\n            context.IssuedClaims.Add(context.Subject.Claims.Single(x => x.Type == CustomClaimTypes.Email));\n            return Task.CompletedTask;\n        }\n\n        public Task IsActiveAsync(IsActiveContext context)\n        {\n            return Task.FromResult(context.IsActive);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/IdentityServer/ResourceOwnerPasswordValidator.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing IdentityServer4.Models;\nusing IdentityServer4.Validation;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.IdentityServer\n{\n    internal class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator\n    {\n        private readonly IUserAccessModule _userAccessModule;\n\n        public ResourceOwnerPasswordValidator(IUserAccessModule userAccessModule)\n        {\n            _userAccessModule = userAccessModule;\n        }\n\n        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)\n        {\n            var authenticationResult = await _userAccessModule.ExecuteCommandAsync(\n                new AuthenticateCommand(context.UserName, context.Password));\n\n            if (!authenticationResult.IsAuthenticated)\n            {\n                context.Result = new GrantValidationResult(\n                    TokenRequestErrors.InvalidGrant,\n                    authenticationResult.AuthenticationError);\n\n                return;\n            }\n\n            context.Result = new GrantValidationResult(\n                authenticationResult.User.Id.ToString(),\n                \"forms\",\n                authenticationResult.User.Claims);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/InternalCommands/InternalCommandEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.InternalCommands\n{\n    internal class InternalCommandEntityTypeConfiguration : IEntityTypeConfiguration<InternalCommand>\n    {\n        public void Configure(EntityTypeBuilder<InternalCommand> builder)\n        {\n            builder.ToTable(\"InternalCommands\", \"users\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Outbox/OutboxAccessor.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Outbox\n{\n    public class OutboxAccessor : IOutbox\n    {\n        private readonly UserAccessContext _userAccessContext;\n\n        public OutboxAccessor(UserAccessContext userAccessContext)\n        {\n            _userAccessContext = userAccessContext;\n        }\n\n        public void Add(OutboxMessage message)\n        {\n            _userAccessContext.OutboxMessages.Add(message);\n        }\n\n        public Task Save()\n        {\n            return Task.CompletedTask; // Save is done automatically using EF Core Change Tracking mechanism during SaveChanges.\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/Outbox/OutboxMessageEntityTypeConfiguration.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Outbox\n{\n    internal class OutboxMessageEntityTypeConfiguration : IEntityTypeConfiguration<OutboxMessage>\n    {\n        public void Configure(EntityTypeBuilder<OutboxMessage> builder)\n        {\n            builder.ToTable(\"OutboxMessages\", \"users\");\n\n            builder.HasKey(b => b.Id);\n            builder.Property(b => b.Id).ValueGeneratedNever();\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/UserAccessContext.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application.Outbox;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Domain.Users;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.InternalCommands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Outbox;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure\n{\n    public class UserAccessContext : DbContext\n    {\n        public DbSet<User> Users { get; set; }\n\n        public DbSet<OutboxMessage> OutboxMessages { get; set; }\n\n        public DbSet<InternalCommand> InternalCommands { get; set; }\n\n        private readonly ILoggerFactory _loggerFactory;\n\n        public UserAccessContext(DbContextOptions options, ILoggerFactory loggerFactory)\n            : base(options)\n        {\n            _loggerFactory = loggerFactory;\n        }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.ApplyConfiguration(new UserEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new OutboxMessageEntityTypeConfiguration());\n            modelBuilder.ApplyConfiguration(new InternalCommandEntityTypeConfiguration());\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Infrastructure/UserAccessModule.cs",
    "content": "﻿using Autofac;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing;\nusing MediatR;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Infrastructure\n{\n    public class UserAccessModule : IUserAccessModule\n    {\n        public async Task<TResult> ExecuteCommandAsync<TResult>(ICommand<TResult> command)\n        {\n            return await CommandsExecutor.Execute(command);\n        }\n\n        public async Task ExecuteCommandAsync(ICommand command)\n        {\n            await CommandsExecutor.Execute(command);\n        }\n\n        public async Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)\n        {\n            using (var scope = UserAccessCompositionRoot.BeginLifetimeScope())\n            {\n                var mediator = scope.Resolve<IMediator>();\n\n                return await mediator.Send(query);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/IntegrationEvents/CompanyName.MyMeetings.Modules.UserAccess.IntegrationEvents.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Modules/UserAccess/Tests/ArchTests/Application/ApplicationTests.cs",
    "content": "using System.Reflection;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Commands;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Configuration.Queries;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.ArchTests.SeedWork;\nusing FluentValidation;\nusing MediatR;\nusing NetArchTest.Rules;\nusing Newtonsoft.Json;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.ArchTests.Application\n{\n    [TestFixture]\n    public class ApplicationTests : TestBase\n    {\n        [Test]\n        public void Command_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(CommandBase))\n                .Or()\n                .Inherit(typeof(CommandBase<>))\n                .Or()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .Or()\n                .ImplementInterface(typeof(ICommand))\n                .Or()\n                .ImplementInterface(typeof(ICommand<>))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Query_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(typeof(IQuery<>)).GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void CommandHandler_Should_Have_Name_EndingWith_CommandHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(ICommandHandler<>))\n                    .Or()\n                .ImplementInterface(typeof(ICommandHandler<,>))\n                .And()\n                .DoNotHaveNameMatching(\".*Decorator.*\").Should()\n                .HaveNameEndingWith(\"CommandHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void QueryHandler_Should_Have_Name_EndingWith_QueryHandler()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .ImplementInterface(typeof(IQueryHandler<,>))\n                .Should()\n                .HaveNameEndingWith(\"QueryHandler\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Command_And_Query_Handlers_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                    .ImplementInterface(typeof(IQueryHandler<,>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<>))\n                        .Or()\n                    .ImplementInterface(typeof(ICommandHandler<,>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void Validator_Should_Have_Name_EndingWith_Validator()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should()\n                .HaveNameEndingWith(\"Validator\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void Validators_Should_Not_Be_Public()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(AbstractValidator<>))\n                .Should().NotBePublic().GetResult().FailingTypes;\n\n            AssertFailingTypes(types);\n        }\n\n        [Test]\n        public void InternalCommand_Should_Have_JsonConstructorAttribute()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That()\n                .Inherit(typeof(InternalCommandBase))\n                .Or()\n                .Inherit(typeof(InternalCommandBase<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n\n            foreach (var type in types)\n            {\n                bool hasJsonConstructorDefined = false;\n                var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var jsonConstructorAttribute = constructorInfo.GetCustomAttributes(typeof(JsonConstructorAttribute), false);\n                    if (jsonConstructorAttribute.Length > 0)\n                    {\n                        hasJsonConstructorDefined = true;\n                        break;\n                    }\n                }\n\n                if (!hasJsonConstructorDefined)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void MediatR_RequestHandler_Should_NotBe_Used_Directly()\n        {\n            var types = Types.InAssembly(ApplicationAssembly)\n                .That().DoNotHaveName(\"ICommandHandler`1\")\n                .Should().ImplementInterface(typeof(IRequestHandler<>))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                bool isCommandHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));\n                bool isCommandWithResultHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(ICommandHandler<,>));\n                bool isQueryHandler = type.GetInterfaces().Any(x =>\n                    x.IsGenericType &&\n                    x.GetGenericTypeDefinition() == typeof(IQueryHandler<,>));\n                if (!isCommandHandler && !isCommandWithResultHandler && !isQueryHandler)\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Command_With_Result_Should_Not_Return_Unit()\n        {\n            Type commandWithResultHandlerType = typeof(ICommandHandler<,>);\n            IEnumerable<Type> types = Types.InAssembly(ApplicationAssembly)\n                .That().ImplementInterface(commandWithResultHandlerType)\n                .GetTypes().ToList();\n\n            List<Type> failingTypes = [];\n            foreach (Type type in types)\n            {\n                Type interfaceType = type.GetInterface(commandWithResultHandlerType.Name);\n                if (interfaceType?.GenericTypeArguments[1] == typeof(Unit))\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/ArchTests/CompanyName.MyMeetings.Modules.UserAccess.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/UserAccess/Tests/ArchTests/Domain/DomainTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.Modules.UserAccess.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.ArchTests.Domain\n{\n    public class DomainTests : TestBase\n    {\n        [Test]\n        public void DomainEvent_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                    .Inherit(typeof(DomainEventBase))\n                        .Or()\n                    .ImplementInterface(typeof(IDomainEvent))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void ValueObject_Should_Be_Immutable()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            AssertAreImmutable(types);\n        }\n\n        [Test]\n        public void Entity_Which_Is_Not_Aggregate_Root_Cannot_Have_Public_Members()\n        {\n            var types = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity))\n                .And().DoNotImplementInterface(typeof(IAggregateRoot)).GetTypes();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.Public |\n                                              BindingFlags.Instance |\n                                              BindingFlags.Static;\n\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                var publicFields = type.GetFields(bindingFlags);\n                var publicProperties = type.GetProperties(bindingFlags);\n                var publicMethods = type.GetMethods(bindingFlags);\n\n                if (publicFields.Any() || publicProperties.Any() || publicMethods.Any())\n                {\n                    failingTypes.Add(type);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Cannot_Have_Reference_To_Other_AggregateRoot()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            var aggregateRoots = Types.InAssembly(DomainAssembly)\n                .That().ImplementInterface(typeof(IAggregateRoot)).GetTypes().ToList();\n\n            const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                              BindingFlags.NonPublic |\n                                              BindingFlags.Instance;\n\n            List<Type> failingTypes = [];\n            foreach (var type in entityTypes)\n            {\n                var fields = type.GetFields(bindingFlags);\n\n                foreach (var field in fields)\n                {\n                    if (aggregateRoots.Contains(field.FieldType) ||\n                        field.FieldType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n\n                var properties = type.GetProperties(bindingFlags);\n                foreach (var property in properties)\n                {\n                    if (aggregateRoots.Contains(property.PropertyType) ||\n                        property.PropertyType.GenericTypeArguments.Any(x => aggregateRoots.Contains(x)))\n                    {\n                        failingTypes.Add(type);\n                        break;\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Entity_Should_Have_Parameterless_Private_Constructor()\n        {\n            var entityTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(Entity)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in entityTypes)\n            {\n                bool hasPrivateParameterlessConstructor = false;\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (constructorInfo.IsPrivate && constructorInfo.GetParameters().Length == 0)\n                    {\n                        hasPrivateParameterlessConstructor = true;\n                    }\n                }\n\n                if (!hasPrivateParameterlessConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void Domain_Object_Should_Have_Only_Private_Constructors()\n        {\n            var domainObjectTypes = Types.InAssembly(DomainAssembly)\n                .That()\n                        .Inherit(typeof(Entity))\n                    .Or()\n                        .Inherit(typeof(ValueObject))\n                .GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var domainObjectType in domainObjectTypes)\n            {\n                var constructors = domainObjectType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    if (!constructorInfo.IsPrivate)\n                    {\n                        failingTypes.Add(domainObjectType);\n                    }\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void ValueObject_Should_Have_Private_Constructor_With_Parameters_For_His_State()\n        {\n            var valueObjects = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(ValueObject)).GetTypes();\n\n            List<Type> failingTypes = [];\n            foreach (var entityType in valueObjects)\n            {\n                bool hasExpectedConstructor = false;\n\n                const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |\n                                                  BindingFlags.Public |\n                                                  BindingFlags.Instance;\n                var names = entityType.GetFields(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                var propertyNames = entityType.GetProperties(bindingFlags).Select(x => x.Name.ToLower()).ToList();\n                names.AddRange(propertyNames);\n                var constructors = entityType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);\n                foreach (var constructorInfo in constructors)\n                {\n                    var parameters = constructorInfo.GetParameters().Select(x => x.Name.ToLower()).ToList();\n\n                    if (names.Intersect(parameters).Count() == names.Count)\n                    {\n                        hasExpectedConstructor = true;\n                        break;\n                    }\n                }\n\n                if (!hasExpectedConstructor)\n                {\n                    failingTypes.Add(entityType);\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        [Test]\n        public void DomainEvent_Should_Have_DomainEventPostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .Inherit(typeof(DomainEventBase))\n                .Or()\n                .ImplementInterface(typeof(IDomainEvent))\n                .Should().HaveNameEndingWith(\"DomainEvent\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void BusinessRule_Should_Have_RulePostfix()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .That()\n                .ImplementInterface(typeof(IBusinessRule))\n                .Should().HaveNameEndingWith(\"Rule\")\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/ArchTests/Module/LayersTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.ArchTests.Module\n{\n    [TestFixture]\n    public class LayersTests : TestBase\n    {\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToApplicationLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void DomainLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(DomainAssembly)\n                .Should()\n                .NotHaveDependencyOn(ApplicationAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void ApplicationLayer_DoesNotHaveDependency_ToInfrastructureLayer()\n        {\n            var result = Types.InAssembly(ApplicationAssembly)\n                .Should()\n                .NotHaveDependencyOn(InfrastructureAssembly.GetName().Name)\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApplicationAssembly => typeof(CommandBase).Assembly;\n\n        protected static Assembly DomainAssembly => typeof(User).Assembly;\n\n        protected static Assembly InfrastructureAssembly => typeof(UserAccessContext).Assembly;\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; private set; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n\n        public void SetUserId(Guid userId)\n        {\n            this.UserId = userId;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/SeedWork/OutboxMessagesHelper.cs",
    "content": "﻿using System.Data;\nusing System.Reflection;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Authentication.Authenticate;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration.Processing.Outbox;\nusing Dapper;\nusing MediatR;\nusing Newtonsoft.Json;\n\nnamespace CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.SeedWork\n{\n    public class OutboxMessagesHelper\n    {\n        public static async Task<List<OutboxMessageDto>> GetOutboxMessages(IDbConnection connection)\n        {\n            const string sql = $\"\"\"\n                               SELECT \n                                   [OutboxMessage].[Id] as [{nameof(OutboxMessageDto.Id)}], \n                                   [OutboxMessage].[Type] as [{nameof(OutboxMessageDto.Type)}], \n                                   [OutboxMessage].[Data] as [{nameof(OutboxMessageDto.Data)}] \n                               FROM [users].[OutboxMessages] AS [OutboxMessage] \n                               ORDER BY [OutboxMessage].[OccurredOn]\n                               \"\"\";\n\n            var messages = await connection.QueryAsync<OutboxMessageDto>(sql);\n            return messages.AsList();\n        }\n\n        public static T Deserialize<T>(OutboxMessageDto message)\n            where T : class, INotification\n        {\n            Type type = Assembly.GetAssembly(typeof(AuthenticateCommand)).GetType(typeof(T).FullName);\n            return JsonConvert.DeserializeObject(message.Data, type) as T;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration;\nusing Dapper;\nusing MediatR;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IUserAccessModule UserAccessModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = Substitute.For<ILogger>();\n            EmailSender = Substitute.For<IEmailSender>();\n\n            UserAccessStartup.Initialize(\n                ConnectionString,\n                new ExecutionContextMock(Guid.NewGuid()),\n                Logger,\n                new EmailsConfiguration(\"from@email.com\"),\n                \"key\",\n                EmailSender,\n                null);\n\n            UserAccessModule = new UserAccessModule();\n        }\n\n        protected async Task<T> GetLastOutboxMessage<T>()\n            where T : class, INotification\n        {\n            using (var connection = new SqlConnection(ConnectionString))\n            {\n                var messages = await OutboxMessagesHelper.GetOutboxMessages(connection);\n\n                return OutboxMessagesHelper.Deserialize<T>(messages.Last());\n            }\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [users].[InboxMessages] \" +\n                               \"DELETE FROM [users].[InternalCommands] \" +\n                               \"DELETE FROM [users].[OutboxMessages] \" +\n                               \"DELETE FROM [users].[Users] \" +\n                               \"DELETE FROM [users].[RolesToPermissions] \" +\n                               \"DELETE FROM [users].[UserRoles] \" +\n                               \"DELETE FROM [users].[Permissions] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/IntegrationTests/Users/CreateUserTests.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.UserAccess.Application.Users.CreateUser;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.GetUser;\nusing CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyNames.MyMeetings.Modules.UserAccess.IntegrationTests.Users\n{\n    [TestFixture]\n    public class CreateUserTests : TestBase\n    {\n        [Test]\n        public async Task CreateUser_Test()\n        {\n            var userId = Guid.NewGuid();\n            await UserAccessModule.ExecuteCommandAsync(new CreateUserCommand(\n                userId,\n                UserSampleData.Login,\n                UserSampleData.Email,\n                UserSampleData.FirstName,\n                UserSampleData.LastName,\n                UserSampleData.Password));\n\n            var user = await UserAccessModule.ExecuteQueryAsync(new GetUserQuery(userId));\n\n            Assert.That(user.Login, Is.EqualTo(UserSampleData.Login));\n            Assert.That(user.Email, Is.EqualTo(UserSampleData.Email));\n            Assert.That(user.Name, Is.EqualTo($\"{UserSampleData.FirstName} {UserSampleData.LastName}\"));\n        }\n    }\n\n    public struct UserSampleData\n    {\n        public static string Login => \"jdoe\";\n\n        public static string Email => \"jdoe@mail.com\";\n\n        public static string FirstName => \"John\";\n\n        public static string LastName => \"Doe\";\n\n        public static string Password => \"qwerty\";\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/UnitTests/CompanyName.MyMeetings.Modules.UserAccess.Domain.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Modules/UserAccess/Tests/UnitTests/SeedWork/DomainEventsTestHelper.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.UnitTests.SeedWork\n{\n    public class DomainEventsTestHelper\n    {\n        public static List<IDomainEvent> GetAllDomainEvents(Entity aggregate)\n        {\n            List<IDomainEvent> domainEvents = [];\n\n            if (aggregate.DomainEvents != null)\n            {\n                domainEvents.AddRange(aggregate.DomainEvents);\n            }\n\n            var fields = aggregate.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).Concat(aggregate.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)).ToArray();\n\n            foreach (var field in fields)\n            {\n                var isEntity = typeof(Entity).IsAssignableFrom(field.FieldType);\n\n                if (isEntity)\n                {\n                    var entity = field.GetValue(aggregate) as Entity;\n                    domainEvents.AddRange(GetAllDomainEvents(entity).ToList());\n                }\n\n                if (field.FieldType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(field.FieldType))\n                {\n                    if (field.GetValue(aggregate) is IEnumerable enumerable)\n                    {\n                        foreach (var en in enumerable)\n                        {\n                            if (en is Entity entityItem)\n                            {\n                                domainEvents.AddRange(GetAllDomainEvents(entityItem));\n                            }\n                        }\n                    }\n                }\n            }\n\n            return domainEvents;\n        }\n    }\n}"
  },
  {
    "path": "src/Modules/UserAccess/Tests/UnitTests/SeedWork/TestBase.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.Modules.UserAccess.Domain.UnitTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        public static T AssertPublishedDomainEvent<T>(Entity aggregate)\n            where T : IDomainEvent\n        {\n            var domainEvent = DomainEventsTestHelper.GetAllDomainEvents(aggregate).OfType<T>().SingleOrDefault();\n\n            if (domainEvent == null)\n            {\n                throw new Exception($\"{typeof(T).Name} event not published\");\n            }\n\n            return domainEvent;\n        }\n\n        public static void AssertBrokenRule<TRule>(TestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException = Assert.Catch<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/ArchTests/Api/ApiTests.cs",
    "content": "using CompanyName.MyMeetings.ArchTests.SeedWork;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.ArchTests.Api\n{\n    [TestFixture]\n    public class ApiTests : TestBase\n    {\n        [Test]\n        public void AdministrationApi_DoesNotHaveDependency_ToOtherModules()\n        {\n            List<string> otherModules = [MeetingsNamespace, PaymentsNamespace, UserAccessNamespace];\n            var result = Types.InAssembly(ApiAssembly)\n                .That()\n                        .ResideInNamespace(\"CompanyName.MyMeetings.API.Modules.Administration\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void MeetingsApi_DoesNotHaveDependency_ToOtherModules()\n        {\n            List<string> otherModules = [AdministrationNamespace, PaymentsNamespace, UserAccessNamespace];\n            var result = Types.InAssembly(ApiAssembly)\n                .That()\n                .ResideInNamespace(\"CompanyName.MyMeetings.API.Modules.Meetings\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void PaymentsApi_DoesNotHaveDependency_ToOtherModules()\n        {\n            List<string> otherModules = [AdministrationNamespace, MeetingsNamespace, UserAccessNamespace];\n            var result = Types.InAssembly(ApiAssembly)\n                .That()\n                .ResideInNamespace(\"CompanyName.MyMeetings.API.Modules.Payments\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void UserAccessApi_DoesNotHaveDependency_ToOtherModules()\n        {\n            List<string> otherModules = [AdministrationNamespace, MeetingsNamespace, PaymentsNamespace];\n            var result = Types.InAssembly(ApiAssembly)\n                .That()\n                .ResideInNamespace(\"CompanyName.MyMeetings.API.Modules.UserAccess\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/ArchTests/CompanyName.MyMeetings.ArchTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />\n"
  },
  {
    "path": "src/Tests/ArchTests/Modules/ModuleTests.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.ArchTests.SeedWork;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.Meetings;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.MeetingFees;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Domain.Users;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\nusing MediatR;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.ArchTests.Modules\n{\n    [TestFixture]\n    public class ModuleTests : TestBase\n    {\n        [Test]\n        public void AdministrationModule_DoesNotHave_Dependency_On_Other_Modules()\n        {\n            List<string> otherModules = [MeetingsNamespace, PaymentsNamespace, UserAccessNamespace];\n            List<Assembly> administrationAssemblies =\n            [\n                typeof(IAdministrationModule).Assembly,\n                typeof(MeetingGroupLocation).Assembly,\n                typeof(AdministrationContext).Assembly\n            ];\n\n            var result = Types.InAssemblies(administrationAssemblies)\n                .That()\n                    .DoNotImplementInterface(typeof(INotificationHandler<>))\n                    .And().DoNotHaveNameEndingWith(\"IntegrationEventHandler\")\n                    .And().DoNotHaveName(\"EventsBusStartup\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void MeetingsModule_DoesNotHave_Dependency_On_Other_Modules()\n        {\n            List<string> otherModules = [AdministrationNamespace, PaymentsNamespace, UserAccessNamespace];\n            List<Assembly> meetingsAssemblies =\n            [\n                typeof(IMeetingsModule).Assembly,\n                typeof(Meeting).Assembly,\n                typeof(MeetingsContext).Assembly\n            ];\n\n            var result = Types.InAssemblies(meetingsAssemblies)\n                .That()\n                .DoNotImplementInterface(typeof(INotificationHandler<>))\n                .And().DoNotHaveNameEndingWith(\"IntegrationEventHandler\")\n                .And().DoNotHaveName(\"EventsBusStartup\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void PaymentsModule_DoesNotHave_Dependency_On_Other_Modules()\n        {\n            List<string> otherModules = [AdministrationNamespace, MeetingsNamespace, UserAccessNamespace];\n            List<Assembly> paymentsAssemblies =\n            [\n                typeof(IPaymentsModule).Assembly,\n                typeof(MeetingFee).Assembly,\n                typeof(PaymentsStartup).Assembly\n            ];\n\n            var result = Types.InAssemblies(paymentsAssemblies)\n                .That()\n                .DoNotImplementInterface(typeof(INotificationHandler<>))\n                .And().DoNotHaveNameEndingWith(\"IntegrationEventHandler\")\n                .And().DoNotHaveName(\"EventsBusStartup\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n\n        [Test]\n        public void UserAccessModule_DoesNotHave_Dependency_On_Other_Modules()\n        {\n            List<string> otherModules = [AdministrationNamespace, MeetingsNamespace, PaymentsNamespace];\n            List<Assembly> userAccessAssemblies =\n            [\n                typeof(IUserAccessModule).Assembly,\n                typeof(User).Assembly,\n                typeof(UserAccessContext).Assembly\n            ];\n\n            var result = Types.InAssemblies(userAccessAssemblies)\n                .That()\n                .DoNotImplementInterface(typeof(INotificationHandler<>))\n                .And().DoNotHaveNameEndingWith(\"IntegrationEventHandler\")\n                .And().DoNotHaveName(\"EventsBusStartup\")\n                .Should()\n                .NotHaveDependencyOnAny(otherModules.ToArray())\n                .GetResult();\n\n            AssertArchTestResult(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/ArchTests/SeedWork/TestBase.cs",
    "content": "﻿using System.Reflection;\nusing CompanyName.MyMeetings.API;\nusing NetArchTest.Rules;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.ArchTests.SeedWork\n{\n    public abstract class TestBase\n    {\n        protected static Assembly ApiAssembly => typeof(Startup).Assembly;\n\n        public const string MeetingsNamespace = \"CompanyName.MyMeetings.Modules.Meetings\";\n\n        public const string AdministrationNamespace = \"CompanyName.MyMeetings.Modules.Administration\";\n\n        public const string PaymentsNamespace = \"CompanyName.MyMeetings.Modules.Payments\";\n\n        public const string UserAccessNamespace = \"CompanyName.MyMeetings.Modules.UserAccess\";\n\n        protected static void AssertAreImmutable(IEnumerable<Type> types)\n        {\n            List<Type> failingTypes = [];\n            foreach (var type in types)\n            {\n                if (type.GetFields().Any(x => !x.IsInitOnly) || type.GetProperties().Any(x => x.CanWrite))\n                {\n                    failingTypes.Add(type);\n                    break;\n                }\n            }\n\n            AssertFailingTypes(failingTypes);\n        }\n\n        protected static void AssertFailingTypes(IEnumerable<Type> types)\n        {\n            Assert.That(types, Is.Null.Or.Empty);\n        }\n\n        protected static void AssertArchTestResult(TestResult result)\n        {\n            AssertFailingTypes(result.FailingTypes);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/IntegrationTests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: NonParallelizable]\n[assembly: LevelOfParallelism(1)]\n\nnamespace CompanyName.MyMeetings.IntegrationTests\n{\n    public class AssemblyInfo\n    {\n    }\n}"
  },
  {
    "path": "src/Tests/IntegrationTests/CompanyName.MyMeetings.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Tests/IntegrationTests/CreateMeetingGroup/CreateMeetingGroupTests.cs",
    "content": "using CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.IntegrationTests.SeedWork;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.GetMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Administration.Domain.MeetingGroupProposals;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.GetAllMeetingGroups;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.IntegrationTests.CreateMeetingGroup\n{\n    public class CreateMeetingGroupTests : TestBase\n    {\n        [Test]\n        public async Task CreateMeetingGroupScenario_WhenProposalIsAccepted()\n        {\n            var meetingGroupId = await MeetingsModule.ExecuteCommandAsync(\n                new ProposeMeetingGroupCommand(\n                    \"Name\",\n                    \"Description\",\n                    \"Location\",\n                    \"PL\"));\n\n            await AssertEventually(\n                new GetMeetingGroupProposalFromAdministrationProbe(meetingGroupId, AdministrationModule),\n                10000);\n\n            await AdministrationModule.ExecuteCommandAsync(new AcceptMeetingGroupProposalCommand(meetingGroupId));\n\n            await AssertEventually(\n                new GetCreatedMeetingGroupFromMeetingsProbe(meetingGroupId, MeetingsModule),\n                15000);\n        }\n\n        private class GetCreatedMeetingGroupFromMeetingsProbe : IProbe\n        {\n            private readonly Guid _expectedMeetingGroupId;\n\n            private readonly IMeetingsModule _meetingsModule;\n\n            private List<MeetingGroupDto> _allMeetingGroups;\n\n            public GetCreatedMeetingGroupFromMeetingsProbe(\n                Guid expectedMeetingGroupId,\n                IMeetingsModule meetingsModule)\n            {\n                _expectedMeetingGroupId = expectedMeetingGroupId;\n                _meetingsModule = meetingsModule;\n            }\n\n            public bool IsSatisfied()\n            {\n                return _allMeetingGroups != null &&\n                       _allMeetingGroups.Any(x => x.Id == _expectedMeetingGroupId);\n            }\n\n            public async Task SampleAsync()\n            {\n                _allMeetingGroups = await _meetingsModule.ExecuteQueryAsync(new GetAllMeetingGroupsQuery());\n            }\n\n            public string DescribeFailureTo()\n                => $\"Meeting group with ID: {_expectedMeetingGroupId} is not created\";\n        }\n\n        private class GetMeetingGroupProposalFromAdministrationProbe : IProbe\n        {\n            private readonly Guid _expectedMeetingGroupProposalId;\n\n            private readonly IAdministrationModule _administrationModule;\n\n            private MeetingGroupProposalDto _meetingGroupProposal;\n\n            public GetMeetingGroupProposalFromAdministrationProbe(\n                Guid expectedMeetingGroupProposalId,\n                IAdministrationModule administrationModule)\n            {\n                _expectedMeetingGroupProposalId = expectedMeetingGroupProposalId;\n                _administrationModule = administrationModule;\n            }\n\n            public bool IsSatisfied()\n            {\n                if (_meetingGroupProposal == null)\n                {\n                    return false;\n                }\n\n                if (_meetingGroupProposal.Id == _expectedMeetingGroupProposalId &&\n                    _meetingGroupProposal.StatusCode == MeetingGroupProposalStatus.ToVerify.Value)\n                {\n                    return true;\n                }\n\n                return false;\n            }\n\n            public async Task SampleAsync()\n            {\n                try\n                {\n                    _meetingGroupProposal =\n                        await _administrationModule.ExecuteQueryAsync(\n                            new GetMeetingGroupProposalQuery(_expectedMeetingGroupProposalId));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n\n            public string DescribeFailureTo()\n                => $\"Meeting group proposal with ID: {_expectedMeetingGroupProposalId} to verification not created\";\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/IntegrationTests/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.IntegrationTests.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n    }\n}"
  },
  {
    "path": "src/Tests/IntegrationTests/SeedWork/TestBase.cs",
    "content": "using System.Data;\nusing System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Domain;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests;\nusing CompanyName.MyMeetings.BuildingBlocks.IntegrationTests.Probing;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration;\nusing Dapper;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.IntegrationTests.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IAdministrationModule AdministrationModule { get; private set; }\n\n        protected IMeetingsModule MeetingsModule { get; private set; }\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        protected ExecutionContextMock ExecutionContext { get; private set; }\n\n        protected IEventsBus EventsBus { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            const string connectionStringEnvironmentVariable =\n                \"ASPNETCORE_MyMeetings_IntegrationTests_ConnectionString\";\n            ConnectionString = EnvironmentVariablesProvider.GetVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to integration tests database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n\n            using (var sqlConnection = new SqlConnection(ConnectionString))\n            {\n                await ClearDatabase(sqlConnection);\n            }\n\n            Logger = new LoggerConfiguration()\n                .Enrich.FromLogContext()\n                .WriteTo.Console(\n                    outputTemplate:\n                    \"[{Timestamp:HH:mm:ss} {Level:u3}] [{Module}] [{Context}] {Message:lj}{NewLine}{Exception}\")\n                .CreateLogger();\n\n            EmailSender = Substitute.For<IEmailSender>();\n            ExecutionContext = new ExecutionContextMock(Guid.NewGuid());\n\n            EventsBus = new InMemoryEventBusClient(Logger);\n\n            AdministrationStartup.Initialize(\n                ConnectionString,\n                ExecutionContext,\n                Logger,\n                EventsBus);\n\n            MeetingsStartup.Initialize(\n                ConnectionString,\n                ExecutionContext,\n                Logger,\n                new EmailsConfiguration(\"from@email.com\"),\n                EventsBus);\n\n            AdministrationModule = new AdministrationModule();\n            MeetingsModule = new MeetingsModule();\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            MeetingsStartup.Stop();\n            AdministrationStartup.Stop();\n            SystemClock.Reset();\n        }\n\n        protected static void AssertBrokenRule<TRule>(AsyncTestDelegate testDelegate)\n            where TRule : class, IBusinessRule\n        {\n            var message = $\"Expected {typeof(TRule).Name} broken rule\";\n            var businessRuleValidationException =\n                Assert.CatchAsync<BusinessRuleValidationException>(testDelegate, message);\n            if (businessRuleValidationException != null)\n            {\n                Assert.That(businessRuleValidationException.BrokenRule, Is.TypeOf<TRule>(), message);\n            }\n        }\n\n        protected static async Task AssertEventually(IProbe probe, int timeout)\n        {\n            await new Poller(timeout).CheckAsync(probe);\n        }\n\n        private static async Task ClearDatabase(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [administration].[InboxMessages] \" +\n                               \"DELETE FROM [administration].[InternalCommands] \" +\n                               \"DELETE FROM [administration].[OutboxMessages] \" +\n                               \"DELETE FROM [administration].[MeetingGroupProposals] \" +\n                               \"DELETE FROM [administration].[Members] \" +\n                               \"DELETE FROM [meetings].[InboxMessages] \" +\n                               \"DELETE FROM [meetings].[InternalCommands] \" +\n                               \"DELETE FROM [meetings].[OutboxMessages] \" +\n                               \"DELETE FROM [meetings].[MeetingAttendees] \" +\n                               \"DELETE FROM [meetings].[MeetingGroupMembers] \" +\n                               \"DELETE FROM [meetings].[MeetingGroupProposals] \" +\n                               \"DELETE FROM [meetings].[MeetingGroups] \" +\n                               \"DELETE FROM [meetings].[MeetingNotAttendees] \" +\n                               \"DELETE FROM [meetings].[MeetingCommentingConfigurations] \" +\n                               \"DELETE FROM [meetings].[Meetings] \" +\n                               \"DELETE FROM [meetings].[MeetingWaitlistMembers] \" +\n                               \"DELETE FROM [meetings].[Members] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/CompanyName.MyMeetings.SUT.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\" />"
  },
  {
    "path": "src/Tests/SUT/Helpers/MeetingGroupsFactory.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Application.MeetingGroupProposals.AcceptMeetingGroupProposal;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroupProposals.ProposeMeetingGroup;\nusing CompanyName.MyMeetings.SUT.SeedWork;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class MeetingGroupsFactory\n    {\n        public static async Task<Guid> GivenMeetingGroup(\n            IMeetingsModule meetingsModule,\n            IAdministrationModule administrationModule,\n            string connectionString,\n            string name,\n            string description,\n            string locationCity,\n            string locationCountryCode)\n        {\n            var meetingGroupId = await meetingsModule.ExecuteCommandAsync(new ProposeMeetingGroupCommand(\n                name,\n                description,\n                locationCity,\n                locationCountryCode));\n\n            await AsyncOperationsHelper.WaitForProcessing(connectionString);\n\n            await administrationModule.ExecuteCommandAsync(new AcceptMeetingGroupProposalCommand(meetingGroupId));\n\n            await AsyncOperationsHelper.WaitForProcessing(connectionString);\n\n            return meetingGroupId;\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/TestMeetingFactory.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.CreateMeeting;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class TestMeetingFactory\n    {\n        internal static async Task<Guid> GivenMeeting(\n            IMeetingsModule meetingsModule,\n            Guid meetingGroupId,\n            string title,\n            DateTime termStartDate,\n            DateTime termEndDate,\n            string description,\n            string meetingLocationName,\n            string meetingLocationAddress,\n            string meetingLocationPostalCode,\n            string meetingLocationCity,\n            int? attendeesLimit,\n            int guestsLimit,\n            DateTime? rsvpTermStartDate,\n            DateTime? rsvpTermEndDate,\n            decimal? eventFeeValue,\n            string eventFeeCurrency,\n            List<Guid> hostMemberIds)\n        {\n            return await meetingsModule.ExecuteCommandAsync(new CreateMeetingCommand(\n                meetingGroupId,\n                title,\n                termStartDate,\n                termEndDate,\n                description,\n                meetingLocationName,\n                meetingLocationAddress,\n                meetingLocationPostalCode,\n                meetingLocationCity,\n                attendeesLimit,\n                guestsLimit,\n                rsvpTermStartDate,\n                rsvpTermEndDate,\n                eventFeeValue,\n                eventFeeCurrency,\n                hostMemberIds));\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/TestMeetingGroupManager.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.MeetingGroups.JoinToGroup;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class TestMeetingGroupManager\n    {\n        internal static async Task JoinToGroup(IMeetingsModule meetingsModule, Guid meetingGroupId)\n        {\n            await meetingsModule.ExecuteCommandAsync(new JoinToGroupCommand(meetingGroupId));\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/TestMeetingManager.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Meetings.AddMeetingAttendee;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class TestMeetingManager\n    {\n        internal static async Task AddAttendee(IMeetingsModule meetingsModule, Guid meetingId, int guestsNumber)\n        {\n            await meetingsModule.ExecuteCommandAsync(new AddMeetingAttendeeCommand(meetingId, guestsNumber));\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/TestPaymentsManager.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.BuySubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetPayerSubscription;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionDetails;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.GetSubscriptionPayments;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Subscriptions.MarkSubscriptionPaymentAsPaid;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.SUT.SeedWork;\nusing CompanyName.MyMeetings.SUT.SeedWork.Probing;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class TestPaymentsManager\n    {\n        public static async Task BuySubscription(\n            IPaymentsModule paymentsModule,\n            IExecutionContextAccessor executionContextAccessor)\n        {\n            var subscriptionPaymentId = await paymentsModule.ExecuteCommandAsync(new BuySubscriptionCommand(\n                SubscriptionPeriod.Month.Code,\n                \"PL\",\n                60,\n                \"PLN\"));\n\n            await TestBase.GetEventually(\n                new GetSubscriptionPaymentsProbe(\n                    paymentsModule,\n                    executionContextAccessor.UserId,\n                    x => true),\n                10000);\n\n            await paymentsModule.ExecuteCommandAsync(\n                new MarkSubscriptionPaymentAsPaidCommand(subscriptionPaymentId));\n\n            await TestBase.GetEventually(\n                new GetPayerSubscriptionProbe(\n                    paymentsModule,\n                    executionContextAccessor.UserId),\n                10000);\n        }\n\n        private class GetSubscriptionPaymentsProbe : IProbe<List<SubscriptionPaymentDto>>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Guid _payerId;\n\n            private readonly Func<List<SubscriptionPaymentDto>, bool> _condition;\n\n            public GetSubscriptionPaymentsProbe(\n                IPaymentsModule paymentsModule,\n                Guid payerId,\n                Func<List<SubscriptionPaymentDto>, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n\n                _payerId = payerId;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(List<SubscriptionPaymentDto> sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<List<SubscriptionPaymentDto>> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetSubscriptionPaymentsQuery(_payerId));\n            }\n\n            public string DescribeFailureTo()\n            {\n                return $\"Cannot get subscription payments for PayerId: {_payerId}\";\n            }\n        }\n\n        private class GetPayerSubscriptionProbe : IProbe<SubscriptionDetailsDto>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            public GetPayerSubscriptionProbe(\n                IPaymentsModule paymentsModule,\n                Guid payerId)\n            {\n                _paymentsModule = paymentsModule;\n            }\n\n            public bool IsSatisfied(SubscriptionDetailsDto sample)\n            {\n                return sample != null;\n            }\n\n            public async Task<SubscriptionDetailsDto> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetAuthenticatedPayerSubscriptionQuery());\n            }\n\n            public string DescribeFailureTo() => \"Subscription read model is not in expected state\";\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/TestPriceListManager.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.CreatePriceListItem;\nusing CompanyName.MyMeetings.Modules.Payments.Application.PriceListItems.GetPriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.PriceListItems;\nusing CompanyName.MyMeetings.Modules.Payments.Domain.Subscriptions;\nusing CompanyName.MyMeetings.SUT.SeedWork;\nusing CompanyName.MyMeetings.SUT.SeedWork.Probing;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class TestPriceListManager\n    {\n        internal static async Task AddPriceListItems(\n            IPaymentsModule paymentsModule,\n            string connectionString)\n        {\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.Month.Code,\n                PriceListItemCategory.New.Code,\n                \"PL\",\n                60,\n                \"PLN\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.New.Code,\n                \"PL\",\n                320,\n                \"PLN\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.Month.Code,\n                PriceListItemCategory.New.Code,\n                \"US\",\n                15,\n                \"USD\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.New.Code,\n                \"US\",\n                80,\n                \"USD\"));\n\n            await paymentsModule.ExecuteCommandAsync(new CreatePriceListItemCommand(\n                SubscriptionPeriod.HalfYear.Code,\n                PriceListItemCategory.Renewal.Code,\n                \"PL\",\n                320,\n                \"PLN\"));\n\n            await TestBase.GetEventually(new GetPriceListProbe(paymentsModule, x => x.Count == 5), 5000);\n\n            await AsyncOperationsHelper.WaitForProcessing(connectionString);\n        }\n\n        private class GetPriceListProbe : IProbe<List<PriceListItemDto>>\n        {\n            private readonly IPaymentsModule _paymentsModule;\n\n            private readonly Func<List<PriceListItemDto>, bool> _condition;\n\n            public GetPriceListProbe(\n                IPaymentsModule paymentsModule,\n                Func<List<PriceListItemDto>, bool> condition)\n            {\n                _paymentsModule = paymentsModule;\n                _condition = condition;\n            }\n\n            public bool IsSatisfied(List<PriceListItemDto> sample)\n            {\n                return sample != null && _condition(sample);\n            }\n\n            public async Task<List<PriceListItemDto>> GetSampleAsync()\n            {\n                return await _paymentsModule.ExecuteQueryAsync(new GetPriceListItemsQuery());\n            }\n\n            public string DescribeFailureTo()\n            {\n                return \"Cannot get price list for specified condition\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Helpers/UsersFactory.cs",
    "content": "﻿using CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.ConfirmUserRegistration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.UserRegistrations.RegisterNewUser;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Users.AddAdminUser;\nusing CompanyName.MyMeetings.SUT.SeedWork;\n\nnamespace CompanyName.MyMeetings.SUT.Helpers\n{\n    internal static class UsersFactory\n    {\n        public static async Task GivenAdmin(\n            IUserAccessModule userAccessModule,\n            string login,\n            string password,\n            string name,\n            string firstName,\n            string lastName,\n            string email)\n        {\n            await userAccessModule.ExecuteCommandAsync(new AddAdminUserCommand(\n                login,\n                password,\n                firstName,\n                lastName,\n                name,\n                email));\n        }\n\n        public static async Task<Guid> GivenUser(\n            IRegistrationsModule registrationsModule,\n            string connectionString,\n            string login,\n            string password,\n            string firstName,\n            string lastName,\n            string email)\n        {\n            var userRegistrationId = await registrationsModule.ExecuteCommandAsync(new RegisterNewUserCommand(\n                login,\n                password,\n                email,\n                firstName,\n                lastName,\n                email));\n\n            await registrationsModule.ExecuteCommandAsync(new ConfirmUserRegistrationCommand(userRegistrationId));\n\n            await AsyncOperationsHelper.WaitForProcessing(connectionString);\n\n            return userRegistrationId;\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/Scripts/SeedPermissions.sql",
    "content": "﻿-- Permissions\nINSERT INTO users.[Permissions] ([Code], [Name]) VALUES\n\t-- Meetings\n\t('GetMeetingGroupProposals', 'GetMeetingGroupProposals'),\n\t('ProposeMeetingGroup', 'ProposeMeetingGroup'),\n\t('CreateNewMeeting','CreateNewMeeting'),\n\t('EditMeeting','EditMeeting'),\n\t('AddMeetingAttendee','AddMeetingAttendee'),\n\t('RemoveMeetingAttendee','RemoveMeetingAttendee'),\n\t('AddNotAttendee','AddNotAttendee'),\n\t('ChangeNotAttendeeDecision','ChangeNotAttendeeDecision'),\n\t('SignUpMemberToWaitlist','SignUpMemberToWaitlist'),\n\t('SignOffMemberFromWaitlist','SignOffMemberFromWaitlist'),\n\t('SetMeetingHostRole','SetMeetingHostRole'),\n\t('SetMeetingAttendeeRole','SetMeetingAttendeeRole'),\n\t('CancelMeeting','CancelMeeting'),\n\t('GetAllMeetingGroups','GetAllMeetingGroups'),\n\t('EditMeetingGroupGeneralAttributes','EditMeetingGroupGeneralAttributes'),\n\t('JoinToGroup','JoinToGroup'),\n\t('LeaveMeetingGroup','LeaveMeetingGroup'),\n\t('AddMeetingComment','AddMeetingComment'),\n\t('EditMeetingComment','EditMeetingComment'),\n\t('RemoveMeetingComment','RemoveMeetingComment'),\n\t('AddMeetingCommentReply','AddMeetingCommentReply'),\n\t('LikeMeetingComment','LikeMeetingComment'),\n\t('UnlikeMeetingComment','UnlikeMeetingComment'),\n\t('EnableMeetingCommenting','EnableMeetingCommenting'),\n\t('DisableMeetingCommenting','DisableMeetingCommenting'),\n\t('MyMeetingGroupsView','MyMeetingGroupsView'),\n\t('AllMeetingGroupsView','AllMeetingGroupsView'),\n\t('SubscriptionView','SubscriptionView'),\n\t('EmailsView','EmailsView'),\n\t('MyMeetingsView','MyMeetingsView'),\n\t('GetAuthenticatedMemberMeetings','GetAuthenticatedMemberMeetings'),\n\n\t-- Administration\n\t('AcceptMeetingGroupProposal','AcceptMeetingGroupProposal'),\n\t('AdministrationsView','AdministrationsView'),\n\n\t-- Payments\n\t('RegisterPayment','RegisterPayment'),\n\t('BuySubscription','BuySubscription'),\n\t('RenewSubscription','RenewSubscription'),\n\t('CreatePriceListItem','CreatePriceListItem'),\n\t('ActivatePriceListItem','ActivatePriceListItem'),\n\t('DeactivatePriceListItem','DeactivatePriceListItem'),\n\t('ChangePriceListItemAttributes','ChangePriceListItemAttributes'),\n\t('GetAuthenticatedPayerSubscription','GetAuthenticatedPayerSubscription'),\n\t('GetPriceListItem','GetPriceListItem')\n\n-- Role To Permissions\n---- Meetings\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingGroupProposals')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'ProposeMeetingGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'CreateNewMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RemoveMeetingAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddNotAttendee')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'ChangeNotAttendeeDecision')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SignUpMemberToWaitlist')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SignOffMemberFromWaitlist')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SetMeetingHostRole')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SetMeetingAttendeeRole')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'CancelMeeting')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAllMeetingGroups')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeetingGroupGeneralAttributes')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'JoinToGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'LeaveMeetingGroup')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EditMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RemoveMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AddMeetingCommentReply')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'LikeMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'UnlikeMeetingComment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedMemberMeetingGroups')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingGroupDetails')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingDetails')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetMeetingAttendees')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'MyMeetingsGroupsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'SubscriptionView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'EmailsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'AllMeetingGroupsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'MyMeetingsView')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedMemberMeetings')\n\n---- Administration\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'AcceptMeetingGroupProposal')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'AdministrationsView')\n\n---- Payments\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RegisterPayment')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'BuySubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'RenewSubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetAuthenticatedPayerSubscription')\nINSERT INTO users.RolesToPermissions VALUES ('Member', 'GetPriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'CreatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'ActivatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'DeactivatePriceListItem')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'ChangePriceListItemAttributes')\nINSERT INTO users.RolesToPermissions VALUES ('Administrator', 'GetPriceListItem')"
  },
  {
    "path": "src/Tests/SUT/SeedWork/AsyncOperationsHelper.cs",
    "content": "﻿using System.Data.SqlClient;\nusing System.Diagnostics;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.SUT.SeedWork\n{\n    internal static class AsyncOperationsHelper\n    {\n        public static async Task WaitForProcessing(string connectionString, int timeoutInSeconds = 20)\n        {\n            await using var sqlConnection = new SqlConnection(connectionString);\n\n            var start = Stopwatch.StartNew();\n            while (start.Elapsed.Seconds < timeoutInSeconds)\n            {\n                var internalCommandsCountUsers = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [users].[InternalCommands] AS [InternalCommand] \n                    WHERE [InternalCommand].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var inboxCountUsers = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [users].[InboxMessages] AS [InboxMessage] \n                    WHERE [InboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var outboxCountUsers = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [users].[OutboxMessages] AS [OutboxMessage] \n                    WHERE [OutboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var internalCommandsCountMeetings = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [meetings].[InternalCommands] AS [InternalCommand] \n                    WHERE [InternalCommand].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var inboxCountMeetings = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [meetings].[InboxMessages] AS [InboxMessage] \n                    WHERE [InboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var outboxCountMeetings = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [meetings].[OutboxMessages] AS [OutboxMessage] \n                    WHERE [OutboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var internalCommandsCountAdministration = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [administration].[InternalCommands] AS [InternalCommand] \n                    WHERE [InternalCommand].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var inboxCountMeetingsAdministration = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [administration].[InboxMessages] AS [InboxMessage] \n                    WHERE [InboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                var outboxCountMeetingsAdministration = await sqlConnection.ExecuteScalarAsync<int>(\n                    \"\"\"\n                    SELECT COUNT(*) \n                    FROM [administration].[OutboxMessages] AS [OutboxMessage] \n                    WHERE [OutboxMessage].[ProcessedDate] IS NULL\n                    \"\"\");\n\n                if (internalCommandsCountUsers == 0 &&\n                    inboxCountUsers == 0 &&\n                    outboxCountUsers == 0 &&\n                    internalCommandsCountMeetings == 0 &&\n                    inboxCountMeetings == 0 &&\n                    outboxCountMeetings == 0 &&\n                    internalCommandsCountAdministration == 0 &&\n                    inboxCountMeetingsAdministration == 0 &&\n                    outboxCountMeetingsAdministration == 0)\n                {\n                    return;\n                }\n\n                Thread.Sleep(100);\n            }\n\n            throw new Exception(\"Timeout for processing elapsed.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/DatabaseCleaner.cs",
    "content": "﻿using System.Data;\nusing Dapper;\n\nnamespace CompanyName.MyMeetings.SUT.SeedWork\n{\n    internal static class DatabaseCleaner\n    {\n        internal static async Task ClearAllData(IDbConnection connection)\n        {\n            await ClearAdministration(connection);\n\n            await ClearApp(connection);\n\n            await ClearMeetings(connection);\n\n            await ClearPayments(connection);\n\n            await ClearUsers(connection);\n\n            await ClearRegistration(connection);\n        }\n\n        private static async Task ClearUsers(IDbConnection connection)\n        {\n            var clearUsersSql =\n                \"DELETE FROM [users].[InboxMessages] \" +\n                \"DELETE FROM [users].[InternalCommands] \" +\n                \"DELETE FROM [users].[OutboxMessages] \" +\n                \"DELETE FROM [users].[Permissions] \" +\n                \"DELETE FROM [users].[RolesToPermissions] \" +\n                \"DELETE FROM [users].[UserRoles] \" +\n                \"DELETE FROM [users].[Users] \";\n\n            await connection.ExecuteScalarAsync(clearUsersSql);\n        }\n\n        private static async Task ClearPayments(IDbConnection connection)\n        {\n            var clearPaymentsSql =\n                \"DELETE FROM [payments].[InboxMessages] \" +\n                \"DELETE FROM [payments].[InternalCommands] \" +\n                \"DELETE FROM [payments].[MeetingFees] \" +\n                \"DELETE FROM [payments].[Messages] \" +\n                \"DELETE FROM [payments].[OutboxMessages] \" +\n                \"DELETE FROM [payments].[Payers] \" +\n                \"DELETE FROM [payments].[PriceListItems] \" +\n                \"DELETE FROM [payments].[Streams] \" +\n                \"DELETE FROM [payments].[SubscriptionCheckpoints] \" +\n                \"DELETE FROM [payments].[SubscriptionDetails] \" +\n                \"DELETE FROM [payments].[SubscriptionPayments] \";\n\n            await connection.ExecuteScalarAsync(clearPaymentsSql);\n        }\n\n        private static async Task ClearMeetings(IDbConnection connection)\n        {\n            var clearMeetingsSql =\n                \"DELETE FROM [meetings].[Countries] \" +\n                \"DELETE FROM [meetings].[InboxMessages] \" +\n                \"DELETE FROM [meetings].[InternalCommands] \" +\n                \"DELETE FROM [meetings].[MeetingAttendees] \" +\n                \"DELETE FROM [meetings].[MeetingCommentingConfigurations] \" +\n                \"DELETE FROM [meetings].[MeetingComments] \" +\n                \"DELETE FROM [meetings].[MeetingGroupMembers] \" +\n                \"DELETE FROM [meetings].[MeetingGroupProposals] \" +\n                \"DELETE FROM [meetings].[MeetingGroups] \" +\n                \"DELETE FROM [meetings].[MeetingMemberCommentLikes] \" +\n                \"DELETE FROM [meetings].[MeetingNotAttendees] \" +\n                \"DELETE FROM [meetings].[Meetings] \" +\n                \"DELETE FROM [meetings].[MeetingWaitlistMembers] \" +\n                \"DELETE FROM [meetings].[Members] \" +\n                \"DELETE FROM [meetings].[MemberSubscriptions] \" +\n                \"DELETE FROM [meetings].[OutboxMessages]\";\n\n            await connection.ExecuteScalarAsync(clearMeetingsSql);\n        }\n\n        private static async Task ClearApp(IDbConnection connection)\n        {\n            var clearAppSql =\n                \"DELETE FROM [app].[Emails] \";\n            await connection.ExecuteScalarAsync(clearAppSql);\n        }\n\n        private static async Task ClearAdministration(IDbConnection connection)\n        {\n            var clearAdministrationSql =\n                \"DELETE FROM [administration].[InboxMessages] \" +\n                \"DELETE FROM [administration].[InternalCommands] \" +\n                \"DELETE FROM [administration].[MeetingGroupProposals] \" +\n                \"DELETE FROM [administration].[Members] \" +\n                \"DELETE FROM [administration].[OutboxMessages] \";\n\n            await connection.ExecuteScalarAsync(clearAdministrationSql);\n        }\n\n        private static async Task ClearRegistration(IDbConnection connection)\n        {\n            const string sql = \"DELETE FROM [registrations].[InboxMessages] \" +\n                               \"DELETE FROM [registrations].[InternalCommands] \" +\n                               \"DELETE FROM [registrations].[OutboxMessages] \" +\n                               \"DELETE FROM [registrations].[UserRegistrations] \";\n\n            await connection.ExecuteScalarAsync(sql);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/ExecutionContextMock.cs",
    "content": "﻿using CompanyName.MyMeetings.BuildingBlocks.Application;\n\nnamespace CompanyName.MyMeetings.SUT.SeedWork\n{\n    public class ExecutionContextMock : IExecutionContextAccessor\n    {\n        public ExecutionContextMock(Guid userId)\n        {\n            UserId = userId;\n        }\n\n        public Guid UserId { get; private set; }\n\n        public Guid CorrelationId { get; }\n\n        public bool IsAvailable { get; }\n\n        public void SetUserId(Guid userId)\n        {\n            this.UserId = userId;\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/Probing/AssertErrorException.cs",
    "content": "﻿namespace CompanyName.MyMeetings.SUT.SeedWork.Probing\n{\n    public class AssertErrorException : Exception\n    {\n        public AssertErrorException(string message)\n            : base(message)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/Probing/IProbe.cs",
    "content": "﻿namespace CompanyName.MyMeetings.SUT.SeedWork.Probing\n{\n    public interface IProbe\n    {\n        bool IsSatisfied();\n\n        Task SampleAsync();\n\n        string DescribeFailureTo();\n    }\n\n    public interface IProbe<T>\n    {\n        bool IsSatisfied(T sample);\n\n        Task<T> GetSampleAsync();\n\n        string DescribeFailureTo();\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/Probing/Poller.cs",
    "content": "﻿namespace CompanyName.MyMeetings.SUT.SeedWork.Probing\n{\n    public class Poller\n    {\n        private readonly int _timeoutMillis;\n\n        private readonly int _pollDelayMillis;\n\n        public Poller(int timeoutMillis)\n        {\n            _timeoutMillis = timeoutMillis;\n            _pollDelayMillis = 1000;\n        }\n\n        public async Task CheckAsync(IProbe probe)\n        {\n            var timeout = new Timeout(_timeoutMillis);\n            while (!probe.IsSatisfied())\n            {\n                if (timeout.HasTimedOut())\n                {\n                    throw new AssertErrorException(DescribeFailureOf(probe));\n                }\n\n                await Task.Delay(_pollDelayMillis);\n                await probe.SampleAsync();\n            }\n        }\n\n        public async Task<T> GetAsync<T>(IProbe<T> probe)\n            where T : class\n        {\n            var timeout = new Timeout(_timeoutMillis);\n            T sample = null;\n            while (!probe.IsSatisfied(sample))\n            {\n                if (timeout.HasTimedOut())\n                {\n                    throw new AssertErrorException(DescribeFailureOf(probe));\n                }\n\n                await Task.Delay(_pollDelayMillis);\n                sample = await probe.GetSampleAsync();\n            }\n\n            return sample;\n        }\n\n        private static string DescribeFailureOf(IProbe probe)\n        {\n            return probe.DescribeFailureTo();\n        }\n\n        private static string DescribeFailureOf<T>(IProbe<T> probe)\n        {\n            return probe.DescribeFailureTo();\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/SeedWork/Probing/Timeout.cs",
    "content": "﻿namespace CompanyName.MyMeetings.SUT.SeedWork.Probing\n{\n    public class Timeout\n    {\n        private readonly DateTime _endTime;\n\n        public Timeout(int duration)\n        {\n            this._endTime = DateTime.Now.AddMilliseconds(duration);\n        }\n\n        public bool HasTimedOut()\n        {\n            return DateTime.Now > _endTime;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Tests/SUT/SeedWork/TestBase.cs",
    "content": "﻿using System.Data.SqlClient;\nusing CompanyName.MyMeetings.BuildingBlocks.Application.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.Emails;\nusing CompanyName.MyMeetings.BuildingBlocks.Infrastructure.EventBus;\nusing CompanyName.MyMeetings.Modules.Administration.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Administration.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Meetings.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Meetings.Domain.SharedKernel;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Meetings.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Payments.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Payments.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.Registrations.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure;\nusing CompanyName.MyMeetings.Modules.Registrations.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.Modules.UserAccess.Application.Contracts;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure;\nusing CompanyName.MyMeetings.Modules.UserAccess.Infrastructure.Configuration;\nusing CompanyName.MyMeetings.SUT.SeedWork.Probing;\nusing Dapper;\nusing NSubstitute;\nusing NUnit.Framework;\nusing Serilog;\n\nnamespace CompanyName.MyMeetings.SUT.SeedWork\n{\n    public class TestBase\n    {\n        protected string ConnectionString { get; set; }\n\n        protected virtual bool PerformDatabaseCleanup => false;\n\n        protected virtual bool CreatePermissions => true;\n\n        protected IEmailSender EmailSender { get; private set; }\n\n        protected ILogger Logger { get; private set; }\n\n        protected IUserAccessModule UserAccessModule { get; private set; }\n\n        protected IRegistrationsModule RegistrationsModule { get; private set; }\n\n        protected IMeetingsModule MeetingsModule { get; private set; }\n\n        protected IAdministrationModule AdministrationModule { get; private set; }\n\n        protected IPaymentsModule PaymentsModule { get; private set; }\n\n        protected ExecutionContextMock ExecutionContextAccessor { get; private set; }\n\n        protected IEventsBus EventsBus { get; private set; }\n\n        [SetUp]\n        public async Task BeforeEachTest()\n        {\n            SetConnectionString();\n\n            if (PerformDatabaseCleanup)\n            {\n                await this.ClearDatabase();\n            }\n\n            if (CreatePermissions)\n            {\n                await this.SeedPermissions();\n            }\n\n            ExecutionContextAccessor = new ExecutionContextMock(Guid.NewGuid());\n\n            var emailsConfiguration = new EmailsConfiguration(\"from@email.com\");\n\n            Logger = Substitute.For<ILogger>();\n\n            EventsBus = new InMemoryEventBusClient(Logger);\n\n            InitializeRegistrationsModule(emailsConfiguration);\n\n            InitializeUserAccessModule(emailsConfiguration);\n\n            InitializeMeetingsModule(emailsConfiguration);\n\n            InitializeAdministrationModule();\n\n            PaymentsStartup.Initialize(\n                ConnectionString,\n                ExecutionContextAccessor,\n                Logger,\n                emailsConfiguration,\n                EventsBus,\n                true,\n                100);\n\n            PaymentsModule = new PaymentsModule();\n        }\n\n        public static async Task<T> GetEventually<T>(IProbe<T> probe, int timeout)\n            where T : class\n        {\n            var poller = new Poller(timeout);\n\n            return await poller.GetAsync(probe);\n        }\n\n        [TearDown]\n        public void AfterEachTest()\n        {\n            SystemClock.Reset();\n            Modules.Payments.Domain.SeedWork.SystemClock.Reset();\n        }\n\n        protected async Task WaitForAsyncOperations()\n        {\n            await AsyncOperationsHelper.WaitForProcessing(ConnectionString);\n        }\n\n        protected void SetDate(DateTime date)\n        {\n            SystemClock.Set(date);\n            Modules.Payments.Domain.SeedWork.SystemClock.Set(date);\n        }\n\n        protected async Task ExecuteScript(string scriptPath)\n        {\n            var sql = await File.ReadAllTextAsync(scriptPath);\n\n            await using var sqlConnection = new SqlConnection(ConnectionString);\n            await sqlConnection.ExecuteScalarAsync(sql);\n        }\n\n        private void InitializeAdministrationModule()\n        {\n            AdministrationStartup.Initialize(\n                ConnectionString,\n                ExecutionContextAccessor,\n                Logger,\n                EventsBus,\n                100);\n\n            AdministrationModule = new AdministrationModule();\n        }\n\n        private void InitializeMeetingsModule(EmailsConfiguration emailsConfiguration)\n        {\n            MeetingsStartup.Initialize(\n                ConnectionString,\n                ExecutionContextAccessor,\n                Logger,\n                emailsConfiguration,\n                EventsBus,\n                100);\n\n            MeetingsModule = new MeetingsModule();\n        }\n\n        private async Task SeedPermissions()\n        {\n            await ExecuteScript(\"Scripts/SeedPermissions.sql\");\n        }\n\n        private void InitializeUserAccessModule(EmailsConfiguration emailsConfiguration)\n        {\n            Logger = Substitute.For<ILogger>();\n            EmailSender = Substitute.For<IEmailSender>();\n\n            UserAccessStartup.Initialize(\n                ConnectionString,\n                ExecutionContextAccessor,\n                Logger,\n                emailsConfiguration,\n                \"key\",\n                EmailSender,\n                EventsBus,\n                100);\n\n            UserAccessModule = new UserAccessModule();\n        }\n\n        private void InitializeRegistrationsModule(EmailsConfiguration emailsConfiguration)\n        {\n            Logger = Substitute.For<ILogger>();\n            EmailSender = Substitute.For<IEmailSender>();\n\n            RegistrationsStartup.Initialize(\n                ConnectionString,\n                ExecutionContextAccessor,\n                Logger,\n                emailsConfiguration,\n                \"key\",\n                EmailSender,\n                EventsBus,\n                100);\n\n            RegistrationsModule = new RegistrationsModule();\n        }\n\n        private void SetConnectionString()\n        {\n            const string connectionStringEnvironmentVariable = \"MyMeetings_SUTDatabaseConnectionString\";\n            ConnectionString = Environment.GetEnvironmentVariable(connectionStringEnvironmentVariable);\n            if (ConnectionString == null)\n            {\n                throw new ApplicationException(\n                    $\"Define connection string to SUT database using environment variable: {connectionStringEnvironmentVariable}\");\n            }\n        }\n\n        private async Task ClearDatabase()\n        {\n            await using var sqlConnection = new SqlConnection(ConnectionString);\n            await DatabaseCleaner.ClearAllData(sqlConnection);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/TestCases/CleanDatabaseTestCase.cs",
    "content": "using CompanyName.MyMeetings.SUT.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.SUT.TestCases\n{\n    public class CleanDatabaseTestCase : TestBase\n    {\n        protected override bool PerformDatabaseCleanup => true;\n\n        protected override bool CreatePermissions => false;\n\n        [Test]\n        public void Prepare()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/TestCases/CreateMeeting.cs",
    "content": "﻿using CompanyName.MyMeetings.SUT.Helpers;\nusing CompanyName.MyMeetings.SUT.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.SUT.TestCases\n{\n    public class CreateMeeting : TestBase\n    {\n        protected override bool PerformDatabaseCleanup => true;\n\n        [Test]\n        public async Task Prepare()\n        {\n            await UsersFactory.GivenAdmin(\n                UserAccessModule,\n                \"testAdmin@mail.com\",\n                \"testAdminPass\",\n                \"Jane Doe\",\n                \"Jane\",\n                \"Doe\",\n                \"testAdmin@mail.com\");\n\n            var userId = await UsersFactory.GivenUser(\n                RegistrationsModule,\n                ConnectionString,\n                \"adamSmith@mail.com\",\n                \"adamSmithPass\",\n                \"Adam\",\n                \"Smith\",\n                \"adamSmith@mail.com\");\n\n            ExecutionContextAccessor.SetUserId(userId);\n\n            var meetingGroupId = await MeetingGroupsFactory.GivenMeetingGroup(\n                MeetingsModule,\n                AdministrationModule,\n                ConnectionString,\n                \"Software Craft\",\n                \"Group for software craft passionates\",\n                \"Warsaw\",\n                \"PL\");\n\n            await TestPriceListManager.AddPriceListItems(PaymentsModule, ConnectionString);\n\n            await TestPaymentsManager.BuySubscription(\n                PaymentsModule,\n                ExecutionContextAccessor);\n\n            SetDate(new DateTime(2022, 7, 1, 10, 0, 0));\n\n            var meetingId = await TestMeetingFactory.GivenMeeting(\n                MeetingsModule,\n                meetingGroupId,\n                \"Tactical DDD\",\n                new DateTime(2022, 7, 10, 18, 0, 0),\n                new DateTime(2022, 7, 10, 20, 0, 0),\n                \"Meeting about Tactical DDD patterns\",\n                \"Location Name\",\n                \"Location Address\",\n                \"01-755\",\n                \"Warsaw\",\n                50,\n                0,\n                null,\n                null,\n                0,\n                null,\n                []);\n\n            var attendeeUserId = await UsersFactory.GivenUser(\n                RegistrationsModule,\n                ConnectionString,\n                \"rickmorty@mail.com\",\n                \"rickmortyPass\",\n                \"Rick\",\n                \"Morty\",\n                \"rickmorty@mail.com\");\n\n            ExecutionContextAccessor.SetUserId(attendeeUserId);\n\n            await TestMeetingGroupManager.JoinToGroup(MeetingsModule, meetingGroupId);\n\n            await TestMeetingManager.AddAttendee(MeetingsModule, meetingId, guestsNumber: 1);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/SUT/TestCases/OnlyAdminTestCase.cs",
    "content": "using CompanyName.MyMeetings.SUT.Helpers;\nusing CompanyName.MyMeetings.SUT.SeedWork;\nusing NUnit.Framework;\n\nnamespace CompanyName.MyMeetings.SUT.TestCases\n{\n    public class OnlyAdminTestCase : TestBase\n    {\n        protected override bool PerformDatabaseCleanup => true;\n\n        [Test]\n        public async Task Prepare()\n        {\n            await UsersFactory.GivenAdmin(\n                UserAccessModule,\n                \"testAdmin@mail.com\",\n                \"testAdminPass\",\n                \"Jane Doe\",\n                \"Jane\",\n                \"Doe\",\n                \"testAdmin@mail.com\");\n        }\n    }\n}"
  },
  {
    "path": "src/entrypoint.sh",
    "content": "#!/bin/bash\necho \"Waiting 60 seconds to start backend\"\n\nsleep 60;\n\necho \"Backend starting...\"\n\ndotnet CompanyName.MyMeetings.API.dll"
  },
  {
    "path": "src/global.json",
    "content": "{\n  \"sdk\": {\n    \"version\": \"8.0.0\",\n    \"rollForward\": \"latestFeature\",\n    \"allowPrerelease\": false\n  }\n}"
  },
  {
    "path": "src/stylecop.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json\",\n  \"settings\": {\n    \"documentationRules\": {\n      \"companyName\": \"Kamil Grzybek\",\n      \"copyrightText\":\n        \"Copyright (c) {companyName}. All rights reserved.\\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.\",\n      \"variables\": {\n        \"licenseName\": \"MIT\",\n        \"licenseFile\": \"LICENSE\"\n      },\n      \"headerDecoration\": \"-----------------------------------------------------------------------\"\n    }\n  }\n}\n"
  }
]