[
  {
    "path": ".aspire/settings.json",
    "content": "{\n  \"appHostPath\": \"../src/Aspire/src/AppHost/AppHost.csproj\"\n}"
  },
  {
    "path": ".config/dotnet-tools.json",
    "content": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"dotnet-outdated-tool\": {\n      \"version\": \"4.6.9\",\n      \"commands\": [\n        \"dotnet-outdated\"\n      ]\n    },\n    \"dotnet-ef\": {\n      \"version\": \"10.0.3\",\n      \"commands\": [\n        \"dotnet-ef\"\n      ]\n    },\n    \"aspire.cli\": {\n      \"version\": \"13.1.1\",\n      \"commands\": [\n        \"aspire\"\n      ]\n    },\n    \"csharpier\": {\n      \"version\": \"0.30.6\",\n      \"commands\": [\n        \"dotnet-csharpier\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": ".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**/.tye/\n**/secrets.dev.yaml\n**/values.dev.yaml\n**/*.jwk\n**/keys\nLICENSE\nREADME.md\nCHANGELOG.md\n\n"
  },
  {
    "path": ".editorconfig",
    "content": "# https://editorconfig.org\n# https://www.jetbrains.com/help/resharper/Using_EditorConfig.html\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files\n# When opening a file, EditorConfig plugins look for a file named .editorconfig in the directory of the opened file and in every parent directory. A search for .editorconfig files will stop if the root filepath is reached or an EditorConfig file with `root=true` is found.\n\n# Remove the line below if you want to inherit .editorconfig settings from higher directories\n\n##################################################################################\n## https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/\n## https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/\n## Microsoft Rules\nroot = true\n\n# All files\n[*]\nindent_style = space\n\n# Xml files\n[*.xml]\nindent_size = 2\n\n# C# files\n[*.cs]\n\n#### Core EditorConfig Options ####\n\n# Indentation and spacing\nindent_size = 4\ntab_width = 4\nmax_line_length = 120\n\n# New line preferences\ninsert_final_newline = false\n\n#### .NET Coding Conventions ####\n[*.{cs,vb}]\n\n# Organize usings\ndotnet_separate_import_directive_groups = false\ndotnet_sort_system_directives_first = true\nfile_header_template = unset\n\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?#enable-on-build\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/language-rules#option-format\n# this. and Me. preferences\ndotnet_style_qualification_for_event = false:silent\ndotnet_style_qualification_for_field = false:silent\ndotnet_style_qualification_for_method = false:silent\ndotnet_style_qualification_for_property = false:silent\n\n# Language keywords vs BCL types preferences\ndotnet_style_predefined_type_for_locals_parameters_members = true:silent\ndotnet_style_predefined_type_for_member_access = true:silent\n\n# Parentheses preferences\ndotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent\ndotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent\ndotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent\n\n# Modifier preferences\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:silent\n\n# Expression-level preferences\ndotnet_style_coalesce_expression = true:suggestion\ndotnet_style_collection_initializer = true:suggestion\ndotnet_style_explicit_tuple_names = true:suggestion\ndotnet_style_namespace_match_folder = true:suggestion\ndotnet_style_null_propagation = true:suggestion\ndotnet_style_object_initializer = true:suggestion\ndotnet_style_operator_placement_when_wrapping = beginning_of_line\ndotnet_style_prefer_auto_properties = true:suggestion\ndotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion\ndotnet_style_prefer_compound_assignment = true:suggestion\ndotnet_style_prefer_conditional_expression_over_assignment = true:suggestion\ndotnet_style_prefer_conditional_expression_over_return = true:suggestion\ndotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed:suggestion\ndotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion\ndotnet_style_prefer_inferred_tuple_names = true:suggestion\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion\ndotnet_style_prefer_simplified_boolean_expressions = true:suggestion\ndotnet_style_prefer_simplified_interpolation = true:suggestion\n\n# Field preferences\ndotnet_style_readonly_field = true:warning\n\n# Parameter preferences\ndotnet_code_quality_unused_parameters = all:suggestion\n\n# Suppression preferences\ndotnet_remove_unnecessary_suppression_exclusions = none\n\n#### C# Coding Conventions ####\n[*.cs]\n\n# var preferences\ncsharp_style_var_elsewhere = false:silent\ncsharp_style_var_for_built_in_types = false:silent\ncsharp_style_var_when_type_is_apparent = false:silent\n\n# Expression-bodied members\ncsharp_style_expression_bodied_accessors = true:silent\ncsharp_style_expression_bodied_constructors = false:silent\ncsharp_style_expression_bodied_indexers = true:silent\ncsharp_style_expression_bodied_lambdas = true:suggestion\ncsharp_style_expression_bodied_local_functions = false:silent\ncsharp_style_expression_bodied_methods = false:silent\ncsharp_style_expression_bodied_operators = false:silent\ncsharp_style_expression_bodied_properties = true:silent\n\n# Pattern matching preferences\ncsharp_style_pattern_matching_over_as_with_null_check = true:suggestion\ncsharp_style_pattern_matching_over_is_with_cast_check = true:suggestion\ncsharp_style_prefer_extended_property_pattern = true:suggestion\ncsharp_style_prefer_not_pattern = true:suggestion\ncsharp_style_prefer_pattern_matching = true:silent\ncsharp_style_prefer_switch_expression = true:suggestion\n\n# Null-checking preferences\ncsharp_style_conditional_delegate_call = true:suggestion\n\n# Modifier preferences\ncsharp_prefer_static_anonymous_function = true:suggestion\ncsharp_prefer_static_local_function = true:warning\ncsharp_preferred_modifier_order = public,private,protected,internal,file,const,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion\ncsharp_style_prefer_readonly_struct = true:suggestion\ncsharp_style_prefer_readonly_struct_member = true:suggestion\n\n# Code-block preferences\ncsharp_prefer_braces = true:silent\ncsharp_prefer_simple_using_statement = true:suggestion\ncsharp_style_namespace_declarations = file_scoped:suggestion\ncsharp_style_prefer_method_group_conversion = true:silent\ncsharp_style_prefer_primary_constructors = true:suggestion\ncsharp_style_prefer_top_level_statements = true:silent\n\n# Expression-level preferences\ncsharp_prefer_simple_default_expression = true:suggestion\ncsharp_style_deconstructed_variable_declaration = true:suggestion\ncsharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion\ncsharp_style_inlined_variable_declaration = true:suggestion\ncsharp_style_prefer_index_operator = true:suggestion\ncsharp_style_prefer_local_over_anonymous_function = true:suggestion\ncsharp_style_prefer_null_check_over_type_check = true:suggestion\ncsharp_style_prefer_range_operator = true:suggestion\ncsharp_style_prefer_tuple_swap = true:suggestion\ncsharp_style_prefer_utf8_string_literals = true:suggestion\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_unused_value_assignment_preference = discard_variable:suggestion\ncsharp_style_unused_value_expression_statement_preference = discard_variable:silent\n\n# 'using' directive preferences\ncsharp_using_directive_placement = outside_namespace:silent\n\n#### C# Formatting Rules ####\n\n# New line preferences\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_else = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_between_query_expression_clauses = true\n\n# Indentation preferences\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_case_contents_when_block = true\ncsharp_indent_labels = one_less_than_current\ncsharp_indent_switch_labels = true\n\n# Space preferences\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = false\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n\n# Wrapping preferences\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = true\n\n#### Naming styles ####\n[*.{cs,vb}]\n\n# Naming rules\n\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion\ndotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces\ndotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase\n\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase\n\ndotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.methods_should_be_pascalcase.symbols = methods\ndotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.properties_should_be_pascalcase.symbols = properties\ndotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.events_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.events_should_be_pascalcase.symbols = events\ndotnet_naming_rule.events_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion\ndotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables\ndotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase\n\ndotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion\ndotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants\ndotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase\n\ndotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion\ndotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters\ndotnet_naming_rule.parameters_should_be_camelcase.style = camelcase\n\ndotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields\ndotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion\ndotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields\ndotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase\n\ndotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion\ndotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields\ndotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase\n\ndotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields\ndotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields\ndotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields\ndotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields\ndotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.enums_should_be_pascalcase.symbols = enums\ndotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions\ndotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase\n\ndotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion\ndotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members\ndotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase\n\n# Symbol specifications\n\ndotnet_naming_symbols.interfaces.applicable_kinds = interface\ndotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.interfaces.required_modifiers =\n\ndotnet_naming_symbols.enums.applicable_kinds = enum\ndotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.enums.required_modifiers =\n\ndotnet_naming_symbols.events.applicable_kinds = event\ndotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.events.required_modifiers =\n\ndotnet_naming_symbols.methods.applicable_kinds = method\ndotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.methods.required_modifiers =\n\ndotnet_naming_symbols.properties.applicable_kinds = property\ndotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.properties.required_modifiers =\n\ndotnet_naming_symbols.public_fields.applicable_kinds = field\ndotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal\ndotnet_naming_symbols.public_fields.required_modifiers =\n\ndotnet_naming_symbols.private_fields.applicable_kinds = field\ndotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\ndotnet_naming_symbols.private_fields.required_modifiers =\n\ndotnet_naming_symbols.private_static_fields.applicable_kinds = field\ndotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\ndotnet_naming_symbols.private_static_fields.required_modifiers = static\n\ndotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum\ndotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.types_and_namespaces.required_modifiers =\n\ndotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method\ndotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.non_field_members.required_modifiers =\n\ndotnet_naming_symbols.type_parameters.applicable_kinds = namespace\ndotnet_naming_symbols.type_parameters.applicable_accessibilities = *\ndotnet_naming_symbols.type_parameters.required_modifiers =\n\ndotnet_naming_symbols.private_constant_fields.applicable_kinds = field\ndotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\ndotnet_naming_symbols.private_constant_fields.required_modifiers = const\n\ndotnet_naming_symbols.local_variables.applicable_kinds = local\ndotnet_naming_symbols.local_variables.applicable_accessibilities = local\ndotnet_naming_symbols.local_variables.required_modifiers =\n\ndotnet_naming_symbols.local_constants.applicable_kinds = local\ndotnet_naming_symbols.local_constants.applicable_accessibilities = local\ndotnet_naming_symbols.local_constants.required_modifiers = const\n\ndotnet_naming_symbols.parameters.applicable_kinds = parameter\ndotnet_naming_symbols.parameters.applicable_accessibilities = *\ndotnet_naming_symbols.parameters.required_modifiers =\n\ndotnet_naming_symbols.public_constant_fields.applicable_kinds = field\ndotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal\ndotnet_naming_symbols.public_constant_fields.required_modifiers = const\n\ndotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field\ndotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal\ndotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static\n\ndotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field\ndotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\ndotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static\n\ndotnet_naming_symbols.local_functions.applicable_kinds = local_function\ndotnet_naming_symbols.local_functions.applicable_accessibilities = *\ndotnet_naming_symbols.local_functions.required_modifiers =\n\n# Naming styles\n\ndotnet_naming_style.pascalcase.required_prefix =\ndotnet_naming_style.pascalcase.required_suffix =\ndotnet_naming_style.pascalcase.word_separator =\ndotnet_naming_style.pascalcase.capitalization = pascal_case\n\ndotnet_naming_style.ipascalcase.required_prefix = I\ndotnet_naming_style.ipascalcase.required_suffix =\ndotnet_naming_style.ipascalcase.word_separator =\ndotnet_naming_style.ipascalcase.capitalization = pascal_case\n\ndotnet_naming_style.tpascalcase.required_prefix = T\ndotnet_naming_style.tpascalcase.required_suffix =\ndotnet_naming_style.tpascalcase.word_separator =\ndotnet_naming_style.tpascalcase.capitalization = pascal_case\n\ndotnet_naming_style._camelcase.required_prefix = _\ndotnet_naming_style._camelcase.required_suffix =\ndotnet_naming_style._camelcase.word_separator =\ndotnet_naming_style._camelcase.capitalization = camel_case\n\ndotnet_naming_style.camelcase.required_prefix =\ndotnet_naming_style.camelcase.required_suffix =\ndotnet_naming_style.camelcase.word_separator =\ndotnet_naming_style.camelcase.capitalization = camel_case\n\ndotnet_naming_style.s_camelcase.required_prefix = s_\ndotnet_naming_style.s_camelcase.required_suffix =\ndotnet_naming_style.s_camelcase.word_separator =\ndotnet_naming_style.s_camelcase.capitalization = camel_case\n\n##################################################################################\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/\n##################################################################################\n## Roslyn Code quality rules\n\ndotnet_diagnostic.CA1030.severity = none\ndotnet_diagnostic.CA1034.severity = none\ndotnet_diagnostic.CA1062.severity = suggestion\ndotnet_code_quality.CA1062.exclude_extension_method_this_parameter = true\ndotnet_code_quality.exclude_extension_method_this_parameter = true\ndotnet_code_quality.null_check_validation_methods = ThrowIfArgumentIsNull\n# CA1031: Do not catch general exception types\ndotnet_diagnostic.CA1031.severity = none\n# CA1303: Do not pass literals as localized parameters\ndotnet_diagnostic.CA1303.severity = none\n# CA1304: Specify CultureInfo\ndotnet_diagnostic.CA1304.severity = error\n# CA1307: Specify StringComparison for clarity\ndotnet_diagnostic.CA1307.severity = error\n# CA1308: Normalize strings to uppercase\ndotnet_diagnostic.CA1308.severity = none\n# CA1309: Use ordinal StringComparison\ndotnet_diagnostic.CA1309.severity = error\n# CA1724: Type names should not match namespaces\ndotnet_diagnostic.CA1724.severity = none\n# CA1819: Properties should not return arrays\ndotnet_diagnostic.CA1819.severity = none\n# CA1851: Possible multiple enumerations of IEnumerable collection. Related to GH-issue #2000\ndotnet_diagnostic.CA1851.severity = suggestion\n# CA1859: Use concrete types when possible for improved performance\ndotnet_diagnostic.CA1859.severity = suggestion\n# CA1860: Avoid using 'Enumerable.Any()' extension method\ndotnet_diagnostic.CA1860.severity = warning\n# CA1861: Avoid constant arrays as arguments\ndotnet_diagnostic.CA1861.severity = none\n# CA2007: Do not directly await a Task\ndotnet_diagnostic.CA2007.severity = none\n# CA2225: Operator overloads have named alternates\ndotnet_diagnostic.CA2225.severity = none\n# CA3075: Insecure DTD Processing\ndotnet_diagnostic.CA3075.severity = none\n# CA5369: Use XmlReader for Deserialize\ndotnet_diagnostic.CA5369.severity = none\n# CA1305: Specify IFormatProvider\ndotnet_diagnostic.CA1305.severity = None\n# CA1063: Implement IDisposable correctly\ndotnet_diagnostic.CA1063.severity = None\n# CA2201: Do not raise reserved exception types\ndotnet_diagnostic.ca2201.severity = Suggestion\n# CA1848: Use the LoggerMessage delegates\ndotnet_diagnostic.ca1848.severity = Suggestion\n# CA1810: Initialize reference type static fields inline\ndotnet_diagnostic.ca1810.severity = Suggestion\n# CA1725: Parameter names should match base declaration\ndotnet_diagnostic.ca1725.severity = Suggestion\n# CA1515: Consider making public types internal\ndotnet_diagnostic.CA1515.severity = None\n# CA2000: Dispose objects before losing scope\ndotnet_diagnostic.CA2000.severity = Suggestion\n# CA1707: Identifiers should not contain underscores\ndotnet_diagnostic.CA1707.severity = None\n# CA1716: Identifiers should not match keywords\ndotnet_diagnostic.CA1716.severity = Suggestion\n# CA1032: Implement standard exception constructors\ndotnet_diagnostic.CA1032.severity = Suggestion\n# AV1500: A method should not exceed a predefined number (60-100 lines) of lines\ndotnet_diagnostic.AV1500.severity = none\n\n##################################################################################\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/\n##################################################################################\n## Roslyn Code-style rules\n\ndotnet_diagnostic.IDE0048.severity = Suggestion\ndotnet_diagnostic.IDE0028.severity = Suggestion\ndotnet_diagnostic.IDE0029.severity = Suggestion\ndotnet_diagnostic.IDE0030\t.severity = Suggestion\ndotnet_diagnostic.IDE0004.severity = error\n\n# IDE0005: Remove unnecessary usings/imports\ndotnet_diagnostic.IDE0005.severity = warning\n\n# IDE0051: Remove unused private members (no reads or writes)\ndotnet_diagnostic.IDE0051.severity = Suggestion\n\n# IDE0052: Remove unread private members (writes but no reads)\ndotnet_diagnostic.IDE0052.severity = warning\n\n# Remove unnecessary using directives (IDE0005)\ndotnet_diagnostic.IDE0005.severity = none\n\n# CS1574: XML comment on 'construct' has syntactically incorrect cref attribute 'name'\ndotnet_diagnostic.CS1574.severity = error\n\n# IDE0055: Fix formatting\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/csharp-formatting-options\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/dotnet-formatting-options\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0055\n\n# https://csharpier.com/docs/IntegratingWithLinters#code-analysis-rules\ndotnet_diagnostic.IDE0055.severity = none\n\n##################################################################################\n# https://jetbrains.com.xy2401.com/help/resharper/EditorConfig_Index.html\n# https://jetbrains.com.xy2401.com/help/resharper/Reference__Code_Inspections_CSHARP.html\n## Resharper\n\n# ReSharper properties\nresharper_align_linq_query = true\nresharper_align_multiline_array_and_object_initializer = true\nresharper_align_multiline_binary_patterns = true\nresharper_align_multiline_expression = true\nresharper_align_multiline_extends_list = true\nresharper_align_multiline_parameter = true\nresharper_align_multiline_property_pattern = true\nresharper_align_multiline_switch_expression = true\nresharper_align_multiple_declaration = true\nresharper_align_multline_type_parameter_constrains = true\nresharper_align_multline_type_parameter_list = true\nresharper_align_tuple_components = true\nresharper_braces_for_for = required_for_multiline\nresharper_braces_for_foreach = required_for_multiline\nresharper_braces_for_ifelse = required_for_multiline\nresharper_csharp_alignment_tab_fill_style = optimal_fill\nresharper_csharp_indent_type_constraints = false\nresharper_csharp_int_align_fix_in_adjacent = false\nresharper_csharp_outdent_commas = true\nresharper_csharp_stick_comment = false\nresharper_csharp_wrap_after_declaration_lpar = true\nresharper_csharp_wrap_after_invocation_lpar = true\nresharper_csharp_wrap_arguments_style = chop_if_long\nresharper_csharp_wrap_before_declaration_rpar = true\nresharper_csharp_wrap_before_first_type_parameter_constraint = true\nresharper_csharp_wrap_before_ternary_opsigns = false\nresharper_csharp_wrap_extends_list_style = chop_if_long\nresharper_csharp_wrap_multiple_declaration_style = wrap_if_long\nresharper_csharp_wrap_multiple_type_parameter_constraints_style = chop_always\nresharper_csharp_wrap_parameters_style = chop_if_long\nresharper_enforce_line_ending_style = true\nresharper_indent_anonymous_method_block = true\nresharper_indent_braces_inside_statement_conditions = false\nresharper_indent_nested_fixed_stmt = true\nresharper_indent_nested_foreach_stmt = true\nresharper_indent_nested_for_stmt = true\nresharper_indent_nested_lock_stmt = true\nresharper_indent_nested_usings_stmt = true\nresharper_indent_nested_while_stmt = true\nresharper_keep_existing_declaration_block_arrangement = true\nresharper_keep_existing_declaration_parens_arrangement = false\nresharper_keep_existing_embedded_arrangement = false\nresharper_keep_existing_embedded_block_arrangement = true\nresharper_keep_existing_enum_arrangement = true\nresharper_keep_existing_invocation_parens_arrangement = false\nresharper_keep_existing_property_patterns_arrangement = false\nresharper_keep_existing_switch_expression_arrangement = false\nresharper_max_array_initializer_elements_on_line = 700\nresharper_max_formal_parameters_on_line = 500\nresharper_max_invocation_arguments_on_line = 700\nresharper_new_line_before_while = true\nresharper_place_attribute_on_same_line = false\nresharper_place_linq_into_on_new_line = false\nresharper_place_simple_case_statement_on_same_line = if_owner_is_single_line\nresharper_place_simple_property_pattern_on_single_line = false\nresharper_show_autodetect_configure_formatting_tip = false\nresharper_space_within_single_line_array_initializer_braces = false\nresharper_trailing_comma_in_multiline_lists = true\nresharper_trailing_comma_in_singleline_lists = true\nresharper_use_heuristics_for_body_style = false\nresharper_use_indent_from_vs = false\nresharper_use_roslyn_logic_for_evident_types = true\nresharper_wrap_array_initializer_style = chop_always\nresharper_wrap_chained_binary_expressions = chop_if_long\nresharper_wrap_chained_binary_patterns = chop_if_long\nresharper_wrap_chained_method_calls = chop_if_long\nresharper_wrap_for_stmt_header_style = wrap_if_long\nresharper_wrap_switch_expression = chop_if_long\nresharper_wrap_verbatim_interpolated_strings = chop_if_long\n\n# ReSharper inspection severities\nresharper_arrange_accessor_owner_body_highlighting = none\nresharper_arrange_redundant_parentheses_highlighting = hint\nresharper_arrange_type_member_modifiers_highlighting = hint\nresharper_arrange_type_modifiers_highlighting = hint\nresharper_check_namespace_highlighting = none\nresharper_enforce_if_statement_braces_highlighting = hint\nresharper_inconsistent_naming_highlighting = suggestion\nresharper_static_member_in_generic_type_highlighting = none\nresharper_suggest_var_or_type_built_in_types_highlighting = hint\nresharper_suggest_var_or_type_elsewhere_highlighting = hint\nresharper_suggest_var_or_type_simple_types_highlighting = hint\nresharper_web_config_module_not_resolved_highlighting = warning\nresharper_web_config_type_not_resolved_highlighting = warning\nresharper_web_config_wrong_module_highlighting = warning\n\n# https://www.jetbrains.com/help/rider/ClassNeverInstantiated.Global.html\nresharper_class_never_instantiated_global_highlighting = none\n\n\n# Convert lambda expression to method group\nresharper_convert_closure_to_method_group_highlighting = none\n\n# Start each element in a object or collection initializer on a new line\nresharper_wrap_object_and_collection_initializer_style = chop_always\n\n# Force an empty line\nresharper_blank_lines_after_multiline_statements = 1\n\n# Don't remove existing line breaks\nresharper_keep_existing_initializer_arrangement = true\nresharper_keep_existing_arrangement = true\n\n# We care about that extra else after an else-if\nresharper_redundant_if_else_block_highlighting = none\n\n# Don't remove explicit default cases in switch statements\nresharper_redundant_empty_switch_section_highlighting = none\n\nresharper_align_multiline_binary_expressions_chain = false\n\n# Only use new() when the type is obvious\nresharper_object_creation_when_type_not_evident = explicitly_typed\nresharper_object_creation_when_type_evident = target_typed\n\n# Indent 4 spaces per necessary indention\nresharper_continuous_indent_multiplier = 1\n\n# Avoid breaking a generic definition\nresharper_wrap_before_extends_colon = true\n\nresharper_blank_lines_before_multiline_statements = 1\n\nresharper_parentheses_non_obvious_operations = arithmetic, multiplicative, equality, relational, additive\nresharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence\n\n##################################################################################\n## https://github.com/DotNetAnalyzers/StyleCopAnalyzers/tree/master/documentation\n## https://documentation.help/StyleCop/StyleCop.html\n## StyleCop.Analyzers\n##################################################################################\n\n# Using directive should appear within a namespace declaration\ndotnet_diagnostic.sa1200.severity = None\n\n# Generic type parameter documentation should have text.\ndotnet_diagnostic.sa1622.severity = None\n\n# XML comment analysis is disabled due to project configuration\ndotnet_diagnostic.sa0001.severity = None\n\n# The file header is missing or not located at the top of the file\ndotnet_diagnostic.sa1633.severity = None\n\n# Use string.Empty for empty strings\ndotnet_diagnostic.sa1122.severity = None\n\n# Variable '_' should begin with lower-case letter\ndotnet_diagnostic.sa1312.severity = None\n\n# Parameter '_' should begin with lower-case letter\ndotnet_diagnostic.sa1313.severity = None\n\n# Elements should be documented\ndotnet_diagnostic.sa1600.severity = None\n\n# Prefix local calls with this\ndotnet_diagnostic.sa1101.severity = None\n\n# 'public' members should come before 'private' members\ndotnet_diagnostic.sa1202.severity = None\n\n# Comments should contain text\ndotnet_diagnostic.sa1120.severity = None\n\n# Constant fields should appear before non-constant fields\ndotnet_diagnostic.sa1203.severity = None\n\n# Field '_blah' should not begin with an underscore\ndotnet_diagnostic.sa1309.severity = None\n\n# Use trailing comma in multi-line initializers\ndotnet_diagnostic.sa1413.severity = None\n\n# A method should not follow a class\ndotnet_diagnostic.sa1201.severity = None\n\n# Elements should be separated by blank line\ndotnet_diagnostic.sa1516.severity = None\n\n# The parameter spans multiple lines\ndotnet_diagnostic.sa1118.severity = None\n\n# Static members should appear before non-static members\ndotnet_diagnostic.sa1204.severity = None\n\n# Put constructor initializers on their own line\ndotnet_diagnostic.sa1128.severity = None\n\n# Opening braces should not be preceded by blank line\ndotnet_diagnostic.sa1509.severity = None\n\n# The parameter should begin on the line after the previous parameter\ndotnet_diagnostic.sa1115.severity = None\n\n# File name should match first type name\ndotnet_diagnostic.sa1649.severity = None\n\n# File may only contain a single type\ndotnet_diagnostic.sa1402.severity = None\n\n# Enumeration items should be documented\ndotnet_diagnostic.sa1602.severity = None\n\n# Element should not be on a single line\ndotnet_diagnostic.sa1502.severity = None\n\n# Closing parenthesis should not be preceded by a space\ndotnet_diagnostic.sa1009.severity = None\n\n# Closing parenthesis should be on line of last parameter\ndotnet_diagnostic.sa1111.severity = None\n\n# Braces should not be ommitted\ndotnet_diagnostic.sa1503.severity = None\n\ndotnet_diagnostic.sa1401.severity = None\n\n# The parameters to a C# method or indexer call or declaration are not all on the same line or each on a separate line.\n# dotnet_diagnostic.SA1117.severity = Suggestion\n\n# The parameters to a C# method or indexer call or declaration span across multiple lines, but the first parameter does not start on the line after the opening bracket.\n# dotnet_diagnostic.SA1116.severity = Suggestion\n\n# A C# partial element is missing a documentation header.\ndotnet_diagnostic.sa1601.severity = None\n\n# A <param> tag within a C# element’s documentation header is empty.\ndotnet_diagnostic.sa1614.severity = None\n\n# A C# element is missing documentation for its return value.\ndotnet_diagnostic.sa1615.severity = None\n\n# The <returns> tag within a C# element’s documentation header is empty.\ndotnet_diagnostic.sa1616.severity = None\n\n# An opening brace within a C# element is not spaced correctly.\ndotnet_diagnostic.sa1012.severity = Suggestion\n\n# A closing brace within a C# element is not spaced correctly.\ndotnet_diagnostic.sa1013.severity = Suggestion\n\n# A call to an instance member of the local class or a base class is not prefixed with 'this.', within a C# code file.\ndotnet_diagnostic.sa1101.severity = None\n\n# The keywords within the declaration of an element do not follow a standard ordering scheme.\ndotnet_diagnostic.SA1206.severity = None\n\ndotnet_diagnostic.SA1106.severity = None\n\n# https://csharpier.com/docs/IntegratingWithLinters#stylecopanalyzers\n# IDE0055: Fix formatting\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/csharp-formatting-options\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/dotnet-formatting-options\n# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0055\n\n# StyleCopAnalyzers\ndotnet_diagnostic.SA1000.severity = none\ndotnet_diagnostic.SA1009.severity = none\ndotnet_diagnostic.SA1111.severity = none\ndotnet_diagnostic.SA1118.severity = none\ndotnet_diagnostic.SA1137.severity = none\ndotnet_diagnostic.SA1413.severity = none\ndotnet_diagnostic.SA1500.severity = none\ndotnet_diagnostic.SA1501.severity = none\ndotnet_diagnostic.SA1502.severity = none\ndotnet_diagnostic.SA1504.severity = none\ndotnet_diagnostic.SA1515.severity = none\ndotnet_diagnostic.SA1516.severity = none\n\n# for csharpier <= 0.21.0\ndotnet_diagnostic.SA1127.severity = none\ndotnet_diagnostic.SA1128.severity = none\n\ndotnet_diagnostic.SA1001.severity = none\ndotnet_diagnostic.SA1002.severity = none\ndotnet_diagnostic.SA1003.severity = none\ndotnet_diagnostic.SA1007.severity = none\ndotnet_diagnostic.SA1008.severity = none\ndotnet_diagnostic.SA1010.severity = none\ndotnet_diagnostic.SA1011.severity = none\ndotnet_diagnostic.SA1012.severity = none\ndotnet_diagnostic.SA1013.severity = none\ndotnet_diagnostic.SA1014.severity = none\ndotnet_diagnostic.SA1015.severity = none\ndotnet_diagnostic.SA1016.severity = none\ndotnet_diagnostic.SA1017.severity = none\ndotnet_diagnostic.SA1018.severity = none\ndotnet_diagnostic.SA1019.severity = none\ndotnet_diagnostic.SA1020.severity = none\ndotnet_diagnostic.SA1021.severity = none\ndotnet_diagnostic.SA1022.severity = none\ndotnet_diagnostic.SA1023.severity = none\ndotnet_diagnostic.SA1024.severity = none\ndotnet_diagnostic.SA1025.severity = none\ndotnet_diagnostic.SA1026.severity = none\ndotnet_diagnostic.SA1027.severity = none\ndotnet_diagnostic.SA1028.severity = none\ndotnet_diagnostic.SA1102.severity = none\ndotnet_diagnostic.SA1103.severity = none\ndotnet_diagnostic.SA1104.severity = none\ndotnet_diagnostic.SA1105.severity = none\ndotnet_diagnostic.SA1107.severity = none\ndotnet_diagnostic.SA1110.severity = none\ndotnet_diagnostic.SA1112.severity = none\ndotnet_diagnostic.SA1113.severity = none\ndotnet_diagnostic.SA1114.severity = none\ndotnet_diagnostic.SA1115.severity = none\ndotnet_diagnostic.SA1116.severity = none\ndotnet_diagnostic.SA1117.severity = none\ndotnet_diagnostic.SA1127.severity = none\ndotnet_diagnostic.SA1128.severity = none\ndotnet_diagnostic.SA1136.severity = none\ndotnet_diagnostic.SA1505.severity = none\ndotnet_diagnostic.SA1506.severity = none\ndotnet_diagnostic.SA1507.severity = none\ndotnet_diagnostic.SA1508.severity = none\ndotnet_diagnostic.SA1509.severity = none\ndotnet_diagnostic.SA1510.severity = none\ndotnet_diagnostic.SA1511.severity = none\ndotnet_diagnostic.SA1517.severity = none\ndotnet_diagnostic.SA1518.severity = none\n\n##################################################################################\n## https://github.com/meziantou/Meziantou.Analyzer/tree/main/docs\n## Meziantou.Analyzer\n\n# MA0048: File name must match type name\ndotnet_diagnostic.ma0048.severity = Suggestion\n\n# MA0051: Method is too long\ndotnet_diagnostic.ma0051.severity = Suggestion\n\n# https://www.meziantou.net/string-comparisons-are-harder-than-it-seems.htm\n# MA0006 - Use String.Equals instead of equality operator\ndotnet_diagnostic.ma0006.severity = Suggestion\n\n# MA0002 - IEqualityComparer<string> or IComparer<string> is missing\ndotnet_diagnostic.ma0002.severity = Suggestion\n\n# MA0001 - StringComparison is missing\ndotnet_diagnostic.ma0001.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#13-pass-cancellation-token\n# MA0040: Specify a cancellation token\ndotnet_diagnostic.ma0032.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#13-pass-cancellation-token\n# MA0040: Flow the cancellation token when available\ndotnet_diagnostic.ma0040.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#14-using-cancellation-token-with-iasyncenumerable\n# MA0079: Use a cancellation token using .WithCancellation()\ndotnet_diagnostic.ma0079.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#14-using-cancellation-token-with-iasyncenumerable\n# MA0080: Use a cancellation token using .WithCancellation()\ndotnet_diagnostic.ma0080.severity = Suggestion\n\n# Use Task.ConfigureAwait(false) as the current SynchronizationContext is not needed\ndotnet_diagnostic.MA0004.severity = none\n\n# Add regex evaluation timeout\ndotnet_diagnostic.MA0009.severity = none\n\n# Use an overload of 'ToString' that has a 'System.IFormatProvider' parameter. Already caught by CA1305.\ndotnet_diagnostic.MA0011.severity = none\n\n# Use an overload of 'System.ArgumentException' with the parameter name. Just a suggestion since we have a bunch of justified exceptions.\ndotnet_diagnostic.MA0015.severity = suggestion\n\n# Use an explicit StringComparer to compute hash codes\ndotnet_diagnostic.MA0021.severity = none\n\n# Declare types in namespaces. Already caught by CA1050\ndotnet_diagnostic.MA0047.severity = none\n\n# Use an overload of 'GetHashCode' that has a StringComparison parameter\ndotnet_diagnostic.MA0074.severity = none\n\n# MA0049: Type name should not match containing namespace\ndotnet_diagnostic.MA0049.severity = none\n\n##################################################################################\n## https://github.com/JosefPihrt/Roslynator/blob/main/docs/Configuration.md\n## https://josefpihrt.github.io/docs/\n## Roslynator\n##################################################################################\n\n# RCS1036 -\tRemove redundant empty line.\ndotnet_diagnostic.rcs1036.severity = None\n\n# RCS1037 - Remove trailing white-space.\ndotnet_diagnostic.rcs1037.severity = None\n\n# RCS1194: Implement exception constructors\ndotnet_diagnostic.rcs1194.severity = None\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#1-redundant-asyncawait\n# RCS1174: Remove redundant async/await.\ndotnet_diagnostic.rcs1174.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#10-returning-null-from-a-task-returning-method\n# RCS1210: Return Task.FromResult instead of returning null.\ndotnet_diagnostic.rcs1210.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#9-missing-configureawaitbool\n# RCS1090: Call 'ConfigureAwait(false)'.\ndotnet_diagnostic.rcs1090.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#11-asynchronous-method-names-should-end-with-async\n#RCS1046: Asynchronous method name should end with 'Async'.\ndotnet_diagnostic.rcs1046.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#12-non-asynchronous-method-names-shouldnt-end-with-async\n# RCS1047: Non-asynchronous method name should not end with 'Async'.\ndotnet_diagnostic.rcs1047.severity = error\n\n# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1174.md\n# RCS1174: Remove redundant async/await\ndotnet_diagnostic.rcs1174.severity = Suggestion\n\n# Combine 'Enumerable.Where' method chain. It doesn't make it more readable in all cases.\ndotnet_diagnostic.RCS1112.severity = suggestion\n\n# Inline local variable.\ndotnet_diagnostic.RCS1124.severity = suggestion\n\n# Add exception to documentation comment. Nice suggestion, but we don't want to document exceptions for internal code.\ndotnet_diagnostic.RCS1140.severity = suggestion\n\n# Missing documentation\ndotnet_diagnostic.RCS1141.severity = suggestion\ndotnet_diagnostic.RCS1142.severity = suggestion\n\n# Use conditional access. Suggestion because it doesn't always improve readability\ndotnet_diagnostic.RCS1146.severity = suggestion\n\n# Enum should declare explicit values. Disabled because we're not storing them.\ndotnet_diagnostic.RCS1161.severity = none\n\n# Static member in generic type should use a type parameter. Disabled because it's not always applicable.\ndotnet_diagnostic.RCS1158.severity = none\n\n# Add region name to #endregion.\ndotnet_diagnostic.RCS1189.severity = none\n\n# Convert comment to documentation comment. Disabled because it also complains about SMELL/REFACTOR comments\ndotnet_diagnostic.RCS1181.severity = none\n\n# Use Regex instance instead of static method. Disabled because it's not always worth it.\ndotnet_diagnostic.RCS1186.severity = none\n\n# Use bit shift operator.\ndotnet_diagnostic.RCS1237.severity = none\n\n# RCS1228: Unused element in documentation comment. (Equivalent to SA1614)\ndotnet_diagnostic.RCS1228.severity = suggestion\n\n# RCS1047: Non-asynchronous method name should not end with 'Async'\n#dotnet_diagnostic.RCS1047.severity = suggestion\n\n##################################################################################\n## https://github.com/semihokur/asyncfixer\n## AsyncFixer01\n##################################################################################\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#1-redundant-asyncawait\n# AsyncFixer01: Unnecessary async/await usage\ndotnet_diagnostic.asyncfixer01.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#2-calling-synchronous-method-inside-the-async-method\n# AsyncFixer02: Long-running or blocking operations inside an async method\ndotnet_diagnostic.asyncfixer02.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#3-async-void-method\n# AsyncFixer03: Fire & forget async void methods\ndotnet_diagnostic.asyncfixer03.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#6-not-awaited-task-inside-the-using-block\n# AsyncFixer04: Fire & forget async call inside a using block\ndotnet_diagnostic.asyncfixer04.severity = error\n\n##################################################################################\n## https://github.com/microsoft/vs-threading\n## Microsoft.VisualStudio.Threading.Analyzers\n##################################################################################\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#2-calling-synchronous-method-inside-the-async-method\n# VSTHRD103: Call async methods when in an async method\ndotnet_diagnostic.vsthrd103.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#3-async-void-method\n# VSTHRD100: Avoid async void methods\ndotnet_diagnostic.vsthrd100.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#4-unsupported-async-delegates\n# VSTHRD101: Avoid unsupported async delegates\ndotnet_diagnostic.vsthrd101.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#5-not-awaited-task-within-using-expression\n# VSTHRD107: Await Task within using expression\ndotnet_diagnostic.vsthrd107.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p1/#7-unobserved-result-of-asynchronous-method\n# VSTHRD110: Observe result of async calls\ndotnet_diagnostic.vsthrd110.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#8-synchronous-waits\n# VSTHRD002: Avoid problematic synchronous waits\ndotnet_diagnostic.vsthrd002.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#9-missing-configureawaitbool\n# VSTHRD111: Use ConfigureAwait(bool)\ndotnet_diagnostic.vsthrd111.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#10-returning-null-from-a-task-returning-method\n# VSTHRD114: Avoid returning a null Task\ndotnet_diagnostic.vsthrd114.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#11-asynchronous-method-names-should-end-with-async\n# VSTHRD200: Use \"Async\" suffix for async methods\ndotnet_diagnostic.vsthrd200.severity = Suggestion\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#12-non-asynchronous-method-names-shouldnt-end-with-async\n# VSTHRD200: Use \"Async\" suffix for async methods\ndotnet_diagnostic.vsthrd200.severity = Suggestion\n\n# VSTHRD003 Avoid awaiting foreign Tasks\ndotnet_diagnostic.VSTHRD003.severity = Suggestion\n\n\n##################################################################################\n## https://github.com/hvanbakel/Asyncify-CSharp\n## Asyncify\n##################################################################################\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#8-synchronous-waits\n# AsyncifyInvocation: Use Task Async\ndotnet_diagnostic.asyncifyinvocation.severity = error\n\n# https://cezarypiatek.github.io/post/async-analyzers-p2/#8-synchronous-waits\n# AsyncifyVariable: Use Task Async\ndotnet_diagnostic.asyncifyvariable.severity = error\n"
  },
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n*.sh text eol=lf\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain"
  },
  {
    "path": ".github/actions/build/action.yml",
    "content": "﻿# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions\n# https://doug.sh/posts/using-composite-actions-with-github-actions/\n# https://wallis.dev/blog/composite-github-actions\n\nname: \"Build\"\ndescription: \"Build service\"\n\n# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs\ninputs:\n  project-path:\n    description: Project path\n    required: true\n  service-name:\n    description: Service name\n    required: true\n\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions\nruns:\n  using: \"composite\"\n  steps:\n\n    # https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows\n    # https://devblogs.microsoft.com/dotnet/dotnet-loves-github-actions/\n    # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net#caching-dependencies\n    - name: Cache NuGet Packages\n      uses: actions/cache@v4\n      if: success()\n      with:\n        path: ~/.nuget/packages\n        key: ${{ runner.os }}-dotnet-nuget\n\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: '10.x.x'\n\n      # https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools\n    - name: Restore .NET Tools\n      shell: bash\n      run: dotnet tool restore\n\n      # Note: `Ubuntu` file and folder names are case sensitive, be aware about naming them in solution references. because `Windows` file and folder names as case-insensitive.\n      # prevent windows case-insensitive for our project with: git config core.ignorecase false; - https://stackoverflow.com/a/27139487/581476\n    - name: Restore NuGet packages\n      shell: bash\n      if: success()\n      # restore root solution\n      run: dotnet restore\n\n    # npm install, runs `prepare` script automatically in the initialize step\n    - name: Install NPM Dependencies\n      shell: bash\n      if: success()\n      run: npm install\n\n    - name: Format Service\n      shell: bash\n      if: ${{ success()}}\n      run: |\n        npm run ci-format\n\n    - name: Build Service\n      shell: bash\n      if: ${{ success()}}\n      working-directory: ${{ inputs.project-path }}\n      run: |\n        dotnet build -c Release --no-restore\n"
  },
  {
    "path": ".github/actions/build-test/action.yml",
    "content": "﻿# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions\n# https://doug.sh/posts/using-composite-actions-with-github-actions/\n# https://wallis.dev/blog/composite-github-actions\n\nname: \"Build-Test\"\ndescription: \"Build and test service\"\n\n# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs\ninputs:\n  project-path:\n    description: Project path\n    required: true\n  tests-path:\n    description: Test path\n    required: false\n    default: ''\n  reports-path:\n    description: Test report path\n    required: true\n  reports-output-path:\n    description: Test report output path\n    required: true\n  service-name:\n    description: Service name\n    required: true\n  # https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github\n  token:\n    description: A Github PAT\n    required: true\n\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions\nruns:\n  using: \"composite\"\n  steps:\n\n    - name: Call Composite Action build\n      uses: ./.github/actions/build\n      if: success()\n      id: build-step\n      with:\n        project-path: ${{ inputs.project-path }}\n        service-name: ${{ inputs.service-name }}\n\n    - name: Call Composite Action test\n      uses: ./.github/actions/test\n      if: ${{ success() && inputs.tests-path != ''}}\n      id: test-step\n      with:\n        tests-path: ${{ inputs.tests-path }}\n        # wildcard search for files with the \".cobertura.xml\" extension in all subdirectories of the current directory\n        # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n        # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n        reports-path: ${{ github.workspace }}/**/*.cobertura.xml\n        reports-output-path: ${{ github.workspace }}/output/test-results\n        service-name: ${{ inputs.service-name }}\n        token: ${{ inputs.token }}\n        no-restore: true\n"
  },
  {
    "path": ".github/actions/docker-build-publish/action.yml",
    "content": "﻿name: \"Publish and Build Docker\"\ndescription: \"Publish and Build Docker \"\n\n# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs\ninputs:\n  tag-name:\n    description: \"Tag Name\"\n    required: true\n  image-name:\n    description: \"Image Name\"\n    required: true\n  registry-username:\n    description: \"Registry username\"\n    required: true\n  registry-password:\n    description: \"Registry password\"\n    required: true\n  dockerfile-path:\n    description: \"Dockerfile path\"\n    required: true\n\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions\nruns:\n  using: \"composite\"\n  steps:\n\n    ##ref: https://docs.docker.com/language/golang/configure-ci-cd/\n    ##ref: https://event-driven.io/en/how_to_buid_and_push_docker_image_with_github_actions\n    - name: Login to DockerHub\n      uses: docker/login-action@v2\n      if: ${{ github.ref == 'refs/heads/main' && success() }}\n      with:\n        username: ${{ inputs.registry-username }}\n        password: ${{ inputs.registry-password }}\n\n    - name: Docker Tag Info\n      shell: bash\n      run:\n        echo \"Docker tag version is:\" ${{ inputs.tag-name }}\n\n    - name: Build Docker Image\n      if: ${{ github.ref == 'refs/heads/main' && success() }}\n      shell: bash\n      run: |\n        docker build -t ${{ inputs.registry-username }}/${{ inputs.image-name }}:${{ inputs.tag-name }} -f \"${{ github.workspace }}/${{ inputs.dockerfile-path }}\" .\n\n    - name: Publish Docker Image\n      if: ${{ github.ref == 'refs/heads/main' && success() }}\n      shell: bash\n      run: |\n        docker push ${{ inputs.registry-username }}/${{ inputs.image-name }}:${{ inputs.tag-name }}\n\n"
  },
  {
    "path": ".github/actions/test/action.yml",
    "content": "﻿# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions\n# https://doug.sh/posts/using-composite-actions-with-github-actions/\n# https://wallis.dev/blog/composite-github-actions\n\nname: \"Test\"\ndescription: \"Test service\"\n\n# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string)\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs\ninputs:\n  tests-path:\n    description: Test path\n    required: true\n  reports-path:\n    description: Test report path\n    required: true\n  reports-output-path:\n    description: Test report output path\n    required: true\n  service-name:\n    description: Service name\n    required: true\n  # https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github\n  token:\n    description: A Github PAT\n    required: true\n  no-restore:\n    description: No restore nuget packages, but building tests because they don't build in the build composition action\n    default: 'true'\n\n# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions\nruns:\n  using: \"composite\"\n  steps:\n\n    # see here https://samlearnsazure.blog/2021/01/05/code-coverage-in-github-with-net-core/\n    # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n    # https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details\n    # https://josef.codes/dotnet-core-filter-out-specific-test-projects-when-running-dotnet-test/\n    # https://learn.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=xunit\n    # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n    # https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md\n    # https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md#filters\n    - name: Tests\n      shell: bash\n      id: tests-step\n      working-directory: ${{ inputs.tests-path }}\n      # https://stackoverflow.com/questions/3779701/msbuild-error-msb1008-only-one-project-can-be-specified\n      # https://octopus.com/blog/githubactions-running-unit-tests\n      # we should not do 'no-build' here, because our tests not build in build phase (build composite action) and should build here\n      run: |\n        for file in $(find . -name \"*.csproj\" -type f); do\n          echo \"Testing $file\"\n          if [ ${{ inputs.no-restore }} == 'true' ]; then\n             echo \"run tests in no-restore mode\"\n             dotnet test \"$file\" -c Release --no-restore --logger \"trx;LogFileName=test-results.trx\" || true\n          else\n             echo \"run tests in restore nuget mode\"\n             dotnet test \"$file\" -c Release --logger \"trx;LogFileName=test-results.trx\" || true\n          fi\n        done\n\n    # GitHub Api call permissions problem here\n    # https://github.com/dorny/test-reporter/issues/168\n    # https://octopus.com/blog/githubactions-running-unit-tests\n    # https://github.com/dorny/test-reporter/issues/67\n    # https://github.com/phoenix-actions/test-reporting/pull/21\n    - name: Test Results\n      uses: phoenix-actions/test-reporting@v10\n      id: test-report\n      if: always()\n      with:\n        name: ${{ inputs.service-name }} Test Reports\n        reporter: dotnet-trx\n        token: ${{ inputs.token }}\n        # only-summary: 'true'\n        output-to: \"step-summary\"\n        path: \"**/test-results.trx\"\n        # Set action as failed if test report contains any failed test\n        fail-on-error: true\n        ## https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories\n        ## https://github.com/dorny/test-reporter/blob/0d9714ddc7ff86918ec725a527a3a069419d301a/src/utils/github-utils.ts#L44\n        ## artifact name to download trx test result if it is in seperated workflow with github rest call, if it is not in another workflow skip this\n        # artifact: \"'\n"
  },
  {
    "path": ".github/release-drafter.yml",
    "content": "# https://johanneskonings.dev/github/2021/02/28/github_automatic_releases_and-changelog/\n# https://tiagomichaelsousa.dev/articles/stop-writing-your-changelogs-manually\n# https://github.com/release-drafter/release-drafter/issues/551\n# https://github.com/release-drafter/release-drafter/pull/1013\n# https://github.com/release-drafter/release-drafter/issues/139\n# https://github.com/atk4/data/blob/develop/.github/release-drafter.yml\n\n# This release drafter follows the conventions from https://keepachangelog.com, https://common-changelog.org/\n# https://www.conventionalcommits.org\n\nname-template: 'v$RESOLVED_VERSION'\ntag-template: 'v$RESOLVED_VERSION'\ntemplate: |\n  ## What Changed 👀\n  $CHANGES\n  **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION\ncategories:\n  - title: 🚀 Features\n    labels:\n      - feature\n  - title: 🐛 Bug Fixes\n    labels:\n      - fix\n      - bug\n  - title: 🧪 Test\n    labels:\n      - test\n  - title: 👷 CI\n    labels:\n      - ci\n  - title: ♻️ Refactor\n    labels:\n      - changed\n      - enhancement\n      - refactor\n  - title: ⛔️ Deprecated\n    labels:\n      - deprecated\n  - title: 🔐 Security\n    labels:\n      - security\n  - title: 📄 Documentation\n    labels:\n      - docs\n      - documentation\n  - title: 🧩 Dependency Updates\n    labels:\n      - deps\n      - dependencies\n  - title: 🧰 Maintenance\n    label: 'chore'\n  - title: 📝 Other changes\n## putting no labels pr to `Other Changes` category with no label - https://github.com/release-drafter/release-drafter/issues/139#issuecomment-480473934\n\n# https://www.trywilco.com/post/wilco-ci-cd-github-heroku\n# https://github.com/release-drafter/release-drafter#autolabeler\n# https://github.com/fuxingloh/multi-labeler\n\n# Using regex for defining rules - https://regexr.com/ - https://regex101.com/\nautolabeler:\n  - label: 'chore'\n    branch:\n      - '/(chore)\\/.*/'\n  - label: 'security'\n    branch:\n      - '/(security)\\/.*/'\n  - label: 'refactor'\n    branch:\n      - '/(refactor)\\/.*/'\n  - label: 'docs'\n    branch:\n      - '/(docs)\\/.*/'\n  - label: 'ci'\n    branch:\n      - '/(ci)\\/.*/'\n  - label: 'test'\n    branch:\n      - '/(test)\\/.*/'\n  - label: 'bug'\n    branch:\n      - '/(fix)\\/.*/'\n  - label: 'feature'\n    branch:\n      - '/(feat)\\/.*/'\n  - label: 'minor'\n    branch:\n      - '/(feat)\\/.*/'\n  - label: 'patch'\n    branch:\n      - '/(fix)\\/.*/'\n    body:\n      - '/JIRA-[0-9]{1,4}/'\n\nchange-template: '- $TITLE @$AUTHOR (#$NUMBER)'\nchange-title-escapes: '\\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.\nversion-resolver:\n  major:\n    labels:\n      - major\n  minor:\n    labels:\n      - minor\n  patch:\n    labels:\n      - patch\n  default: patch\n\nexclude-labels:\n  - skip-changelog\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [ \"main\"]\n    paths-ignore:\n      - \"README.md\"\n  pull_request:\n    branches: [ \"main\"]\n    paths-ignore:\n      - \"README.md\"\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  ci:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Build and Test Flight Microservice\n        uses: ./.github/actions/build-test\n        if: success()\n        id: build-test-flight-step\n        with:\n          project-path: 'src/Services/Flight/src/Flight.Api'\n          tests-path: 'src/Services/Flight/tests/'\n          # wildcard search for files with the \".cobertura.xml\" extension in all subdirectories of the current directory\n          # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n          # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n          reports-path: ${{ github.workspace }}/**/*.cobertura.xml\n          reports-output-path: ${{ github.workspace }}/output/test-results\n          service-name: 'Flight'\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build and Test Identity Microservice\n        uses: ./.github/actions/build-test\n        if: success()\n        id: build-test-identity-step\n        with:\n          project-path: 'src/Services/Identity/src/Identity.Api'\n          tests-path: 'src/Services/Identity/tests/'\n          # wildcard search for files with the \".cobertura.xml\" extension in all subdirectories of the current directory\n          # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n          # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n          reports-path: ${{ github.workspace }}/**/*.cobertura.xml\n          reports-output-path: ${{ github.workspace }}/output/test-results\n          service-name: 'Identity'\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build and Test Passenger Microservice\n        uses: ./.github/actions/build-test\n        if: success()\n        id: build-test-passenger-step\n        with:\n          project-path: 'src/Services/Passenger/src/Passenger.Api'\n          tests-path: 'src/Services/Passenger/tests/'\n          # wildcard search for files with the \".cobertura.xml\" extension in all subdirectories of the current directory\n          # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n          # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n          reports-path: ${{ github.workspace }}/**/*.cobertura.xml\n          reports-output-path: ${{ github.workspace }}/output/test-results\n          service-name: 'Passenger'\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build and Test Booking Microservice\n        uses: ./.github/actions/build-test\n        if: success()\n        id: build-test-booking-step\n        with:\n          project-path: 'src/Services/Booking/src/Booking.Api'\n          tests-path: 'src/Services/Booking/tests/'\n          # wildcard search for files with the \".cobertura.xml\" extension in all subdirectories of the current directory\n          # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/\n          # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not\n          reports-path: ${{ github.workspace }}/**/*.cobertura.xml\n          reports-output-path: ${{ github.workspace }}/output/test-results\n          service-name: 'Booking'\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Update Release Drafter\n        if: ${{ github.ref == 'refs/heads/main' && success() }}\n        id: last_release\n        uses: release-drafter/release-drafter@v5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Release Version Info\n        run:\n          echo \"Release version is:\" ${{ steps.last_release.outputs.tag_name }}\n\n      - name: Build and Publish Identity Microservice to Docker\n        if: ${{ github.ref == 'refs/heads/main' && success() }}\n        uses: ./.github/actions/docker-build-publish\n        with:\n          tag-name: ${{ steps.last_release.outputs.tag_name }}\n          registry-username: ${{ secrets.DOCKERHUB_USERNAME }}\n          registry-password: ${{ secrets.DOCKERHUB_PASSWORD }}\n          dockerfile-path: 'src/Services/Identity/Dockerfile'\n          image-name: 'booking-microservices-identity'\n\n      - name: Build and Publish Flight Microservice to Docker\n        if: ${{ github.ref == 'refs/heads/main' && success() }}\n        uses: ./.github/actions/docker-build-publish\n        with:\n          tag-name: ${{ steps.last_release.outputs.tag_name }}\n          registry-username: ${{ secrets.DOCKERHUB_USERNAME }}\n          registry-password: ${{ secrets.DOCKERHUB_PASSWORD }}\n          dockerfile-path: 'src/Services/Flight/Dockerfile'\n          image-name: 'booking-microservices-flight'\n\n      - name: Build and Publish Passenger Microservice to Docker\n        if: ${{ github.ref == 'refs/heads/main' && success() }}\n        uses: ./.github/actions/docker-build-publish\n        with:\n          tag-name: ${{ steps.last_release.outputs.tag_name }}\n          registry-username: ${{ secrets.DOCKERHUB_USERNAME }}\n          registry-password: ${{ secrets.DOCKERHUB_PASSWORD }}\n          dockerfile-path: 'src/Services/Passenger/Dockerfile'\n          image-name: 'booking-microservices-passenger'\n\n      - name: Build and Publish Booking Microservice to Docker\n        if: ${{ github.ref == 'refs/heads/main' && success() }}\n        uses: ./.github/actions/docker-build-publish\n        with:\n          tag-name: ${{ steps.last_release.outputs.tag_name }}\n          registry-username: ${{ secrets.DOCKERHUB_USERNAME }}\n          registry-password: ${{ secrets.DOCKERHUB_PASSWORD }}\n          dockerfile-path: 'src/Services/Booking/Dockerfile'\n          image-name: 'booking-microservices-booking'\n"
  },
  {
    "path": ".github/workflows/release-drafter-labeler.yml",
    "content": "name: Release Drafter Auto Labeler\n\non:\n  pull_request:\n    types:\n      - opened\n      - synchronize\n      - reopened\n      - labeled\n      - unlabeled\n\njobs:\n auto-labeler:\n   runs-on: ubuntu-latest\n   steps:\n     - uses: release-drafter/release-drafter@v5\n       with:\n         config-name: release-drafter.yml\n         disable-releaser: true # only run auto-labeler for PRs\n       env:\n         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\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# Visual Studio Trace Files\n*.e2e\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# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\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# Note: 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# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable 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*.appx\n*.appxbundle\n*.appxupload\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\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\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\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\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\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\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# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/usage.statistics.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# AWS User-specific\n.idea/**/aws.xml\n\n# Generated files\n.idea/**/contentModel.xml\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Gradle and Maven with auto-import\n# When using Gradle or Maven with auto-import, you should exclude module files,\n# since they will be recreated, and may cause churn.  Uncomment if using\n# auto-import.\n# .idea/artifacts\n# .idea/compiler.xml\n# .idea/jarRepositories.xml\n# .idea/modules.xml\n# .idea/*.iml\n# .idea/modules\n# *.iml\n# *.ipr\n\n# CMake\ncmake-build-*/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# SonarLint plugin\n.idea/sonarlint/\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n# Android studio 3.1+ serialized cache file\n.idea/caches/build_file_checksums.ser\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# Tye\n.tye/\n\n*.jwk\n\n# Monitoring\n**/grafana-data\n\n# EventStore\n**/eventstore\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "npx --no -- commitlint --edit ${1}"
  },
  {
    "path": ".husky/pre-commit",
    "content": "npm run format\nnpm run ci-format\n"
  },
  {
    "path": "CONTRIBUTION.md",
    "content": "## Contribution\n\nThis is great that you'd like to contribute to this project. All change requests should go through the steps described below.\n\n## Pull Requests\n\n**Please, make sure you open an issue before starting with a Pull Request, unless it's a typo or a really obvious error.** Pull requests are the best way to propose changes.\n\n## Conventional commits\n\nOur repository follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. Releasing to GitHub and NuGet is done with the support of [semantic-release](https://semantic-release.gitbook.io/semantic-release/).\n\nPull requests should have a title that follows the specification, otherwise, merging is blocked. If you are not familiar with the specification simply ask maintainers to modify. You can also use this cheatsheet if you want:\n\n- `fix: ` prefix in the title indicates that PR is a bug fix and PATCH release must be triggered.\n- `feat: ` prefix in the title indicates that PR is a feature and MINOR release must be triggered.\n- `docs: ` prefix in the title indicates that PR is only related to the documentation and there is no need to trigger release.\n- `chore: ` prefix in the title indicates that PR is only related to cleanup in the project and there is no need to trigger release.\n- `test: ` prefix in the title indicates that PR is only related to tests and there is no need to trigger release.\n- `refactor: ` prefix in the title indicates that PR is only related to refactoring and there is no need to trigger release.\n\n## Resources\n\n- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)\n- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)\n- [GitHub Help](https://help.github.com)\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StyleCop.Analyzers\" PrivateAssets=\"all\" Version=\"1.1.118\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Meziantou.Analyzer\" PrivateAssets=\"all\" Version=\"2.0.299\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Roslynator.Analyzers\" PrivateAssets=\"all\" Version=\"4.15.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Roslynator.CodeAnalysis.Analyzers\" PrivateAssets=\"all\" Version=\"4.15.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Roslynator.Formatting.Analyzers\" PrivateAssets=\"all\" Version=\"4.15.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.VisualStudio.Threading.Analyzers\" PrivateAssets=\"all\" Version=\"17.14.15\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"AsyncAwaitBestPractices\" PrivateAssets=\"all\" Version=\"10.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"CSharpGuidelinesAnalyzer\" PrivateAssets=\"all\" Version=\"3.8.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <PropertyGroup>\n    <RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>\n    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>\n    <CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>\n    <AnalysisLevel>latest-Recommended</AnalysisLevel>\n    <AnalysisMode>Recommended</AnalysisMode>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Meysam Hadeli\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": "<div align=\"center\" style=\"margin-bottom:20px\">\n  <img src=\"assets/logo.png\" alt=\"booking-microservices\" />\n    <div align=\"center\">\n           <a href=\"https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml\"><img alt=\"ci-status\" src=\"https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml/badge.svg?branch=main&style=flat-square\"/></a>\n                 <a href=\"https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE\"><img alt=\"build-status\"          src=\"https://img.shields.io/github/license/meysamhadeli/booking-microservices?color=%234275f5&style=flat-square\"/></a>\n    </div>\n</div>\n\n> 🚀 **A practical microservices with the latest technologies and architectures like Vertical Slice Architecture, Event Sourcing, CQRS, DDD, gRpc, MongoDB, RabbitMq, Masstransit, and Aspire in .Net 10.**\n\n## You can find other version of this project here:\n- [Booking with Modular Monolith Architecture](https://github.com/meysamhadeli/booking-modular-monolith)\n- [Booking with Monolith Architecture](https://github.com/meysamhadeli/booking-monolith)\n\n<div>\n  <a href='https://codespaces.new/meysamhadeli/booking-microservices?quickstart=1'><img alt='Open in GitHub Codespaces' src='https://github.com/codespaces/badge.svg'></a>\n</div>\n\n# Table of Contents\n\n- [The Goals of This Project](#the-goals-of-this-project)\n- [Technologies - Libraries](#technologies---libraries)\n- [Key Features](#key-features)\n- [When to Use](#when-to-use)\n- [Challenges](#challenges)\n- [The Domain and Bounded Context - Service Boundary](#the-domain-and-bounded-context---service-boundary)\n- [Structure of Project](#structure-of-project)\n- [Development Setup](#development-setup)\n  - [Dotnet Tools Packages](#dotnet-tools-packages)\n  - [Husky](#husky)\n  - [Upgrade Nuget Packages](#upgrade-nuget-packages)\n- [How to Run](#how-to-run)\n  - [Config Certificate](#config-certificate)\n  - [Aspire](#aspire)\n  - [Docker Compose](#docker-compose)\n  - [Kubernetes](#kubernetes)\n  - [Build](#build)\n  - [Run](#run)\n  - [Test](#test)\n- [Documentation Apis](#documentation-apis)\n- [Support](#support)\n- [Contribution](#contribution)\n\n\n## The Goals of This Project\n\n- :sparkle: Using `Vertical Slice Architecture` for `architecture` level.\n- :sparkle: Using `Domain Driven Design (DDD)` to implement all `business logic`.\n- :sparkle: Using `Rabbitmq` on top of `Masstransit` for `Event Driven Architecture`.\n- :sparkle: Using `gRPC` for `internal communication`.\n- :sparkle: Using `CQRS` implementation with `MediatR` library.\n- :sparkle: Using `Postgres` for `write side` database.\n- :sparkle: Using `MongoDB` for `read side` database.\n- :sparkle: Using `Event Store` for `write side` of Booking Microservice/Module to store all `historical change` of aggregate.\n- :sparkle: Using `Inbox Pattern` for ensuring message idempotency for receiver and `Exactly once Delivery`.\n- :sparkle: Using `Outbox Pattern` for ensuring no message is lost and there is at `At Least One Delivery`.\n- :sparkle: Using `Unit Testing` for testing small units and mocking our dependencies with `Nsubstitute`.\n- :sparkle: Using `End-To-End Testing` and `Integration Testing` for testing `features` with all dependencies using `testcontainers`.\n- :sparkle: Using `Fluent Validation` and a `Validation Pipeline Behaviour` on top of `MediatR`.\n- :sparkle: Using `Minimal API` for all endpoints.\n- :sparkle: Using `AspNetCore OpenApi` for `generating` built-in support `OpenAPI documentation` in ASP.NET Core.\n- :sparkle: Using `Health Check` for `reporting` the `health` of app infrastructure components.\n- :sparkle: Using `Docker-Compose` and `Kubernetes` for our deployment mechanism.\n- :sparkle: Using `Kibana` on top of `Serilog` for `logging`.\n- :sparkle: Using `OpenTelemetry` for distributed tracing on top of `Jaeger`.\n- :sparkle: Using `OpenTelemetry` for monitoring on top of `Prometheus` and `Grafana`.\n- :sparkle: Using `IdentityServer` for authentication and authorization base on `OpenID-Connect` and `OAuth2`.\n- :sparkle: Using `Yarp` as a microservices `gateway`.\n- :sparkle: Using `Kubernetes` to achieve efficient `scaling` and ensure `high availability` for each of our microservices.\n- :sparkle: Using `Nginx Ingress Controller` for `load balancing` between our microservices top of `Kubernetes`.\n- :sparkle: Using `cert-manager` to Configure `TLS` in `kubernetes cluster`.\n- :sparkle: Using `Aspire` for `service discovery`, `observability`, and `local orchestration` of microservices.\n\n\n## Technologies - Libraries\n\n- ✔️ **[`.NET 10`](https://github.com/dotnet/aspnetcore)** - .NET Framework and .NET Core, including ASP.NET and ASP.NET Core.\n- ✔️ **[`MVC Versioning API`](https://github.com/microsoft/aspnet-api-versioning)** - Set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET Core.\n- ✔️ **[`EF Core`](https://github.com/dotnet/efcore)** - Modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.\n- ✔️ **[`AspNetCore OpenApi`](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/aspnetcore-openapi)** - Provides built-in support for OpenAPI document generation in ASP.NET Core.\n- ✔️ **[`Masstransit`](https://github.com/MassTransit/MassTransit)** - Distributed Application Framework for .NET.\n- ✔️ **[`MediatR`](https://github.com/jbogard/MediatR)** - Simple, unambitious mediator implementation in .NET.\n- ✔️ **[`FluentValidation`](https://github.com/FluentValidation/FluentValidation)** - Popular .NET validation library for building strongly-typed validation rules.\n- ✔️ **[`Scalar`](https://github.com/scalar/scalar/tree/main/packages/scalar.aspnetcore)** - Scalar provides an easy way to render beautiful API references based on OpenAPI/Swagger documents.\n- ✔️ **[`Swagger UI`](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)** - Swagger tools for documenting API's built on ASP.NET Core.\n- ✔️ **[`Serilog`](https://github.com/serilog/serilog)** - Simple .NET logging with fully-structured events\n- ✔️ **[`Polly`](https://github.com/App-vNext/Polly)** - Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.\n- ✔️ **[`Scrutor`](https://github.com/khellang/Scrutor)** - Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection\n- ✔️ **[`Opentelemetry-dotnet`](https://github.com/open-telemetry/opentelemetry-dotnet)** - The OpenTelemetry .NET Client\n- ✔️ **[`DuendeSoftware IdentityServer`](https://github.com/DuendeSoftware/IdentityServer)** - The most flexible and standards-compliant OpenID Connect and OAuth 2.x framework for ASP.NET Core.\n- ✔️ **[`EasyCaching`](https://github.com/dotnetcore/EasyCaching)** - Open source caching library that contains basic usages and some advanced usages of caching which can help us to handle caching more easier.\n- ✔️ **[`Mapster`](https://github.com/MapsterMapper/Mapster)** - Convention-based object-object mapper in .NET.\n- ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core.\n- ✔️ **[`NewId`](https://github.com/phatboyg/NewId)** - NewId can be used as an embedded unique ID generator that produces 128 bit (16 bytes) sequential IDs.\n- ✔️ **[`Yarp`](https://github.com/microsoft/reverse-proxy)** - Reverse proxy toolkit for building fast proxy servers in .NET.\n- ✔️ **[`Tye`](https://github.com/dotnet/tye)** - Developer tool that makes developing, testing, and deploying microservices and distributed applications easier.\n- ✔️ **[`gRPC-dotnet`](https://github.com/grpc/grpc-dotnet)** - gRPC functionality for .NET.\n- ✔️ **[`EventStore`](https://github.com/EventStore/EventStore)** - The open-source, functional database with Complex Event Processing.\n- ✔️ **[`MongoDB.Driver`](https://github.com/mongodb/mongo-csharp-driver)** - .NET Driver for MongoDB.\n- ✔️ **[`xUnit.net`](https://github.com/xunit/xunit)** - A free, open source, community-focused unit testing tool for the .NET Framework.\n- ✔️ **[`Respawn`](https://github.com/jbogard/Respawn)** - Respawn is a small utility to help in resetting test databases to a clean state.\n- ✔️ **[`Testcontainers`](https://github.com/testcontainers/testcontainers-dotnet)** - Testcontainers for .NET is a library to support tests with throwaway instances of Docker containers.\n- ✔️ **[`K6`](https://github.com/grafana/k6)** - Modern load testing for developers and testers in the DevOps era.\n- ✔️ **[`Aspire`](https://github.com/dotnet/aspire)** - .NET stack for building and orchestrating observable, distributed cloud-native applications.\n\n\n## Key Features\n1. **Independent Services**: Each service is a separate project with its own database and deployment pipeline, enabling independent development and deployment.\n2. **Decentralized Communication**: Services communicate via APIs (REST, gRPC) or message brokers (RabbitMQ, Kafka), ensuring loose coupling and resilience.\n3. **Scalability**: Services can be scaled independently based on demand, allowing efficient resource utilization.\n4. **Fault Tolerance**: Failures are isolated, preventing cascading failures and ensuring high availability.\n5. **Technology Agnostic**: Services can use different technologies, frameworks, or databases, providing flexibility.\n\n\n## When to Use\n1. **Large and Complex Projects**: Ideal for applications with complex business logic that can be broken into smaller, manageable services.\n2. **High Scalability Needs**: Suitable for applications requiring independent scaling of components.\n3. **Fault Tolerance and High Availability**: Perfect for systems where failure isolation and uptime are critical.\n4. **Distributed Teams**: Enables teams to work independently on different services.\n5. **Frequent Updates**: Supports continuous deployment and A/B testing for individual services.\n6. **Technology Diversity**: Allows the use of different technologies for different services.\n\n\n## Challenges\n- Increased complexity in management, DevOps overhead, data consistency, latency, and higher costs.\n\n\n## The Domain And Bounded Context - Service Boundary\n\n- `Identity Service`: The Identity Service is a bounded context for the authentication and authorization of users using [Identity Server](https://github.com/DuendeSoftware/IdentityServer). This service is responsible for creating new users and their corresponding roles and permissions using [.Net Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) and Jwt authentication and authorization.\n\n- `Flight Service`: The Flight Service is a bounded context `CRUD` service to handle flight related operations.\n\n- `Passenger Service`: The Passenger Service is a bounded context for managing passenger information, tracking activities and subscribing to get notification for out of stock products.\n\n- `Booking Service`: The Booking Service is a bounded context for managing all operation related to booking ticket.\n\n![](./assets/booking-microservices.png)\n\n\n## Structure of Project\n\nIn this project, I used [vertical slice architecture](https://jimmybogard.com/vertical-slice-architecture/) at the architectural level and [feature folder structure](http://www.kamilgrzybek.com/design/feature-folders/) to structure my files.\n\nI treat each request as a distinct use case or slice, encapsulating and grouping all concerns from front-end to back.\nWhen adding or changing a feature in an application in n-tire architecture, we are typically touching many \"layers\" in an application. We are changing the user interface, adding fields to models, modifying validation, and so on. Instead of coupling across a layer, we couple vertically along a slice. We `minimize coupling` `between slices`, and `maximize coupling` `in a slice`.\n\nWith this approach, each of our vertical slices can decide for itself how to best fulfill the request. New features only add code, we're not changing shared code and worrying about side effects.\n\n<div align=\"center\">\n  <img src=\"./assets/vertical-slice-architecture.png\" />\n</div>\n\nInstead of grouping related action methods in one controller, as found in traditional ASP.net controllers, I used the [REPR pattern](https://deviq.com/design-patterns/repr-design-pattern). Each action gets its own small endpoint, consisting of a route, the action, and an `IMediator` instance (see [MediatR](https://github.com/jbogard/MediatR)). The request is passed to the `IMediator` instance, routed through a [`Mediatr pipeline`](https://lostechies.com/jimmybogard/2014/09/09/tackling-cross-cutting-concerns-with-a-mediator-pipeline/) where custom [middleware](https://github.com/jbogard/MediatR/wiki/Behaviors) can log, validate and intercept requests. The request is then handled by a request specific `IRequestHandler` which performs business logic before returning the result.\n\nThe use of the [mediator pattern](https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-in-net-core-part-1-whats-a-mediator/) in my controllers creates clean and [thin controllers](https://codeopinion.com/thin-controllers-cqrs-mediatr/). By separating action logic into individual handlers we support the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle) and [Don't Repeat Yourself principles](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), this is because traditional controllers tend to become bloated with large action methods and several injected `Services` only being used by a few methods.\n\nI used CQRS to decompose my features into small parts that makes our application:\n\n- Maximize performance, scalability and simplicity.\n- Easy to maintain and add features to. Changes only affect one command or query, avoiding breaking changes or creating side effects.\n- It gives us better separation of concerns and cross-cutting concern (with help of mediatr behavior pipelines), instead of bloated service classes doing many things.\n\nUsing the CQRS pattern, we cut each business functionality into vertical slices, for each of these slices we group classes (see [technical folders structure](http://www.kamilgrzybek.com/design/feature-folders)) specific to that feature together (command, handlers, infrastructure, repository, controllers, etc). In our CQRS pattern each command/query handler is a separate slice. This is where you can reduce coupling between layers. Each handler can be a separated code unit, even copy/pasted. Thanks to that, we can tune down the specific method to not follow general conventions (e.g. use custom SQL query or even different storage). In a traditional layered architecture, when we change the core generic mechanism in one layer, it can impact all methods.\n\n\n## Development Setup\n\n### Dotnet Tools Packages\nFor installing our requirement packages with .NET cli tools, we need to install `dotnet tool manifest`.\n```bash\ndotnet new tool-manifest\n```\nAnd after that we can restore our dotnet tools packages with .NET cli tools from `.config` folder and `dotnet-tools.json` file.\n```\ndotnet tool restore\n```\n\n### Husky\nHere we use `husky` to handel some pre commit rules and we used `conventional commits` rules and `formatting` as pre commit rules, here in [package.json](.././package.json). of course, we can add more rules for pre commit in future. (find more about husky in the [documentation](https://typicode.github.io/husky/get-started.html))\nWe need to install `husky` package for `manage` `pre commits hooks` and also I add two packages `@commitlint/cli` and `@commitlint/config-conventional` for handling conventional commits rules in [package.json](.././package.json).\nRun the command bellow in the root of project to install all npm dependencies related to husky:\n\n```bash\nnpm install\n```\n\n> Note: In the root of project we have `.husky` folder and it has `commit-msg` file for handling conventional commits rules with provide user friendly message and `pre-commit` file that we can run our `scripts` as a `pre-commit` hooks. that here we call `format` script from [package.json](./package.json) for formatting purpose.\n\n### Upgrade Nuget Packages\nFor upgrading our nuget packages to last version, we use the great package [dotnet-outdated](https://github.com/dotnet-outdated/dotnet-outdated).\nRun the command below in the root of project to upgrade all of packages to last version:\n```bash\ndotnet outdated -u\n```\n\n## How to Run\n\n> ### Config Certificate\nRun the following commands to [Config SSL](https://docs.microsoft.com/en-us/aspnet/core/security/docker-compose-https?view=aspnetcore-6.0) in your system:\n\n#### Windows using Linux containers\n```bash\ndotnet dev-certs https -ep %USERPROFILE%\\.aspnet\\https\\aspnetapp.pfx -p password\ndotnet dev-certs https --trust\n```\n> Note: for running this command in `powershell` use `$env:USERPROFILE` instead of `%USERPROFILE%`*\n\n#### macOS or Linux\n```bash\ndotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p $CREDENTIAL_PLACEHOLDER$\ndotnet dev-certs https --trust\n```\n\n### Aspire\n\nTo run the application using the `Aspire App Host`, execute the following command from the solution root:\n\n```bash\naspire run\n```\n\n> Note:The `Aspire dashboard` will be available at `http://localhost:18888`\n\n> ### Docker Compose\n\n\nTo run this app in `Docker`, use the [docker-compose.yaml](./deployments/docker-compose/docker-compose.yaml) and execute the below command at the `root` of the application:\n\n```bash\ndocker-compose -f ./deployments/docker-compose/docker-compose.yaml up -d\n```\n\n> ### Kubernetes\nTo `configure TLS` in the `Kubernetes cluster`, we need to install `cert-manager` based on the [docs](https://cert-manager.io/docs/installation) and run the following commands to apply TLS in our application. Here, we use [Let's Encrypt](https://letsencrypt.org/) to encrypt our certificate.\n\n```bash\nkubectl apply -f ./deployments/kubernetes/booking-cert-manager.yml\n```\n\nTo apply all necessary `deployments`, `pods`, `services`, `ingress`, and `config maps`, please run the following command:\n\n```bash\nkubectl apply -f ./deployments/kubernetes/booking-microservices.yml\n```\n\n> ### Build\nTo `build` all microservices, run this command in the `root` of the project:\n```bash\ndotnet build\n```\n\n> ### Run\nTo `run` each microservice, run this command in the root of the `Api` folder of each microservice where the `csproj` file is located:\n```bash\ndotnet run\n```\n\n> ### Test\n\nTo `test` all microservices, run this command in the `root` of the project:\n```bash\ndotnet test\n```\n\n> ### Documentation Apis\n\nEach microservice provides `API documentation` and navigate to `/swagger` for `Swagger OpenAPI` or `/scalar/v1` for `Scalar OpenAPI` to visit list of endpoints.\n\nAs part of API testing, I created the [booking.rest](./booking.rest) file which can be run with the [REST Client](https://github.com/Huachao/vscode-restclient) `VSCode plugin`.\n\n# Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. And we will be happy together :)\n\nThanks a bunch for supporting me!\n\n## Contribution\n\nThanks to all [contributors](https://github.com/meysamhadeli/booking-microservices/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized, community-driven collection of very well-known resources.\n\nPlease follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull request or create the issue.\n\n## Project References & Credits\n\n- [https://github.com/jbogard/ContosoUniversityDotNetCore-Pages](https://github.com/jbogard/ContosoUniversityDotNetCore-Pages)\n- [https://github.com/kgrzybek/modular-monolith-with-ddd](https://github.com/kgrzybek/modular-monolith-with-ddd)\n- [https://github.com/oskardudycz/EventSourcing.NetCore](https://github.com/oskardudycz/EventSourcing.NetCore)\n- [https://github.com/thangchung/clean-architecture-dotnet](https://github.com/thangchung/clean-architecture-dotnet)\n- [https://github.com/pdevito3/MessageBusTestingInMemHarness](https://github.com/pdevito3/MessageBusTestingInMemHarness)\n\n## License\nThis project is made available under the MIT license. See [LICENSE](https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE) for details.\n"
  },
  {
    "path": "assets/booking-microservices.drawio",
    "content": "<mxfile host=\"app.diagrams.net\" agent=\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36\" version=\"28.0.6\">\n  <diagram name=\"Page-1\" id=\"LwSOovy8OdwzHFtQ82wI\">\n    <mxGraphModel dx=\"2852\" dy=\"3254\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"1100\" pageHeight=\"850\" math=\"0\" shadow=\"0\">\n      <root>\n        <mxCell id=\"0\" />\n        <mxCell id=\"1\" parent=\"0\" />\n        <mxCell id=\"Hl4Qm-QQrkKEjvrf066_-2\" value=\"\" style=\"rounded=0;whiteSpace=wrap;html=1;fontFamily=Helvetica;fontSize=12;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"10\" y=\"-1190\" width=\"1800\" height=\"1390\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-73\" value=\"&lt;span style=&quot;color: rgba(0, 0, 0, 0); font-family: monospace; font-size: 0px; text-align: start; text-wrap-mode: nowrap;&quot;&gt;%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%26lt%3Bb%26gt%3B%26lt%3Bfont%26gt%3BOutbox%20Processor%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%22%20style%3D%22text%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D18%3BfontFamily%3DComic%20Sans%20MS%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%2298%22%20y%3D%22-84%22%20width%3D%22145%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#ffe6cc;strokeColor=#d79b00;opacity=50;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"80\" y=\"-388\" width=\"310\" height=\"544\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-6\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;opacity=10;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"120\" y=\"-760\" width=\"370\" height=\"220\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-49\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"3LE55ruSKFipPZqCUEyQ-1\" target=\"PG-S5D8SCmHSsYNVxMVk-10\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-50\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"3LE55ruSKFipPZqCUEyQ-1\" target=\"PG-S5D8SCmHSsYNVxMVk-9\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-143\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=light-dark(#d44e4e, #ededed);align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"3LE55ruSKFipPZqCUEyQ-1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"830\" y=\"-160\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"224\" y=\"-470\" />\n              <mxPoint x=\"830\" y=\"-470\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-152\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"222.00000000000045\" y=\"-620\" as=\"sourcePoint\" />\n            <mxPoint x=\"1008\" y=\"-169\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"222\" y=\"-407\" />\n              <mxPoint x=\"1008\" y=\"-407\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3LE55ruSKFipPZqCUEyQ-1\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/app_services/App_Services.svg;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"190\" y=\"-691\" width=\"68\" height=\"68\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-55\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;shadow=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;elbow=vertical;curved=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"855.5799999999999\" y=\"-1080\" as=\"sourcePoint\" />\n            <mxPoint x=\"306\" y=\"-760\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-58\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1106.5\" y=\"-760\" as=\"targetPoint\" />\n            <mxPoint x=\"958\" y=\"-1079\" as=\"sourcePoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3LE55ruSKFipPZqCUEyQ-5\" value=\"\" style=\"aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;prIcon=ing\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"854.58\" y=\"-1130\" width=\"104.17\" height=\"100\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-173\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1119\" y=\"-122\" as=\"targetPoint\" />\n            <mxPoint x=\"1020\" y=\"-122\" as=\"sourcePoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"-whiLjia1cdvk5nuR-Pi-1\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij4mI3hhOyAgPHBhdGggZD0iTTY3LjY0OCA2OS43OTdjLTUuMjQ2IDUuMjUtNS4yNDYgMTMuNzU4IDAgMTkuMDA4IDUuMjUgNS4yNDYgMTMuNzU4IDUuMjQ2IDE5LjAwNCAwIDUuMjUtNS4yNSA1LjI1LTEzLjc1OCAwLTE5LjAwOC01LjI0Ni01LjI0Ni0xMy43NTQtNS4yNDYtMTkuMDA0IDBabTE0LjIwNyAxNC4yMTlhNi42NDkgNi42NDkgMCAwIDEtOS40MSAwIDYuNjUgNi42NSAwIDAgMSAwLTkuNDA3IDYuNjQ5IDYuNjQ5IDAgMCAxIDkuNDEgMGMyLjU5OCAyLjU4NiAyLjU5OCA2LjgwOSAwIDkuNDA3Wk04Ni40MyAzLjY3MmwtOC4yMzUgOC4yMzRhNC4xNyA0LjE3IDAgMCAwIDAgNS44NzVsMzIuMTQ5IDMyLjE0OWE0LjE3IDQuMTcgMCAwIDAgNS44NzUgMGw4LjIzNC04LjIzNWMxLjYxLTEuNjEgMS42MS00LjI2MSAwLTUuODdMOTIuMjkgMy42NzFhNC4xNTkgNC4xNTkgMCAwIDAtNS44NiAwWk0yOC43MzggMTA4Ljg5NWEzLjc2MyAzLjc2MyAwIDAgMCAwLTUuMzFsLTQuMTgzLTQuMTg3YTMuNzY4IDMuNzY4IDAgMCAwLTUuMzEzIDBsLTguNjQ0IDguNjQ5LS4wMTYuMDEyLTIuMzcxLTIuMzc1Yy0xLjMxMy0xLjMxMy0zLjQ1LTEuMzEzLTQuNzUgMC0xLjMxMyAxLjMxMi0xLjMxMyAzLjQ0OSAwIDQuNzVsMTQuMjQ2IDE0LjI0MmEzLjM1MyAzLjM1MyAwIDAgMCA0Ljc0NiAwYzEuMy0xLjMxMyAxLjMxMy0zLjQ1IDAtNC43NDZsLTIuMzc1LTIuMzc1LjAxNi0uMDEyWm0wIDAiIGZpbGw9IiNmNWE4MDAiLz4mI3hhOyAgPHBhdGggZD0iTTcyLjI5NyAyNy4zMTMgNTQuMDA0IDQ1LjYwNWMtMS42MjUgMS42MjUtMS42MjUgNC4zMDEgMCA1LjkyNkw2NS4zIDYyLjgyNGM3Ljk4NC01Ljc0NiAxOS4xOC01LjAzNSAyNi4zNjMgMi4xNTNsOS4xNDgtOS4xNDljMS42MjItMS42MjUgMS42MjItNC4yOTcgMC01LjkyMkw3OC4yMiAyNy4zMTNhNC4xODUgNC4xODUgMCAwIDAtNS45MjIgMFpNNjAuNTUgNjcuNTg1bC02LjY3Mi02LjY3MmMtMS41NjMtMS41NjItNC4xMjUtMS41NjItNS42ODQgMGwtMjMuNTMgMjMuNTRhNC4wMzYgNC4wMzYgMCAwIDAgMCA1LjY4N2wxMy4zMzEgMTMuMzMyYTQuMDM2IDQuMDM2IDAgMCAwIDUuNjg4IDBsMTUuMTMyLTE1LjE1N2MtMy4xOTktNi42MDktMi42MjUtMTQuNTkzIDEuNzM1LTIwLjczWm0wIDAiIGZpbGw9IiM0MjVjYzciLz4mI3hhOzwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"953.75\" y=\"-169\" width=\"82\" height=\"82\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-9\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNODguMDM4IDQyLjgxMmMxLjYwNSA0LjY0MyAyLjc2MSA5LjM4MyAzLjE0MSAxNC4yOTYuNDcyIDYuMDk1LjI1NiAxMi4xNDctMS4wMjkgMTguMTQyLS4wMzUuMTY1LS4xMDkuMzItLjE2NC40OC0uNDAzLjAwMS0uODE0LS4wNDktMS4yMDguMDEyLTMuMzI5LjUyMy02LjY1NSAxLjA2NS05Ljk4MSAxLjYwNC0zLjQzOC41NTctNi44ODEgMS4wOTItMTAuMzEzIDEuNjg3LTEuMjE2LjIxLTIuNzIxLS4wNDEtMy4yMTIgMS42NDEtLjAxNC4wNDYtLjE1NC4wNTQtLjIzNS4wOGwuMTY2LTEwLjA1MS0uMTY5LTI0LjI1MiAxLjYwMi0uMjc1YzIuNjItLjQyOSA1LjI0LS44NjQgNy44NjItMS4yODEgMy4xMjktLjQ5NyA2LjI2MS0uOTggOS4zOTItMS40NjUgMS4zODEtLjIxNSAyLjc2NC0uNDEyIDQuMTQ4LS42MTh6IiBmaWxsPSIjNDM5OTM0IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02MS43MjkgMTEwLjA1NGMtMS42OS0xLjQ1My0zLjQzOS0yLjg0Mi01LjA1OS00LjM3LTguNzE3LTguMjIyLTE1LjA5My0xNy44OTktMTguMjMzLTI5LjU2Ni0uODY1LTMuMjExLTEuNDQyLTYuNDc0LTEuNjI3LTkuNzkyLS4xMy0yLjMyMi0uMzE4LTQuNjY1LS4xNTQtNi45NzUuNDM3LTYuMTQ0IDEuMzI1LTEyLjIyOSAzLjEyNy0xOC4xNDdsLjA5OS0uMTM4Yy4xNzUuMjMzLjQyNy40MzkuNTE2LjcwMiAxLjc1OSA1LjE4IDMuNTA1IDEwLjM2NCA1LjI0MiAxNS41NTEgNS40NTggMTYuMyAxMC45MDkgMzIuNjA0IDE2LjM3NiA0OC45LjEwNy4zMTguMzg0LjU3OS41ODMuODY2bC0uODcgMi45Njl6IiBmaWxsPSIjNDVBNTM4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik04OC4wMzggNDIuODEyYy0xLjM4NC4yMDYtMi43NjguNDAzLTQuMTQ5LjYxNi0zLjEzMS40ODUtNi4yNjMuOTY4LTkuMzkyIDEuNDY1LTIuNjIyLjQxNy01LjI0Mi44NTItNy44NjIgMS4yODFsLTEuNjAyLjI3NS0uMDEyLTEuMDQ1Yy0uMDUzLS44NTktLjE0NC0xLjcxNy0uMTU0LTIuNTc2LS4wNjktNS40NzgtLjExMi0xMC45NTYtLjE4LTE2LjQzNC0uMDQyLTMuNDI5LS4xMDUtNi44NTctLjE3NS0xMC4yODUtLjA0My0yLjEzLS4wODktNC4yNjEtLjE4NS02LjM4OC0uMDUyLTEuMTQzLS4yMzYtMi4yOC0uMzExLTMuNDIzLS4wNDItLjY1Ny4wMTYtMS4zMTkuMDI5LTEuOTc5LjgxNyAxLjU4MyAxLjYxNiAzLjE3OCAyLjQ1NiA0Ljc0OSAxLjMyNyAyLjQ4NCAzLjQ0MSA0LjMxNCA1LjM0NCA2LjMxMSA3LjUyMyA3Ljg5MiAxMi44NjQgMTcuMDY4IDE2LjE5MyAyNy40MzN6IiBmaWxsPSIjNDZBMDM3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMzYgODAuNzUzYy4wODEtLjAyNi4yMjItLjAzNC4yMzUtLjA4LjQ5MS0xLjY4MiAxLjk5Ni0xLjQzMSAzLjIxMi0xLjY0MSAzLjQzMi0uNTk0IDYuODc1LTEuMTMgMTAuMzEzLTEuNjg3IDMuMzI2LS41MzkgNi42NTItMS4wODEgOS45ODEtMS42MDQuMzk0LS4wNjIuODA1LS4wMTEgMS4yMDgtLjAxMi0uNjIyIDIuMjItMS4xMTIgNC40ODgtMS45MDEgNi42NDctLjg5NiAyLjQ0OS0xLjk4IDQuODM5LTMuMTMxIDcuMTgyYTQ5LjE0MiA0OS4xNDIgMCAwMS02LjM1MyA5Ljc2M2MtMS45MTkgMi4zMDgtNC4wNTggNC40NDEtNi4yMDIgNi41NDgtMS4xODUgMS4xNjUtMi41ODIgMi4xMTQtMy44ODIgMy4xNjFsLS4zMzctLjIzLTEuMjE0LTEuMDM4LTEuMjU2LTIuNzUzYTQxLjQwMiA0MS40MDIgMCAwMS0xLjM5NC05LjgzOGwuMDIzLS41NjEuMTcxLTIuNDI2Yy4wNTctLjgyOC4xMzMtMS42NTUuMTY4LTIuNDg1LjEyOS0yLjk4Mi4yNDEtNS45NjQuMzU5LTguOTQ2eiIgZmlsbD0iIzQwOTQzMyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjUuMDM2IDgwLjc1M2MtLjExOCAyLjk4Mi0uMjMgNS45NjQtLjM1NyA4Ljk0Ny0uMDM1LjgzLS4xMTEgMS42NTctLjE2OCAyLjQ4NWwtLjc2NS4yODljLTEuNjk5LTUuMDAyLTMuMzk5LTkuOTUxLTUuMDYyLTE0LjkxMy0yLjc1LTguMjA5LTUuNDY3LTE2LjQzMS04LjIxMy0yNC42NDJhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMC02LjctMTkuODY3Yy0uMTA1LS4zMS0uNDA3LS41NTItLjYxNy0uODI2bDQuODk2LTkuMDAyYy4xNjguMjkyLjM5LjU2NS40OTYuODc5YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDE2Ljc2OCAyMC4xMThjMi45MTYgOC43MyA1LjgxNCAxNy40NjcgOC43MjggMjYuMTk4LjExNi4zNDkuMzA4LjY3MS40OTEgMS4wNjJsLjY3LS43OC0uMTY3IDEwLjA1MnoiIGZpbGw9IiM0RkFBNDEiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTQzLjE1NSAzMi4yMjdjLjIxLjI3NC41MTEuNTE2LjYxNy44MjZhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMTYuNyAxOS44NjdjMi43NDYgOC4yMTEgNS40NjMgMTYuNDMzIDguMjEzIDI0LjY0MiAxLjY2MiA0Ljk2MSAzLjM2MiA5LjkxMSA1LjA2MiAxNC45MTNsLjc2NS0uMjg5LS4xNzEgMi40MjYtLjE1NS41NTljLS4yNjYgMi42NTYtLjQ5IDUuMzE4LS44MTQgNy45NjgtLjE2MyAxLjMyOC0uNTA5IDIuNjMyLS43NzIgMy45NDctLjE5OC0uMjg3LS40NzYtLjU0OC0uNTgzLS44NjYtNS40NjctMTYuMjk3LTEwLjkxOC0zMi42LTE2LjM3Ni00OC45YTM4ODguOTcyIDM4ODguOTcyIDAgMDAtNS4yNDItMTUuNTUxYy0uMDg5LS4yNjMtLjM0LS40NjktLjUxNi0uNzAybDMuMjcyLTguODR6IiBmaWxsPSIjNEFBNzNDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4yMDIgNzAuNzAybC0uNjcuNzhjLS4xODMtLjM5MS0uMzc1LS43MTQtLjQ5MS0xLjA2Mi0yLjkxMy04LjczMS01LjgxMi0xNy40NjgtOC43MjgtMjYuMTk4YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDAtNi43NjgtMjAuMTE4Yy0uMTA1LS4zMTQtLjMyNy0uNTg4LS40OTYtLjg3OWw2LjA1NS03Ljk2NWMuMTkxLjI1NS40NjMuNDgyLjU2Mi43NjkgMS42ODEgNC45MjEgMy4zNDcgOS44NDggNS4wMDMgMTQuNzc4IDEuNTQ3IDQuNjA0IDMuMDcxIDkuMjE1IDQuNjM2IDEzLjgxMy4xMDUuMzA4LjQ3LjUyNi43MTQuNzg2bC4wMTIgMS4wNDVjLjA1OCA4LjA4Mi4xMTUgMTYuMTY3LjE3MSAyNC4yNTF6IiBmaWxsPSIjNTdBRTQ3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMjEgNDUuNDA0Yy0uMjQ0LS4yNi0uNjA5LS40NzgtLjcxNC0uNzg2LTEuNTY1LTQuNTk4LTMuMDg5LTkuMjA5LTQuNjM2LTEzLjgxMy0xLjY1Ni00LjkzLTMuMzIyLTkuODU2LTUuMDAzLTE0Ljc3OC0uMDk5LS4yODctLjM3MS0uNTE0LS41NjItLjc2OSAxLjk2OS0xLjkyOCAzLjg3Ny0zLjkyNSA1LjkyNS01Ljc2NCAxLjgyMS0xLjYzNCAzLjI4NS0zLjM4NiAzLjM1Mi01Ljk2OC4wMDMtLjEwNy4wNTktLjIxNC4xNDUtLjUxNGwuNTE5IDEuMzA2Yy0uMDEzLjY2MS0uMDcyIDEuMzIyLS4wMjkgMS45NzkuMDc1IDEuMTQzLjI1OSAyLjI4LjMxMSAzLjQyMy4wOTYgMi4xMjcuMTQyIDQuMjU4LjE4NSA2LjM4OC4wNjkgMy40MjguMTMyIDYuODU2LjE3NSAxMC4yODUuMDY3IDUuNDc4LjExMSAxMC45NTYuMTggMTYuNDM0LjAwOC44NjEuMDk4IDEuNzE4LjE1MiAyLjU3N3oiIGZpbGw9IiM2MEIyNEYiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjU5OCAxMDcuMDg1Yy4yNjMtMS4zMTUuNjA5LTIuNjIuNzcyLTMuOTQ3LjMyNS0yLjY0OS41NDgtNS4zMTIuODE0LTcuOTY4bC4wNjYtLjAxLjA2Ni4wMTFhNDEuNDAyIDQxLjQwMiAwIDAwMS4zOTQgOS44MzhjLS4xNzYuMjMyLS40MjUuNDM5LS41MTguNzAxLS43MjcgMi4wNS0xLjQxMiA0LjExNi0yLjE0MyA2LjE2Ni0uMS4yOC0uMzc4LjQ5OC0uNTc0Ljc0NGwtLjc0Ny0yLjU2Ni44Ny0yLjk2OXoiIGZpbGw9IiNBOUFBODgiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjQ3NiAxMTIuNjIxYy4xOTYtLjI0Ni40NzUtLjQ2NC41NzQtLjc0NC43MzEtMi4wNSAxLjQxNy00LjExNSAyLjE0My02LjE2Ni4wOTMtLjI2Mi4zNDEtLjQ2OS41MTgtLjcwMWwxLjI1NSAyLjc1NGMtLjI0OC4zNTItLjU5LjY2OS0uNzI4IDEuMDYxbC0yLjQwNCA3LjA1OWMtLjA5OS4yODMtLjQzNy40ODMtLjY2My43MjJsLS42OTUtMy45ODV6IiBmaWxsPSIjQjZCNTk4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02My4xNzEgMTE2LjYwNWMuMjI3LS4yMzguNTY0LS40MzkuNjYzLS43MjJsMi40MDQtNy4wNTljLjEzNy0uMzkxLjQ4LS43MDkuNzI4LTEuMDYxbDEuMjE1IDEuMDM3Yy0uNTg3LjU4LS45MTMgMS4yNS0uNzE3IDIuMDk3bC0uMzY5IDEuMjA4Yy0uMTY4LjIwNy0uNDExLjM4Ny0uNDk0LjYyNC0uODM5IDIuNDAzLTEuNjQgNC44MTktMi40ODUgNy4yMjItLjEwNy4zMDUtLjQwNC41NDQtLjYxNC44MTItLjEwOS0xLjM4Ny0uMjItMi43NzEtLjMzMS00LjE1OHoiIGZpbGw9IiNDMkMxQTciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYzLjUwMyAxMjAuNzYzYy4yMDktLjI2OS41MDYtLjUwOC42MTQtLjgxMi44NDUtMi40MDIgMS42NDYtNC44MTggMi40ODUtNy4yMjIuMDgzLS4yMzYuMzI1LS40MTcuNDk0LS42MjRsLS41MDkgNS41NDVjLS4xMzYuMTU3LS4zMzMuMjk0LS4zOTguNDc3LS41NzUgMS42MTQtMS4xMTcgMy4yNC0xLjY5NCA0Ljg1NC0uMTE5LjMzMy0uMzQ3LjYyNy0uNTI1LjkzOC0uMTU4LS4yMDctLjQ0MS0uNDA3LS40NTQtLjYyMy0uMDUxLS44NDEtLjAxNi0xLjY4OC0uMDEzLTIuNTMzeiIgZmlsbD0iI0NFQ0RCNyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjMuOTY5IDEyMy45MTljLjE3OC0uMzEyLjQwNi0uNjA2LjUyNS0uOTM4LjU3OC0xLjYxMyAxLjExOS0zLjIzOSAxLjY5NC00Ljg1NC4wNjUtLjE4My4yNjMtLjMxOS4zOTgtLjQ3N2wuMDEyIDMuNjQtMS4yMTggMy4xMjQtMS40MTEtLjQ5NXoiIGZpbGw9IiNEQkRBQzciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY1LjM4IDEyNC40MTVsMS4yMTgtMy4xMjQuMjUxIDMuNjk2LTEuNDY5LS41NzJ6IiBmaWxsPSIjRUJFOURDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02Ny40NjQgMTEwLjg5OGMtLjE5Ni0uODQ3LjEyOS0xLjUxOC43MTctMi4wOTdsLjMzNy4yMy0xLjA1NCAxLjg2N3oiIGZpbGw9IiNDRUNEQjciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY0LjMxNiA5NS4xNzJsLS4wNjYtLjAxMS0uMDY2LjAxLjE1NS0uNTU5LS4wMjMuNTZ6IiBmaWxsPSIjNEZBQTQxIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"400\" y=\"-646\" width=\"70\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-10\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"400\" y=\"-710\" width=\"60\" height=\"60\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-11\" value=\"&lt;b&gt;&lt;font&gt;Api&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"190\" y=\"-623\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-20\" value=\"&lt;b&gt;Identity Service&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"170\" y=\"-749\" width=\"170\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-24\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#d5e8d4;strokeColor=#82b366;opacity=30;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"520\" y=\"-760\" width=\"370\" height=\"220\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-25\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#e1d5e7;strokeColor=#9673a6;opacity=30;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"920\" y=\"-760\" width=\"370\" height=\"220\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-26\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#bac8d3;strokeColor=#23445d;opacity=20;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1320\" y=\"-760\" width=\"370\" height=\"220\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-28\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"785\" y=\"-710\" width=\"60\" height=\"60\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-29\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNODguMDM4IDQyLjgxMmMxLjYwNSA0LjY0MyAyLjc2MSA5LjM4MyAzLjE0MSAxNC4yOTYuNDcyIDYuMDk1LjI1NiAxMi4xNDctMS4wMjkgMTguMTQyLS4wMzUuMTY1LS4xMDkuMzItLjE2NC40OC0uNDAzLjAwMS0uODE0LS4wNDktMS4yMDguMDEyLTMuMzI5LjUyMy02LjY1NSAxLjA2NS05Ljk4MSAxLjYwNC0zLjQzOC41NTctNi44ODEgMS4wOTItMTAuMzEzIDEuNjg3LTEuMjE2LjIxLTIuNzIxLS4wNDEtMy4yMTIgMS42NDEtLjAxNC4wNDYtLjE1NC4wNTQtLjIzNS4wOGwuMTY2LTEwLjA1MS0uMTY5LTI0LjI1MiAxLjYwMi0uMjc1YzIuNjItLjQyOSA1LjI0LS44NjQgNy44NjItMS4yODEgMy4xMjktLjQ5NyA2LjI2MS0uOTggOS4zOTItMS40NjUgMS4zODEtLjIxNSAyLjc2NC0uNDEyIDQuMTQ4LS42MTh6IiBmaWxsPSIjNDM5OTM0IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02MS43MjkgMTEwLjA1NGMtMS42OS0xLjQ1My0zLjQzOS0yLjg0Mi01LjA1OS00LjM3LTguNzE3LTguMjIyLTE1LjA5My0xNy44OTktMTguMjMzLTI5LjU2Ni0uODY1LTMuMjExLTEuNDQyLTYuNDc0LTEuNjI3LTkuNzkyLS4xMy0yLjMyMi0uMzE4LTQuNjY1LS4xNTQtNi45NzUuNDM3LTYuMTQ0IDEuMzI1LTEyLjIyOSAzLjEyNy0xOC4xNDdsLjA5OS0uMTM4Yy4xNzUuMjMzLjQyNy40MzkuNTE2LjcwMiAxLjc1OSA1LjE4IDMuNTA1IDEwLjM2NCA1LjI0MiAxNS41NTEgNS40NTggMTYuMyAxMC45MDkgMzIuNjA0IDE2LjM3NiA0OC45LjEwNy4zMTguMzg0LjU3OS41ODMuODY2bC0uODcgMi45Njl6IiBmaWxsPSIjNDVBNTM4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik04OC4wMzggNDIuODEyYy0xLjM4NC4yMDYtMi43NjguNDAzLTQuMTQ5LjYxNi0zLjEzMS40ODUtNi4yNjMuOTY4LTkuMzkyIDEuNDY1LTIuNjIyLjQxNy01LjI0Mi44NTItNy44NjIgMS4yODFsLTEuNjAyLjI3NS0uMDEyLTEuMDQ1Yy0uMDUzLS44NTktLjE0NC0xLjcxNy0uMTU0LTIuNTc2LS4wNjktNS40NzgtLjExMi0xMC45NTYtLjE4LTE2LjQzNC0uMDQyLTMuNDI5LS4xMDUtNi44NTctLjE3NS0xMC4yODUtLjA0My0yLjEzLS4wODktNC4yNjEtLjE4NS02LjM4OC0uMDUyLTEuMTQzLS4yMzYtMi4yOC0uMzExLTMuNDIzLS4wNDItLjY1Ny4wMTYtMS4zMTkuMDI5LTEuOTc5LjgxNyAxLjU4MyAxLjYxNiAzLjE3OCAyLjQ1NiA0Ljc0OSAxLjMyNyAyLjQ4NCAzLjQ0MSA0LjMxNCA1LjM0NCA2LjMxMSA3LjUyMyA3Ljg5MiAxMi44NjQgMTcuMDY4IDE2LjE5MyAyNy40MzN6IiBmaWxsPSIjNDZBMDM3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMzYgODAuNzUzYy4wODEtLjAyNi4yMjItLjAzNC4yMzUtLjA4LjQ5MS0xLjY4MiAxLjk5Ni0xLjQzMSAzLjIxMi0xLjY0MSAzLjQzMi0uNTk0IDYuODc1LTEuMTMgMTAuMzEzLTEuNjg3IDMuMzI2LS41MzkgNi42NTItMS4wODEgOS45ODEtMS42MDQuMzk0LS4wNjIuODA1LS4wMTEgMS4yMDgtLjAxMi0uNjIyIDIuMjItMS4xMTIgNC40ODgtMS45MDEgNi42NDctLjg5NiAyLjQ0OS0xLjk4IDQuODM5LTMuMTMxIDcuMTgyYTQ5LjE0MiA0OS4xNDIgMCAwMS02LjM1MyA5Ljc2M2MtMS45MTkgMi4zMDgtNC4wNTggNC40NDEtNi4yMDIgNi41NDgtMS4xODUgMS4xNjUtMi41ODIgMi4xMTQtMy44ODIgMy4xNjFsLS4zMzctLjIzLTEuMjE0LTEuMDM4LTEuMjU2LTIuNzUzYTQxLjQwMiA0MS40MDIgMCAwMS0xLjM5NC05LjgzOGwuMDIzLS41NjEuMTcxLTIuNDI2Yy4wNTctLjgyOC4xMzMtMS42NTUuMTY4LTIuNDg1LjEyOS0yLjk4Mi4yNDEtNS45NjQuMzU5LTguOTQ2eiIgZmlsbD0iIzQwOTQzMyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjUuMDM2IDgwLjc1M2MtLjExOCAyLjk4Mi0uMjMgNS45NjQtLjM1NyA4Ljk0Ny0uMDM1LjgzLS4xMTEgMS42NTctLjE2OCAyLjQ4NWwtLjc2NS4yODljLTEuNjk5LTUuMDAyLTMuMzk5LTkuOTUxLTUuMDYyLTE0LjkxMy0yLjc1LTguMjA5LTUuNDY3LTE2LjQzMS04LjIxMy0yNC42NDJhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMC02LjctMTkuODY3Yy0uMTA1LS4zMS0uNDA3LS41NTItLjYxNy0uODI2bDQuODk2LTkuMDAyYy4xNjguMjkyLjM5LjU2NS40OTYuODc5YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDE2Ljc2OCAyMC4xMThjMi45MTYgOC43MyA1LjgxNCAxNy40NjcgOC43MjggMjYuMTk4LjExNi4zNDkuMzA4LjY3MS40OTEgMS4wNjJsLjY3LS43OC0uMTY3IDEwLjA1MnoiIGZpbGw9IiM0RkFBNDEiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTQzLjE1NSAzMi4yMjdjLjIxLjI3NC41MTEuNTE2LjYxNy44MjZhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMTYuNyAxOS44NjdjMi43NDYgOC4yMTEgNS40NjMgMTYuNDMzIDguMjEzIDI0LjY0MiAxLjY2MiA0Ljk2MSAzLjM2MiA5LjkxMSA1LjA2MiAxNC45MTNsLjc2NS0uMjg5LS4xNzEgMi40MjYtLjE1NS41NTljLS4yNjYgMi42NTYtLjQ5IDUuMzE4LS44MTQgNy45NjgtLjE2MyAxLjMyOC0uNTA5IDIuNjMyLS43NzIgMy45NDctLjE5OC0uMjg3LS40NzYtLjU0OC0uNTgzLS44NjYtNS40NjctMTYuMjk3LTEwLjkxOC0zMi42LTE2LjM3Ni00OC45YTM4ODguOTcyIDM4ODguOTcyIDAgMDAtNS4yNDItMTUuNTUxYy0uMDg5LS4yNjMtLjM0LS40NjktLjUxNi0uNzAybDMuMjcyLTguODR6IiBmaWxsPSIjNEFBNzNDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4yMDIgNzAuNzAybC0uNjcuNzhjLS4xODMtLjM5MS0uMzc1LS43MTQtLjQ5MS0xLjA2Mi0yLjkxMy04LjczMS01LjgxMi0xNy40NjgtOC43MjgtMjYuMTk4YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDAtNi43NjgtMjAuMTE4Yy0uMTA1LS4zMTQtLjMyNy0uNTg4LS40OTYtLjg3OWw2LjA1NS03Ljk2NWMuMTkxLjI1NS40NjMuNDgyLjU2Mi43NjkgMS42ODEgNC45MjEgMy4zNDcgOS44NDggNS4wMDMgMTQuNzc4IDEuNTQ3IDQuNjA0IDMuMDcxIDkuMjE1IDQuNjM2IDEzLjgxMy4xMDUuMzA4LjQ3LjUyNi43MTQuNzg2bC4wMTIgMS4wNDVjLjA1OCA4LjA4Mi4xMTUgMTYuMTY3LjE3MSAyNC4yNTF6IiBmaWxsPSIjNTdBRTQ3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMjEgNDUuNDA0Yy0uMjQ0LS4yNi0uNjA5LS40NzgtLjcxNC0uNzg2LTEuNTY1LTQuNTk4LTMuMDg5LTkuMjA5LTQuNjM2LTEzLjgxMy0xLjY1Ni00LjkzLTMuMzIyLTkuODU2LTUuMDAzLTE0Ljc3OC0uMDk5LS4yODctLjM3MS0uNTE0LS41NjItLjc2OSAxLjk2OS0xLjkyOCAzLjg3Ny0zLjkyNSA1LjkyNS01Ljc2NCAxLjgyMS0xLjYzNCAzLjI4NS0zLjM4NiAzLjM1Mi01Ljk2OC4wMDMtLjEwNy4wNTktLjIxNC4xNDUtLjUxNGwuNTE5IDEuMzA2Yy0uMDEzLjY2MS0uMDcyIDEuMzIyLS4wMjkgMS45NzkuMDc1IDEuMTQzLjI1OSAyLjI4LjMxMSAzLjQyMy4wOTYgMi4xMjcuMTQyIDQuMjU4LjE4NSA2LjM4OC4wNjkgMy40MjguMTMyIDYuODU2LjE3NSAxMC4yODUuMDY3IDUuNDc4LjExMSAxMC45NTYuMTggMTYuNDM0LjAwOC44NjEuMDk4IDEuNzE4LjE1MiAyLjU3N3oiIGZpbGw9IiM2MEIyNEYiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjU5OCAxMDcuMDg1Yy4yNjMtMS4zMTUuNjA5LTIuNjIuNzcyLTMuOTQ3LjMyNS0yLjY0OS41NDgtNS4zMTIuODE0LTcuOTY4bC4wNjYtLjAxLjA2Ni4wMTFhNDEuNDAyIDQxLjQwMiAwIDAwMS4zOTQgOS44MzhjLS4xNzYuMjMyLS40MjUuNDM5LS41MTguNzAxLS43MjcgMi4wNS0xLjQxMiA0LjExNi0yLjE0MyA2LjE2Ni0uMS4yOC0uMzc4LjQ5OC0uNTc0Ljc0NGwtLjc0Ny0yLjU2Ni44Ny0yLjk2OXoiIGZpbGw9IiNBOUFBODgiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjQ3NiAxMTIuNjIxYy4xOTYtLjI0Ni40NzUtLjQ2NC41NzQtLjc0NC43MzEtMi4wNSAxLjQxNy00LjExNSAyLjE0My02LjE2Ni4wOTMtLjI2Mi4zNDEtLjQ2OS41MTgtLjcwMWwxLjI1NSAyLjc1NGMtLjI0OC4zNTItLjU5LjY2OS0uNzI4IDEuMDYxbC0yLjQwNCA3LjA1OWMtLjA5OS4yODMtLjQzNy40ODMtLjY2My43MjJsLS42OTUtMy45ODV6IiBmaWxsPSIjQjZCNTk4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02My4xNzEgMTE2LjYwNWMuMjI3LS4yMzguNTY0LS40MzkuNjYzLS43MjJsMi40MDQtNy4wNTljLjEzNy0uMzkxLjQ4LS43MDkuNzI4LTEuMDYxbDEuMjE1IDEuMDM3Yy0uNTg3LjU4LS45MTMgMS4yNS0uNzE3IDIuMDk3bC0uMzY5IDEuMjA4Yy0uMTY4LjIwNy0uNDExLjM4Ny0uNDk0LjYyNC0uODM5IDIuNDAzLTEuNjQgNC44MTktMi40ODUgNy4yMjItLjEwNy4zMDUtLjQwNC41NDQtLjYxNC44MTItLjEwOS0xLjM4Ny0uMjItMi43NzEtLjMzMS00LjE1OHoiIGZpbGw9IiNDMkMxQTciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYzLjUwMyAxMjAuNzYzYy4yMDktLjI2OS41MDYtLjUwOC42MTQtLjgxMi44NDUtMi40MDIgMS42NDYtNC44MTggMi40ODUtNy4yMjIuMDgzLS4yMzYuMzI1LS40MTcuNDk0LS42MjRsLS41MDkgNS41NDVjLS4xMzYuMTU3LS4zMzMuMjk0LS4zOTguNDc3LS41NzUgMS42MTQtMS4xMTcgMy4yNC0xLjY5NCA0Ljg1NC0uMTE5LjMzMy0uMzQ3LjYyNy0uNTI1LjkzOC0uMTU4LS4yMDctLjQ0MS0uNDA3LS40NTQtLjYyMy0uMDUxLS44NDEtLjAxNi0xLjY4OC0uMDEzLTIuNTMzeiIgZmlsbD0iI0NFQ0RCNyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjMuOTY5IDEyMy45MTljLjE3OC0uMzEyLjQwNi0uNjA2LjUyNS0uOTM4LjU3OC0xLjYxMyAxLjExOS0zLjIzOSAxLjY5NC00Ljg1NC4wNjUtLjE4My4yNjMtLjMxOS4zOTgtLjQ3N2wuMDEyIDMuNjQtMS4yMTggMy4xMjQtMS40MTEtLjQ5NXoiIGZpbGw9IiNEQkRBQzciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY1LjM4IDEyNC40MTVsMS4yMTgtMy4xMjQuMjUxIDMuNjk2LTEuNDY5LS41NzJ6IiBmaWxsPSIjRUJFOURDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02Ny40NjQgMTEwLjg5OGMtLjE5Ni0uODQ3LjEyOS0xLjUxOC43MTctMi4wOTdsLjMzNy4yMy0xLjA1NCAxLjg2N3oiIGZpbGw9IiNDRUNEQjciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY0LjMxNiA5NS4xNzJsLS4wNjYtLjAxMS0uMDY2LjAxLjE1NS0uNTU5LS4wMjMuNTZ6IiBmaWxsPSIjNEZBQTQxIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"785\" y=\"-645\" width=\"70\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-30\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNODguMDM4IDQyLjgxMmMxLjYwNSA0LjY0MyAyLjc2MSA5LjM4MyAzLjE0MSAxNC4yOTYuNDcyIDYuMDk1LjI1NiAxMi4xNDctMS4wMjkgMTguMTQyLS4wMzUuMTY1LS4xMDkuMzItLjE2NC40OC0uNDAzLjAwMS0uODE0LS4wNDktMS4yMDguMDEyLTMuMzI5LjUyMy02LjY1NSAxLjA2NS05Ljk4MSAxLjYwNC0zLjQzOC41NTctNi44ODEgMS4wOTItMTAuMzEzIDEuNjg3LTEuMjE2LjIxLTIuNzIxLS4wNDEtMy4yMTIgMS42NDEtLjAxNC4wNDYtLjE1NC4wNTQtLjIzNS4wOGwuMTY2LTEwLjA1MS0uMTY5LTI0LjI1MiAxLjYwMi0uMjc1YzIuNjItLjQyOSA1LjI0LS44NjQgNy44NjItMS4yODEgMy4xMjktLjQ5NyA2LjI2MS0uOTggOS4zOTItMS40NjUgMS4zODEtLjIxNSAyLjc2NC0uNDEyIDQuMTQ4LS42MTh6IiBmaWxsPSIjNDM5OTM0IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02MS43MjkgMTEwLjA1NGMtMS42OS0xLjQ1My0zLjQzOS0yLjg0Mi01LjA1OS00LjM3LTguNzE3LTguMjIyLTE1LjA5My0xNy44OTktMTguMjMzLTI5LjU2Ni0uODY1LTMuMjExLTEuNDQyLTYuNDc0LTEuNjI3LTkuNzkyLS4xMy0yLjMyMi0uMzE4LTQuNjY1LS4xNTQtNi45NzUuNDM3LTYuMTQ0IDEuMzI1LTEyLjIyOSAzLjEyNy0xOC4xNDdsLjA5OS0uMTM4Yy4xNzUuMjMzLjQyNy40MzkuNTE2LjcwMiAxLjc1OSA1LjE4IDMuNTA1IDEwLjM2NCA1LjI0MiAxNS41NTEgNS40NTggMTYuMyAxMC45MDkgMzIuNjA0IDE2LjM3NiA0OC45LjEwNy4zMTguMzg0LjU3OS41ODMuODY2bC0uODcgMi45Njl6IiBmaWxsPSIjNDVBNTM4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik04OC4wMzggNDIuODEyYy0xLjM4NC4yMDYtMi43NjguNDAzLTQuMTQ5LjYxNi0zLjEzMS40ODUtNi4yNjMuOTY4LTkuMzkyIDEuNDY1LTIuNjIyLjQxNy01LjI0Mi44NTItNy44NjIgMS4yODFsLTEuNjAyLjI3NS0uMDEyLTEuMDQ1Yy0uMDUzLS44NTktLjE0NC0xLjcxNy0uMTU0LTIuNTc2LS4wNjktNS40NzgtLjExMi0xMC45NTYtLjE4LTE2LjQzNC0uMDQyLTMuNDI5LS4xMDUtNi44NTctLjE3NS0xMC4yODUtLjA0My0yLjEzLS4wODktNC4yNjEtLjE4NS02LjM4OC0uMDUyLTEuMTQzLS4yMzYtMi4yOC0uMzExLTMuNDIzLS4wNDItLjY1Ny4wMTYtMS4zMTkuMDI5LTEuOTc5LjgxNyAxLjU4MyAxLjYxNiAzLjE3OCAyLjQ1NiA0Ljc0OSAxLjMyNyAyLjQ4NCAzLjQ0MSA0LjMxNCA1LjM0NCA2LjMxMSA3LjUyMyA3Ljg5MiAxMi44NjQgMTcuMDY4IDE2LjE5MyAyNy40MzN6IiBmaWxsPSIjNDZBMDM3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMzYgODAuNzUzYy4wODEtLjAyNi4yMjItLjAzNC4yMzUtLjA4LjQ5MS0xLjY4MiAxLjk5Ni0xLjQzMSAzLjIxMi0xLjY0MSAzLjQzMi0uNTk0IDYuODc1LTEuMTMgMTAuMzEzLTEuNjg3IDMuMzI2LS41MzkgNi42NTItMS4wODEgOS45ODEtMS42MDQuMzk0LS4wNjIuODA1LS4wMTEgMS4yMDgtLjAxMi0uNjIyIDIuMjItMS4xMTIgNC40ODgtMS45MDEgNi42NDctLjg5NiAyLjQ0OS0xLjk4IDQuODM5LTMuMTMxIDcuMTgyYTQ5LjE0MiA0OS4xNDIgMCAwMS02LjM1MyA5Ljc2M2MtMS45MTkgMi4zMDgtNC4wNTggNC40NDEtNi4yMDIgNi41NDgtMS4xODUgMS4xNjUtMi41ODIgMi4xMTQtMy44ODIgMy4xNjFsLS4zMzctLjIzLTEuMjE0LTEuMDM4LTEuMjU2LTIuNzUzYTQxLjQwMiA0MS40MDIgMCAwMS0xLjM5NC05LjgzOGwuMDIzLS41NjEuMTcxLTIuNDI2Yy4wNTctLjgyOC4xMzMtMS42NTUuMTY4LTIuNDg1LjEyOS0yLjk4Mi4yNDEtNS45NjQuMzU5LTguOTQ2eiIgZmlsbD0iIzQwOTQzMyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjUuMDM2IDgwLjc1M2MtLjExOCAyLjk4Mi0uMjMgNS45NjQtLjM1NyA4Ljk0Ny0uMDM1LjgzLS4xMTEgMS42NTctLjE2OCAyLjQ4NWwtLjc2NS4yODljLTEuNjk5LTUuMDAyLTMuMzk5LTkuOTUxLTUuMDYyLTE0LjkxMy0yLjc1LTguMjA5LTUuNDY3LTE2LjQzMS04LjIxMy0yNC42NDJhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMC02LjctMTkuODY3Yy0uMTA1LS4zMS0uNDA3LS41NTItLjYxNy0uODI2bDQuODk2LTkuMDAyYy4xNjguMjkyLjM5LjU2NS40OTYuODc5YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDE2Ljc2OCAyMC4xMThjMi45MTYgOC43MyA1LjgxNCAxNy40NjcgOC43MjggMjYuMTk4LjExNi4zNDkuMzA4LjY3MS40OTEgMS4wNjJsLjY3LS43OC0uMTY3IDEwLjA1MnoiIGZpbGw9IiM0RkFBNDEiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTQzLjE1NSAzMi4yMjdjLjIxLjI3NC41MTEuNTE2LjYxNy44MjZhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMTYuNyAxOS44NjdjMi43NDYgOC4yMTEgNS40NjMgMTYuNDMzIDguMjEzIDI0LjY0MiAxLjY2MiA0Ljk2MSAzLjM2MiA5LjkxMSA1LjA2MiAxNC45MTNsLjc2NS0uMjg5LS4xNzEgMi40MjYtLjE1NS41NTljLS4yNjYgMi42NTYtLjQ5IDUuMzE4LS44MTQgNy45NjgtLjE2MyAxLjMyOC0uNTA5IDIuNjMyLS43NzIgMy45NDctLjE5OC0uMjg3LS40NzYtLjU0OC0uNTgzLS44NjYtNS40NjctMTYuMjk3LTEwLjkxOC0zMi42LTE2LjM3Ni00OC45YTM4ODguOTcyIDM4ODguOTcyIDAgMDAtNS4yNDItMTUuNTUxYy0uMDg5LS4yNjMtLjM0LS40NjktLjUxNi0uNzAybDMuMjcyLTguODR6IiBmaWxsPSIjNEFBNzNDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4yMDIgNzAuNzAybC0uNjcuNzhjLS4xODMtLjM5MS0uMzc1LS43MTQtLjQ5MS0xLjA2Mi0yLjkxMy04LjczMS01LjgxMi0xNy40NjgtOC43MjgtMjYuMTk4YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDAtNi43NjgtMjAuMTE4Yy0uMTA1LS4zMTQtLjMyNy0uNTg4LS40OTYtLjg3OWw2LjA1NS03Ljk2NWMuMTkxLjI1NS40NjMuNDgyLjU2Mi43NjkgMS42ODEgNC45MjEgMy4zNDcgOS44NDggNS4wMDMgMTQuNzc4IDEuNTQ3IDQuNjA0IDMuMDcxIDkuMjE1IDQuNjM2IDEzLjgxMy4xMDUuMzA4LjQ3LjUyNi43MTQuNzg2bC4wMTIgMS4wNDVjLjA1OCA4LjA4Mi4xMTUgMTYuMTY3LjE3MSAyNC4yNTF6IiBmaWxsPSIjNTdBRTQ3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMjEgNDUuNDA0Yy0uMjQ0LS4yNi0uNjA5LS40NzgtLjcxNC0uNzg2LTEuNTY1LTQuNTk4LTMuMDg5LTkuMjA5LTQuNjM2LTEzLjgxMy0xLjY1Ni00LjkzLTMuMzIyLTkuODU2LTUuMDAzLTE0Ljc3OC0uMDk5LS4yODctLjM3MS0uNTE0LS41NjItLjc2OSAxLjk2OS0xLjkyOCAzLjg3Ny0zLjkyNSA1LjkyNS01Ljc2NCAxLjgyMS0xLjYzNCAzLjI4NS0zLjM4NiAzLjM1Mi01Ljk2OC4wMDMtLjEwNy4wNTktLjIxNC4xNDUtLjUxNGwuNTE5IDEuMzA2Yy0uMDEzLjY2MS0uMDcyIDEuMzIyLS4wMjkgMS45NzkuMDc1IDEuMTQzLjI1OSAyLjI4LjMxMSAzLjQyMy4wOTYgMi4xMjcuMTQyIDQuMjU4LjE4NSA2LjM4OC4wNjkgMy40MjguMTMyIDYuODU2LjE3NSAxMC4yODUuMDY3IDUuNDc4LjExMSAxMC45NTYuMTggMTYuNDM0LjAwOC44NjEuMDk4IDEuNzE4LjE1MiAyLjU3N3oiIGZpbGw9IiM2MEIyNEYiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjU5OCAxMDcuMDg1Yy4yNjMtMS4zMTUuNjA5LTIuNjIuNzcyLTMuOTQ3LjMyNS0yLjY0OS41NDgtNS4zMTIuODE0LTcuOTY4bC4wNjYtLjAxLjA2Ni4wMTFhNDEuNDAyIDQxLjQwMiAwIDAwMS4zOTQgOS44MzhjLS4xNzYuMjMyLS40MjUuNDM5LS41MTguNzAxLS43MjcgMi4wNS0xLjQxMiA0LjExNi0yLjE0MyA2LjE2Ni0uMS4yOC0uMzc4LjQ5OC0uNTc0Ljc0NGwtLjc0Ny0yLjU2Ni44Ny0yLjk2OXoiIGZpbGw9IiNBOUFBODgiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjQ3NiAxMTIuNjIxYy4xOTYtLjI0Ni40NzUtLjQ2NC41NzQtLjc0NC43MzEtMi4wNSAxLjQxNy00LjExNSAyLjE0My02LjE2Ni4wOTMtLjI2Mi4zNDEtLjQ2OS41MTgtLjcwMWwxLjI1NSAyLjc1NGMtLjI0OC4zNTItLjU5LjY2OS0uNzI4IDEuMDYxbC0yLjQwNCA3LjA1OWMtLjA5OS4yODMtLjQzNy40ODMtLjY2My43MjJsLS42OTUtMy45ODV6IiBmaWxsPSIjQjZCNTk4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02My4xNzEgMTE2LjYwNWMuMjI3LS4yMzguNTY0LS40MzkuNjYzLS43MjJsMi40MDQtNy4wNTljLjEzNy0uMzkxLjQ4LS43MDkuNzI4LTEuMDYxbDEuMjE1IDEuMDM3Yy0uNTg3LjU4LS45MTMgMS4yNS0uNzE3IDIuMDk3bC0uMzY5IDEuMjA4Yy0uMTY4LjIwNy0uNDExLjM4Ny0uNDk0LjYyNC0uODM5IDIuNDAzLTEuNjQgNC44MTktMi40ODUgNy4yMjItLjEwNy4zMDUtLjQwNC41NDQtLjYxNC44MTItLjEwOS0xLjM4Ny0uMjItMi43NzEtLjMzMS00LjE1OHoiIGZpbGw9IiNDMkMxQTciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYzLjUwMyAxMjAuNzYzYy4yMDktLjI2OS41MDYtLjUwOC42MTQtLjgxMi44NDUtMi40MDIgMS42NDYtNC44MTggMi40ODUtNy4yMjIuMDgzLS4yMzYuMzI1LS40MTcuNDk0LS42MjRsLS41MDkgNS41NDVjLS4xMzYuMTU3LS4zMzMuMjk0LS4zOTguNDc3LS41NzUgMS42MTQtMS4xMTcgMy4yNC0xLjY5NCA0Ljg1NC0uMTE5LjMzMy0uMzQ3LjYyNy0uNTI1LjkzOC0uMTU4LS4yMDctLjQ0MS0uNDA3LS40NTQtLjYyMy0uMDUxLS44NDEtLjAxNi0xLjY4OC0uMDEzLTIuNTMzeiIgZmlsbD0iI0NFQ0RCNyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjMuOTY5IDEyMy45MTljLjE3OC0uMzEyLjQwNi0uNjA2LjUyNS0uOTM4LjU3OC0xLjYxMyAxLjExOS0zLjIzOSAxLjY5NC00Ljg1NC4wNjUtLjE4My4yNjMtLjMxOS4zOTgtLjQ3N2wuMDEyIDMuNjQtMS4yMTggMy4xMjQtMS40MTEtLjQ5NXoiIGZpbGw9IiNEQkRBQzciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY1LjM4IDEyNC40MTVsMS4yMTgtMy4xMjQuMjUxIDMuNjk2LTEuNDY5LS41NzJ6IiBmaWxsPSIjRUJFOURDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02Ny40NjQgMTEwLjg5OGMtLjE5Ni0uODQ3LjEyOS0xLjUxOC43MTctMi4wOTdsLjMzNy4yMy0xLjA1NCAxLjg2N3oiIGZpbGw9IiNDRUNEQjciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY0LjMxNiA5NS4xNzJsLS4wNjYtLjAxMS0uMDY2LjAxLjE1NS0uNTU5LS4wMjMuNTZ6IiBmaWxsPSIjNEZBQTQxIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"-643\" width=\"70\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-31\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"-710\" width=\"60\" height=\"60\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-33\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNODguMDM4IDQyLjgxMmMxLjYwNSA0LjY0MyAyLjc2MSA5LjM4MyAzLjE0MSAxNC4yOTYuNDcyIDYuMDk1LjI1NiAxMi4xNDctMS4wMjkgMTguMTQyLS4wMzUuMTY1LS4xMDkuMzItLjE2NC40OC0uNDAzLjAwMS0uODE0LS4wNDktMS4yMDguMDEyLTMuMzI5LjUyMy02LjY1NSAxLjA2NS05Ljk4MSAxLjYwNC0zLjQzOC41NTctNi44ODEgMS4wOTItMTAuMzEzIDEuNjg3LTEuMjE2LjIxLTIuNzIxLS4wNDEtMy4yMTIgMS42NDEtLjAxNC4wNDYtLjE1NC4wNTQtLjIzNS4wOGwuMTY2LTEwLjA1MS0uMTY5LTI0LjI1MiAxLjYwMi0uMjc1YzIuNjItLjQyOSA1LjI0LS44NjQgNy44NjItMS4yODEgMy4xMjktLjQ5NyA2LjI2MS0uOTggOS4zOTItMS40NjUgMS4zODEtLjIxNSAyLjc2NC0uNDEyIDQuMTQ4LS42MTh6IiBmaWxsPSIjNDM5OTM0IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02MS43MjkgMTEwLjA1NGMtMS42OS0xLjQ1My0zLjQzOS0yLjg0Mi01LjA1OS00LjM3LTguNzE3LTguMjIyLTE1LjA5My0xNy44OTktMTguMjMzLTI5LjU2Ni0uODY1LTMuMjExLTEuNDQyLTYuNDc0LTEuNjI3LTkuNzkyLS4xMy0yLjMyMi0uMzE4LTQuNjY1LS4xNTQtNi45NzUuNDM3LTYuMTQ0IDEuMzI1LTEyLjIyOSAzLjEyNy0xOC4xNDdsLjA5OS0uMTM4Yy4xNzUuMjMzLjQyNy40MzkuNTE2LjcwMiAxLjc1OSA1LjE4IDMuNTA1IDEwLjM2NCA1LjI0MiAxNS41NTEgNS40NTggMTYuMyAxMC45MDkgMzIuNjA0IDE2LjM3NiA0OC45LjEwNy4zMTguMzg0LjU3OS41ODMuODY2bC0uODcgMi45Njl6IiBmaWxsPSIjNDVBNTM4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik04OC4wMzggNDIuODEyYy0xLjM4NC4yMDYtMi43NjguNDAzLTQuMTQ5LjYxNi0zLjEzMS40ODUtNi4yNjMuOTY4LTkuMzkyIDEuNDY1LTIuNjIyLjQxNy01LjI0Mi44NTItNy44NjIgMS4yODFsLTEuNjAyLjI3NS0uMDEyLTEuMDQ1Yy0uMDUzLS44NTktLjE0NC0xLjcxNy0uMTU0LTIuNTc2LS4wNjktNS40NzgtLjExMi0xMC45NTYtLjE4LTE2LjQzNC0uMDQyLTMuNDI5LS4xMDUtNi44NTctLjE3NS0xMC4yODUtLjA0My0yLjEzLS4wODktNC4yNjEtLjE4NS02LjM4OC0uMDUyLTEuMTQzLS4yMzYtMi4yOC0uMzExLTMuNDIzLS4wNDItLjY1Ny4wMTYtMS4zMTkuMDI5LTEuOTc5LjgxNyAxLjU4MyAxLjYxNiAzLjE3OCAyLjQ1NiA0Ljc0OSAxLjMyNyAyLjQ4NCAzLjQ0MSA0LjMxNCA1LjM0NCA2LjMxMSA3LjUyMyA3Ljg5MiAxMi44NjQgMTcuMDY4IDE2LjE5MyAyNy40MzN6IiBmaWxsPSIjNDZBMDM3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMzYgODAuNzUzYy4wODEtLjAyNi4yMjItLjAzNC4yMzUtLjA4LjQ5MS0xLjY4MiAxLjk5Ni0xLjQzMSAzLjIxMi0xLjY0MSAzLjQzMi0uNTk0IDYuODc1LTEuMTMgMTAuMzEzLTEuNjg3IDMuMzI2LS41MzkgNi42NTItMS4wODEgOS45ODEtMS42MDQuMzk0LS4wNjIuODA1LS4wMTEgMS4yMDgtLjAxMi0uNjIyIDIuMjItMS4xMTIgNC40ODgtMS45MDEgNi42NDctLjg5NiAyLjQ0OS0xLjk4IDQuODM5LTMuMTMxIDcuMTgyYTQ5LjE0MiA0OS4xNDIgMCAwMS02LjM1MyA5Ljc2M2MtMS45MTkgMi4zMDgtNC4wNTggNC40NDEtNi4yMDIgNi41NDgtMS4xODUgMS4xNjUtMi41ODIgMi4xMTQtMy44ODIgMy4xNjFsLS4zMzctLjIzLTEuMjE0LTEuMDM4LTEuMjU2LTIuNzUzYTQxLjQwMiA0MS40MDIgMCAwMS0xLjM5NC05LjgzOGwuMDIzLS41NjEuMTcxLTIuNDI2Yy4wNTctLjgyOC4xMzMtMS42NTUuMTY4LTIuNDg1LjEyOS0yLjk4Mi4yNDEtNS45NjQuMzU5LTguOTQ2eiIgZmlsbD0iIzQwOTQzMyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjUuMDM2IDgwLjc1M2MtLjExOCAyLjk4Mi0uMjMgNS45NjQtLjM1NyA4Ljk0Ny0uMDM1LjgzLS4xMTEgMS42NTctLjE2OCAyLjQ4NWwtLjc2NS4yODljLTEuNjk5LTUuMDAyLTMuMzk5LTkuOTUxLTUuMDYyLTE0LjkxMy0yLjc1LTguMjA5LTUuNDY3LTE2LjQzMS04LjIxMy0yNC42NDJhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMC02LjctMTkuODY3Yy0uMTA1LS4zMS0uNDA3LS41NTItLjYxNy0uODI2bDQuODk2LTkuMDAyYy4xNjguMjkyLjM5LjU2NS40OTYuODc5YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDE2Ljc2OCAyMC4xMThjMi45MTYgOC43MyA1LjgxNCAxNy40NjcgOC43MjggMjYuMTk4LjExNi4zNDkuMzA4LjY3MS40OTEgMS4wNjJsLjY3LS43OC0uMTY3IDEwLjA1MnoiIGZpbGw9IiM0RkFBNDEiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTQzLjE1NSAzMi4yMjdjLjIxLjI3NC41MTEuNTE2LjYxNy44MjZhNDQ5OC44ODcgNDQ5OC44ODcgMCAwMTYuNyAxOS44NjdjMi43NDYgOC4yMTEgNS40NjMgMTYuNDMzIDguMjEzIDI0LjY0MiAxLjY2MiA0Ljk2MSAzLjM2MiA5LjkxMSA1LjA2MiAxNC45MTNsLjc2NS0uMjg5LS4xNzEgMi40MjYtLjE1NS41NTljLS4yNjYgMi42NTYtLjQ5IDUuMzE4LS44MTQgNy45NjgtLjE2MyAxLjMyOC0uNTA5IDIuNjMyLS43NzIgMy45NDctLjE5OC0uMjg3LS40NzYtLjU0OC0uNTgzLS44NjYtNS40NjctMTYuMjk3LTEwLjkxOC0zMi42LTE2LjM3Ni00OC45YTM4ODguOTcyIDM4ODguOTcyIDAgMDAtNS4yNDItMTUuNTUxYy0uMDg5LS4yNjMtLjM0LS40NjktLjUxNi0uNzAybDMuMjcyLTguODR6IiBmaWxsPSIjNEFBNzNDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4yMDIgNzAuNzAybC0uNjcuNzhjLS4xODMtLjM5MS0uMzc1LS43MTQtLjQ5MS0xLjA2Mi0yLjkxMy04LjczMS01LjgxMi0xNy40NjgtOC43MjgtMjYuMTk4YTYxNjcuNDc2IDYxNjcuNDc2IDAgMDAtNi43NjgtMjAuMTE4Yy0uMTA1LS4zMTQtLjMyNy0uNTg4LS40OTYtLjg3OWw2LjA1NS03Ljk2NWMuMTkxLjI1NS40NjMuNDgyLjU2Mi43NjkgMS42ODEgNC45MjEgMy4zNDcgOS44NDggNS4wMDMgMTQuNzc4IDEuNTQ3IDQuNjA0IDMuMDcxIDkuMjE1IDQuNjM2IDEzLjgxMy4xMDUuMzA4LjQ3LjUyNi43MTQuNzg2bC4wMTIgMS4wNDVjLjA1OCA4LjA4Mi4xMTUgMTYuMTY3LjE3MSAyNC4yNTF6IiBmaWxsPSIjNTdBRTQ3IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02NS4wMjEgNDUuNDA0Yy0uMjQ0LS4yNi0uNjA5LS40NzgtLjcxNC0uNzg2LTEuNTY1LTQuNTk4LTMuMDg5LTkuMjA5LTQuNjM2LTEzLjgxMy0xLjY1Ni00LjkzLTMuMzIyLTkuODU2LTUuMDAzLTE0Ljc3OC0uMDk5LS4yODctLjM3MS0uNTE0LS41NjItLjc2OSAxLjk2OS0xLjkyOCAzLjg3Ny0zLjkyNSA1LjkyNS01Ljc2NCAxLjgyMS0xLjYzNCAzLjI4NS0zLjM4NiAzLjM1Mi01Ljk2OC4wMDMtLjEwNy4wNTktLjIxNC4xNDUtLjUxNGwuNTE5IDEuMzA2Yy0uMDEzLjY2MS0uMDcyIDEuMzIyLS4wMjkgMS45NzkuMDc1IDEuMTQzLjI1OSAyLjI4LjMxMSAzLjQyMy4wOTYgMi4xMjcuMTQyIDQuMjU4LjE4NSA2LjM4OC4wNjkgMy40MjguMTMyIDYuODU2LjE3NSAxMC4yODUuMDY3IDUuNDc4LjExMSAxMC45NTYuMTggMTYuNDM0LjAwOC44NjEuMDk4IDEuNzE4LjE1MiAyLjU3N3oiIGZpbGw9IiM2MEIyNEYiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjU5OCAxMDcuMDg1Yy4yNjMtMS4zMTUuNjA5LTIuNjIuNzcyLTMuOTQ3LjMyNS0yLjY0OS41NDgtNS4zMTIuODE0LTcuOTY4bC4wNjYtLjAxLjA2Ni4wMTFhNDEuNDAyIDQxLjQwMiAwIDAwMS4zOTQgOS44MzhjLS4xNzYuMjMyLS40MjUuNDM5LS41MTguNzAxLS43MjcgMi4wNS0xLjQxMiA0LjExNi0yLjE0MyA2LjE2Ni0uMS4yOC0uMzc4LjQ5OC0uNTc0Ljc0NGwtLjc0Ny0yLjU2Ni44Ny0yLjk2OXoiIGZpbGw9IiNBOUFBODgiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYyLjQ3NiAxMTIuNjIxYy4xOTYtLjI0Ni40NzUtLjQ2NC41NzQtLjc0NC43MzEtMi4wNSAxLjQxNy00LjExNSAyLjE0My02LjE2Ni4wOTMtLjI2Mi4zNDEtLjQ2OS41MTgtLjcwMWwxLjI1NSAyLjc1NGMtLjI0OC4zNTItLjU5LjY2OS0uNzI4IDEuMDYxbC0yLjQwNCA3LjA1OWMtLjA5OS4yODMtLjQzNy40ODMtLjY2My43MjJsLS42OTUtMy45ODV6IiBmaWxsPSIjQjZCNTk4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02My4xNzEgMTE2LjYwNWMuMjI3LS4yMzguNTY0LS40MzkuNjYzLS43MjJsMi40MDQtNy4wNTljLjEzNy0uMzkxLjQ4LS43MDkuNzI4LTEuMDYxbDEuMjE1IDEuMDM3Yy0uNTg3LjU4LS45MTMgMS4yNS0uNzE3IDIuMDk3bC0uMzY5IDEuMjA4Yy0uMTY4LjIwNy0uNDExLjM4Ny0uNDk0LjYyNC0uODM5IDIuNDAzLTEuNjQgNC44MTktMi40ODUgNy4yMjItLjEwNy4zMDUtLjQwNC41NDQtLjYxNC44MTItLjEwOS0xLjM4Ny0uMjItMi43NzEtLjMzMS00LjE1OHoiIGZpbGw9IiNDMkMxQTciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTYzLjUwMyAxMjAuNzYzYy4yMDktLjI2OS41MDYtLjUwOC42MTQtLjgxMi44NDUtMi40MDIgMS42NDYtNC44MTggMi40ODUtNy4yMjIuMDgzLS4yMzYuMzI1LS40MTcuNDk0LS42MjRsLS41MDkgNS41NDVjLS4xMzYuMTU3LS4zMzMuMjk0LS4zOTguNDc3LS41NzUgMS42MTQtMS4xMTcgMy4yNC0xLjY5NCA0Ljg1NC0uMTE5LjMzMy0uMzQ3LjYyNy0uNTI1LjkzOC0uMTU4LS4yMDctLjQ0MS0uNDA3LS40NTQtLjYyMy0uMDUxLS44NDEtLjAxNi0xLjY4OC0uMDEzLTIuNTMzeiIgZmlsbD0iI0NFQ0RCNyIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNjMuOTY5IDEyMy45MTljLjE3OC0uMzEyLjQwNi0uNjA2LjUyNS0uOTM4LjU3OC0xLjYxMyAxLjExOS0zLjIzOSAxLjY5NC00Ljg1NC4wNjUtLjE4My4yNjMtLjMxOS4zOTgtLjQ3N2wuMDEyIDMuNjQtMS4yMTggMy4xMjQtMS40MTEtLjQ5NXoiIGZpbGw9IiNEQkRBQzciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY1LjM4IDEyNC40MTVsMS4yMTgtMy4xMjQuMjUxIDMuNjk2LTEuNDY5LS41NzJ6IiBmaWxsPSIjRUJFOURDIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik02Ny40NjQgMTEwLjg5OGMtLjE5Ni0uODQ3LjEyOS0xLjUxOC43MTctMi4wOTdsLjMzNy4yMy0xLjA1NCAxLjg2N3oiIGZpbGw9IiNDRUNEQjciIGNsaXAtcnVsZT0iZXZlbm9kZCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0iTTY0LjMxNiA5NS4xNzJsLS4wNjYtLjAxMS0uMDY2LjAxLjE1NS0uNTU5LS4wMjMuNTZ6IiBmaWxsPSIjNEZBQTQxIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1592\" y=\"-643\" width=\"70\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-47\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-34\" target=\"PG-S5D8SCmHSsYNVxMVk-28\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-48\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-34\" target=\"PG-S5D8SCmHSsYNVxMVk-29\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-12\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#D44E4E;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;entryX=0.253;entryY=0.114;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" target=\"PG-S5D8SCmHSsYNVxMVk-72\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"623\" y=\"-643\" as=\"sourcePoint\" />\n            <mxPoint x=\"820\" y=\"-200\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"623\" y=\"-480\" />\n              <mxPoint x=\"820\" y=\"-480\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-34\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/app_services/App_Services.svg;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"590\" y=\"-691\" width=\"68\" height=\"68\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-51\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-35\" target=\"PG-S5D8SCmHSsYNVxMVk-31\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-52\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-35\" target=\"PG-S5D8SCmHSsYNVxMVk-30\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-35\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/app_services/App_Services.svg;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"990\" y=\"-693\" width=\"68\" height=\"68\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-53\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-36\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1592.9999999999995\" y=\"-680\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-54\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-36\" target=\"PG-S5D8SCmHSsYNVxMVk-33\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-146\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#D44E4E;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-36\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"855\" y=\"-160\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1424\" y=\"-460\" />\n              <mxPoint x=\"855\" y=\"-460\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-151\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.25;entryDx=0;entryDy=0;shadow=0;strokeColor=#3587F3;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-36\" target=\"PG-S5D8SCmHSsYNVxMVk-73\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <Array as=\"points\">\n              <mxPoint x=\"1424\" y=\"-430\" />\n              <mxPoint x=\"500\" y=\"-430\" />\n              <mxPoint x=\"500\" y=\"-252\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-154\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.75;entryY=0;entryDx=0;entryDy=0;shadow=0;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1422.0000000000005\" y=\"-625\" as=\"sourcePoint\" />\n            <mxPoint x=\"1017\" y=\"-172\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1422\" y=\"-410\" />\n              <mxPoint x=\"1017\" y=\"-410\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-36\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/app_services/App_Services.svg;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1390\" y=\"-693\" width=\"68\" height=\"68\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-126\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=light-dark(#3587f3, #ededed);align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;exitX=0.049;exitY=0.824;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-34\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"390\" y=\"-220\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"490\" y=\"-635\" />\n              <mxPoint x=\"490\" y=\"-220\" />\n              <mxPoint x=\"390\" y=\"-220\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-37\" value=\"&lt;b&gt;&lt;font&gt;Api&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"590.0000000000001\" y=\"-623\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-38\" value=\"&lt;b&gt;&lt;font&gt;Api&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"990\" y=\"-625\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-39\" value=\"&lt;b&gt;&lt;font&gt;Api&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1388\" y=\"-625\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-44\" value=\"&lt;b&gt;Flight Service&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"573\" y=\"-750\" width=\"150\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-45\" value=\"&lt;b&gt;Passenger Service&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"972\" y=\"-749\" width=\"180\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-46\" value=\"&lt;b&gt;Booking Service&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1372\" y=\"-750\" width=\"160\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-57\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"855.5799999999999\" y=\"-1076\" as=\"sourcePoint\" />\n            <mxPoint x=\"701\" y=\"-760\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-59\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.563;entryY=-0.014;entryDx=0;entryDy=0;entryPerimeter=0;shadow=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"957.75\" y=\"-1076\" as=\"sourcePoint\" />\n            <mxPoint x=\"1527.3099999999995\" y=\"-759.0799999999999\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-72\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIG1lZXQiIHZpZXdCb3g9IjAgLTE4IDI1NiAyNTYiIGhlaWdodD0iODAwcHgiIHdpZHRoPSI4MDBweCI+PHBhdGggZmlsbD0iIzkxMjYyNiIgZD0iTTI0NS45NyAxNjguOTQzYy0xMy42NjIgNy4xMjEtODQuNDM0IDM2LjIyLTk5LjUwMSA0NC4wNzUtMTUuMDY3IDcuODU2LTIzLjQzNyA3Ljc4LTM1LjM0IDIuMDktMTEuOTAyLTUuNjktODcuMjE2LTM2LjExMi0xMDAuNzgzLTQyLjU5N0MzLjU2NiAxNjkuMjcxIDAgMTY2LjUzNSAwIDE2My45NTF2LTI1Ljg3NnM5OC4wNS0yMS4zNDUgMTEzLjg3OS0yNy4wMjRjMTUuODI4LTUuNjc5IDIxLjMyLTUuODg0IDM0Ljc5LS45NSAxMy40NzIgNC45MzYgOTQuMDE4IDE5LjQ2OCAxMDcuMzMxIDI0LjM0NGwtLjAwNiAyNS41MWMuMDAyIDIuNTU4LTMuMDcgNS4zNjQtMTAuMDI0IDguOTg4Ii8+PHBhdGggZmlsbD0iI0M2MzAyQiIgZD0iTTI0NS45NjUgMTQzLjIyYy0xMy42NjEgNy4xMTgtODQuNDMxIDM2LjIxOC05OS40OTggNDQuMDcyLTE1LjA2NiA3Ljg1Ny0yMy40MzYgNy43OC0zNS4zMzggMi4wOS0xMS45MDMtNS42ODYtODcuMjE0LTM2LjExMy0xMDAuNzgtNDIuNTk0LTEzLjU2Ni02LjQ4NS0xMy44NS0xMC45NDgtLjUyNC0xNi4xNjYgMTMuMzI2LTUuMjIgODguMjI0LTM0LjYwNSAxMDQuMDU1LTQwLjI4NCAxNS44MjgtNS42NzcgMjEuMzE5LTUuODg0IDM0Ljc4OS0uOTQ4IDEzLjQ3MSA0LjkzNCA4My44MTkgMzIuOTM1IDk3LjEzIDM3LjgxIDEzLjMxNiA0Ljg4MSAxMy44MjcgOC45LjE2NiAxNi4wMiIvPjxwYXRoIGZpbGw9IiM5MTI2MjYiIGQ9Ik0yNDUuOTcgMTI3LjA3NGMtMTMuNjYyIDcuMTIyLTg0LjQzNCAzNi4yMi05OS41MDEgNDQuMDc4LTE1LjA2NyA3Ljg1My0yMy40MzcgNy43NzctMzUuMzQgMi4wODctMTEuOTAzLTUuNjg3LTg3LjIxNi0zNi4xMTItMTAwLjc4My00Mi41OTdDMy41NjYgMTI3LjQwMiAwIDEyNC42NyAwIDEyMi4wODVWOTYuMjA2czk4LjA1LTIxLjM0NCAxMTMuODc5LTI3LjAyM2MxNS44MjgtNS42NzkgMjEuMzItNS44ODUgMzQuNzktLjk1QzE2Mi4xNDIgNzMuMTY4IDI0Mi42ODggODcuNjk3IDI1NiA5Mi41NzRsLS4wMDYgMjUuNTEzYy4wMDIgMi41NTctMy4wNyA1LjM2My0xMC4wMjQgOC45ODciLz48cGF0aCBmaWxsPSIjQzYzMDJCIiBkPSJNMjQ1Ljk2NSAxMDEuMzUxYy0xMy42NjEgNy4xMi04NC40MzEgMzYuMjE4LTk5LjQ5OCA0NC4wNzUtMTUuMDY2IDcuODU0LTIzLjQzNiA3Ljc3Ny0zNS4zMzggMi4wODctMTEuOTAzLTUuNjg2LTg3LjIxNC0zNi4xMTItMTAwLjc4LTQyLjU5NC0xMy41NjYtNi40ODMtMTMuODUtMTAuOTQ3LS41MjQtMTYuMTY3QzIzLjE1MSA4My41MzUgOTguMDUgNTQuMTQ4IDExMy44OCA0OC40N2MxNS44MjgtNS42NzggMjEuMzE5LTUuODg0IDM0Ljc4OS0uOTQ5IDEzLjQ3MSA0LjkzNCA4My44MTkgMzIuOTMzIDk3LjEzIDM3LjgxIDEzLjMxNiA0Ljg4IDEzLjgyNyA4LjkuMTY2IDE2LjAyIi8+PHBhdGggZmlsbD0iIzkxMjYyNiIgZD0iTTI0NS45NyA4My42NTNjLTEzLjY2MiA3LjEyLTg0LjQzNCAzNi4yMi05OS41MDEgNDQuMDc4LTE1LjA2NyA3Ljg1NC0yMy40MzcgNy43NzctMzUuMzQgMi4wODctMTEuOTAzLTUuNjg3LTg3LjIxNi0zNi4xMTMtMTAwLjc4My00Mi41OTVDMy41NjYgODMuOTggMCA4MS4yNDcgMCA3OC42NjV2LTI1Ljg4czk4LjA1LTIxLjM0MyAxMTMuODc5LTI3LjAyMWMxNS44MjgtNS42OCAyMS4zMi01Ljg4NCAzNC43OS0uOTVDMTYyLjE0MiAyOS43NDkgMjQyLjY4OCA0NC4yNzggMjU2IDQ5LjE1NWwtLjAwNiAyNS41MTJjLjAwMiAyLjU1NS0zLjA3IDUuMzYxLTEwLjAyNCA4Ljk4NiIvPjxwYXRoIGZpbGw9IiNDNjMwMkIiIGQ9Ik0yNDUuOTY1IDU3LjkzYy0xMy42NjEgNy4xMi04NC40MzEgMzYuMjItOTkuNDk4IDQ0LjA3NC0xNS4wNjYgNy44NTQtMjMuNDM2IDcuNzc3LTM1LjMzOCAyLjA5Qzk5LjIyNyA5OC40MDQgMjMuOTE1IDY3Ljk4IDEwLjM1IDYxLjQ5Ny0zLjIxNyA1NS4wMTUtMy41IDUwLjU1IDkuODI1IDQ1LjMzMSAyMy4xNTEgNDAuMTEzIDk4LjA1IDEwLjczIDExMy44OCA1LjA1YzE1LjgyOC01LjY3OSAyMS4zMTktNS44ODMgMzQuNzg5LS45NDggMTMuNDcxIDQuOTM1IDgzLjgxOSAzMi45MzQgOTcuMTMgMzcuODExIDEzLjMxNiA0Ljg3NiAxMy44MjcgOC44OTcuMTY2IDE2LjAxNyIvPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0xNTkuMjgzIDMyLjc1N2wtMjIuMDEgMi4yODUtNC45MjcgMTEuODU2LTcuOTU4LTEzLjIzLTI1LjQxNS0yLjI4NCAxOC45NjQtNi44MzktNS42OS0xMC40OTggMTcuNzU1IDYuOTQ0IDE2LjczOC01LjQ4LTQuNTI0IDEwLjg1NSAxNy4wNjcgNi4zOTFNMTMxLjAzMiA5MC4yNzVMODkuOTU1IDczLjIzOGw1OC44Ni05LjAzNS0xNy43ODMgMjYuMDcyTTc0LjA4MiAzOS4zNDdjMTcuMzc1IDAgMzEuNDYgNS40NiAzMS40NiAxMi4xOTQgMCA2LjczNi0xNC4wODUgMTIuMTk1LTMxLjQ2IDEyLjE5NXMtMzEuNDYtNS40Ni0zMS40Ni0xMi4xOTVjMC02LjczNCAxNC4wODUtMTIuMTk0IDMxLjQ2LTEyLjE5NCIvPjxwYXRoIGZpbGw9IiM2MjFCMUMiIGQ9Ik0xODUuMjk1IDM1Ljk5OGwzNC44MzYgMTMuNzY2LTM0LjgwNiAxMy43NTMtLjAzLTI3LjUyIi8+PHBhdGggZmlsbD0iIzlBMjkyOCIgZD0iTTE0Ni43NTUgNTEuMjQzbDM4LjU0LTE1LjI0NS4wMyAyNy41MTktMy43NzkgMS40NzgtMzQuNzkxLTEzLjc1MiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"800\" y=\"-169\" width=\"79\" height=\"79\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-74\" value=\"&lt;b&gt;&lt;font&gt;Mongo&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"395\" y=\"-576\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-75\" value=\"&lt;b&gt;&lt;font&gt;Postgres&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"395\" y=\"-748\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-77\" value=\"&lt;b&gt;&lt;font&gt;Postgres&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"785\" y=\"-748\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-78\" value=\"&lt;b&gt;&lt;font&gt;Postgres&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1175\" y=\"-748\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-79\" value=\"&lt;b&gt;&lt;font&gt;EventStore&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1591\" y=\"-750\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-80\" value=\"&lt;b&gt;&lt;font&gt;Mongo&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"784.58\" y=\"-579\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-81\" value=\"&lt;b&gt;&lt;font&gt;Mongo&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"-579\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-82\" value=\"&lt;b&gt;&lt;font&gt;Mongo&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1594\" y=\"-576\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-121\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;dashed=1;dashPattern=8 8;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-84\" target=\"PG-S5D8SCmHSsYNVxMVk-95\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-84\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/storage/Data_Box_Edge.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"133\" y=\"-306\" width=\"72.58\" height=\"52\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-122\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-85\" target=\"PG-S5D8SCmHSsYNVxMVk-95\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-85\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/storage/Azure_Stack_Edge.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"131.16999999999996\" y=\"-154\" width=\"73.67\" height=\"52\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-123\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-86\" target=\"PG-S5D8SCmHSsYNVxMVk-95\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-86\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/storage/StorSimple_Device_Managers.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"129.72000000000003\" y=\"6\" width=\"76.56\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-88\" value=\"\" style=\"image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/Notification_Hubs.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"110\" y=\"-364\" width=\"30\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-89\" value=\"&lt;b&gt;MESSAGE PROCESSOR&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=15;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"151.34000000000003\" y=\"-364\" width=\"188\" height=\"20\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-91\" value=\"&lt;b&gt;&lt;font&gt;Outbox Processor&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"98\" y=\"-84\" width=\"145\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-92\" value=\"&lt;b&gt;&lt;font&gt;Internal Command Processor&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"95\" y=\"86\" width=\"175\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-95\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuODA5IDkyLjExMmMuNzg1LTYuNTMzLjU1LTcuNDkyIDUuNDE2LTYuNDMzbDEuMjM1LjEwOGMzLjc0Mi4xNyA4LjYzNy0uNjAyIDExLjUxMy0xLjkzOCA2LjE5MS0yLjg3MyA5Ljg2MS03LjY2OCAzLjc1OC02LjQwOS0xMy45MjQgMi44NzMtMTQuODgxLTEuODQyLTE0Ljg4MS0xLjg0MiAxNC43MDMtMjEuODE1IDIwLjg0OS00OS41MDggMTUuNTQzLTU2LjI4Ny0xNC40Ny0xOC40ODktMzkuNTE3LTkuNzQ2LTM5LjkzNi05LjUybC0uMTM0LjAyNWMtMi43NTEtLjU3MS01LjgzLS45MTItOS4yODktLjk2OC02LjMwMS0uMTA0LTExLjA4MiAxLjY1Mi0xNC43MDkgNC40MDIgMCAwLTQ0LjY4My0xOC40MDktNDIuNjA0IDIzLjE1MS40NDIgOC44NDEgMTIuNjcyIDY2Ljg5OCAyNy4yNiA0OS4zNjIgNS4zMzItNi40MTIgMTAuNDg0LTExLjgzNCAxMC40ODQtMTEuODM0IDIuNTU4IDEuNjk5IDUuNjIyIDIuNTY3IDguODM0IDIuMjU1bC4yNDktLjIxMmMtLjA3OC43OTYtLjA0NCAxLjU3NS4wOTkgMi40OTctMy43NTcgNC4xOTktMi42NTMgNC45MzYtMTAuMTY2IDYuNDgyLTcuNjAyIDEuNTY2LTMuMTM2IDQuMzU1LS4yMjEgNS4wODQgMy41MzUuODg0IDExLjcxMiAyLjEzNiAxNy4yMzgtNS41OThsLS4yMi44ODJjMS40NzQgMS4xOCAxLjM3NSA4LjQ3NyAxLjU4MyAxMy42OS4yMDkgNS4yMTQuNTU4IDEwLjA3OSAxLjYyMSAxMi45NDggMS4wNjMgMi44NjggMi4zMTcgMTAuMjU2IDEyLjE5MSA4LjE0IDguMjUyLTEuNzY0IDE0LjU2MS00LjMwOSAxNS4xMzYtMjcuOTg1Ii8+PHBhdGggZD0iTTc1LjQ1OCAxMjUuMjU2Yy00LjM2NyAwLTcuMjExLTEuNjg5LTguOTM4LTMuMzItMi42MDctMi40Ni0zLjY0MS01LjYyOS00LjI1OS03LjUyMmwtLjI2Ny0uNzljLTEuMjQ0LTMuMzU4LTEuNjY2LTguMTkzLTEuOTE2LTE0LjQxOS0uMDM4LS45MzUtLjA2NC0xLjg5OC0uMDkzLTIuOTE5LS4wMjEtLjc0Ny0uMDQ3LTEuNjg0LS4wODUtMi42NjRhMTguOCAxOC44IDAgMDEtNC45NjIgMS41NjhjLTMuMDc5LjUyNi02LjM4OS4zNTYtOS44NC0uNTA3LTIuNDM1LS42MDktNC45NjUtMS44NzEtNi40MDctMy44Mi00LjIwMyAzLjY4MS04LjIxMiAzLjE4Mi0xMC4zOTYgMi40NTMtMy44NTMtMS4yODUtNy4zMDEtNC44OTYtMTAuNTQyLTExLjAzNy0yLjMwOS00LjM3NS00LjU0Mi0xMC4wNzUtNi42MzgtMTYuOTQzLTMuNjUtMTEuOTYtNS45NjktMjQuNTU3LTYuMTc1LTI4LjY5M0M0LjI5MiAyMy42OTggNy43NzcgMTQuNDQgMTUuMjk2IDkuMTI5IDI3LjE1Ny43NTEgNDUuMTI4IDUuNjc4IDUxLjY4IDcuOTE1YzQuNDAyLTIuNjUzIDkuNTgxLTMuOTQ0IDE1LjQzMy0zLjg1MSAzLjE0My4wNTEgNi4xMzYuMzI3IDguOTE2LjgyMyAyLjktLjkxMiA4LjYyOC0yLjIyMSAxNS4xODUtMi4xMzkgMTIuMDgxLjE0NCAyMi4wOTIgNC44NTIgMjguOTQ5IDEzLjYxNSA0Ljg5NCA2LjI1MiAyLjQ3NCAxOS4zODEuNTk3IDI2LjY1MS0yLjY0MiAxMC4yMjYtNy4yNzEgMjEuMTAyLTEyLjk1NyAzMC41NyAxLjU0NC4wMTEgMy43ODEtLjE3NCA2Ljk2MS0uODMxIDYuMjc0LTEuMjk1IDguMTA5IDIuMDY5IDguNjA3IDMuNTc1IDEuOTk1IDYuMDQyLTYuNjc3IDEwLjYwOC05LjM4MiAxMS44NjQtMy40NjYgMS42MDktOS4xMTcgMi41ODktMTMuNzQ1IDIuMzc3bC0uMjAyLS4wMTMtMS4yMTYtLjEwNy0uMTIgMS4wMTQtLjExNi45OTFjLS4zMTEgMTEuOTk5LTIuMDI1IDE5LjU5OC01LjU1MiAyNC42MTktMy42OTcgNS4yNjQtOC44MzUgNi43MzktMTMuMzYxIDcuNzA5LTEuNTQ0LjMzLTIuOTQ3LjQ3NC00LjIxOS40NzR6bS05LjE5LTQzLjY3MWMyLjgxOSAyLjI1NiAzLjA2NiA2LjUwMSAzLjI4NyAxNC40MzQuMDI4Ljk5LjA1NCAxLjkyNy4wODkgMi44MDIuMTA2IDIuNjUuMzU1IDguODU1IDEuMzI3IDExLjQ3Ny4xMzcuMzcxLjI2Ljc0Ny4zOSAxLjE0NiAxLjA4MyAzLjMxNiAxLjYyNiA0Ljk3OSA2LjMwOSAzLjk3OCAzLjkzMS0uODQzIDUuOTUyLTEuNTk5IDcuNTM0LTMuODUxIDIuMjk5LTMuMjc0IDMuNTg1LTkuODYgMy44MjEtMTkuNTc1bDQuNzgzLjExNi00Ljc1LS41Ny4xNC0xLjE4NmMuNDU1LTMuOTEuNzgzLTYuNzM0IDMuMzk2LTguNjAyIDIuMDk3LTEuNDk4IDQuNDg2LTEuMzUzIDYuMzg5LTEuMDEtMi4wOTEtMS41OC0yLjY2OS0zLjQzMy0yLjgyMy00LjE5M2wtLjM5OS0xLjk2NSAxLjEyMS0xLjY2M2M2LjQ1Ny05LjU4IDExLjc4MS0yMS4zNTQgMTQuNjA5LTMyLjMwNCAyLjkwNi0xMS4yNTEgMi4wMi0xNy4yMjYgMS4xMzQtMTguMzU2LTExLjcyOS0xNC45ODctMzIuMDY4LTguNzk5LTM0LjE5Mi04LjA5N2wtLjM1OS4xOTQtMS44LjMzNS0uOTIyLS4xOTFjLTIuNTQyLS41MjgtNS4zNjYtLjgyLTguMzkzLS44NjktNC43NTYtLjA4LTguNTkzIDEuMDQ0LTExLjczOSAzLjQzMWwtMi4xODMgMS42NTUtMi41MzMtMS4wNDNjLTUuNDEyLTIuMjEzLTIxLjMwOC02LjY2Mi0yOS42OTYtLjcyMS00LjY1NiAzLjI5OC02Ljc3NyA5Ljc2LTYuMzA1IDE5LjIwNy4xNTYgMy4xMTkgMi4yNzUgMTQuOTI2IDUuNzcxIDI2LjM3NyA0LjgzMSAxNS44MjUgOS4yMjEgMjEuMDgyIDExLjA1NCAyMS42OTMuMzIuMTA4IDEuMTUtLjUzNyAxLjk3Ni0xLjUyOWEyNzAuNzA4IDI3MC43MDggMCAwMTEwLjY5NC0xMi4wN2wyLjc3LTIuOTE1IDMuMzQ5IDIuMjI1YzEuMzUuODk3IDIuODM5IDEuNDA2IDQuMzY4IDEuNTAybDcuOTg3LTYuODEyLTEuMTU3IDExLjgwOGMtLjAyNi4yNjUtLjAzOS42MjYuMDY1IDEuMjk2bC4zNDggMi4yMzgtMS41MSAxLjY4OC0uMTc0LjE5NiA0LjM4OCAyLjAyNSAxLjgzNi0yLjMwMXoiLz48cGF0aCBkPSJNMTE1LjczMSA3Ny40NGMtMTMuOTI1IDIuODczLTE0Ljg4Mi0xLjg0Mi0xNC44ODItMS44NDIgMTQuNzAzLTIxLjgxNiAyMC44NDktNDkuNTEgMTUuNTQ1LTU2LjI4N0MxMDEuOTI0LjgyMyA3Ni44NzUgOS41NjYgNzYuNDU3IDkuNzkzbC0uMTM1LjAyNGMtMi43NTEtLjU3MS01LjgzLS45MTEtOS4yOTEtLjk2Ny02LjMwMS0uMTAzLTExLjA4IDEuNjUyLTE0LjcwNyA0LjQwMiAwIDAtNDQuNjg0LTE4LjQwOC00Mi42MDYgMjMuMTUxLjQ0MiA4Ljg0MiAxMi42NzIgNjYuODk5IDI3LjI2IDQ5LjM2MyA1LjMzMi02LjQxMiAxMC40ODMtMTEuODM0IDEwLjQ4My0xMS44MzQgMi41NTkgMS42OTkgNS42MjIgMi41NjcgOC44MzMgMi4yNTVsLjI1LS4yMTJjLS4wNzguNzk2LS4wNDIgMS41NzUuMSAyLjQ5Ny0zLjc1OCA0LjE5OS0yLjY1NCA0LjkzNi0xMC4xNjcgNi40ODItNy42MDIgMS41NjYtMy4xMzYgNC4zNTUtLjIyIDUuMDg0IDMuNTM0Ljg4NCAxMS43MTIgMi4xMzYgMTcuMjM3LTUuNTk4bC0uMjIxLjg4MmMxLjQ3MyAxLjE4IDIuNTA3IDcuNjcyIDIuMzM0IDEzLjU1Ny0uMTc0IDUuODg1LS4yOSA5LjkyNi44NzEgMTMuMDgyIDEuMTYgMy4xNTYgMi4zMTYgMTAuMjU2IDEyLjE5MiA4LjE0IDguMjUyLTEuNzY4IDEyLjUyOC02LjM1MSAxMy4xMjQtMTMuOTk1LjQyMi01LjQzNSAxLjM3Ny00LjYzMSAxLjQzOC05LjQ5bC43NjctMi4zYy44ODQtNy4zNjcuMTQtOS43NDMgNS4yMjUtOC42MzhsMS4yMzUuMTA4YzMuNzQyLjE3IDguNjM5LS42MDIgMTEuNTE0LTEuOTM4IDYuMTktMi44NzEgOS44NjEtNy42NjcgMy43NTgtNi40MDh6IiBmaWxsPSIjMzM2NzkxIi8+PHBhdGggZD0iTTc1Ljk1NyAxMjIuMzA3Yy04LjIzMiAwLTEwLjg0LTYuNTE5LTExLjkwNy05LjE4NS0xLjU2Mi0zLjkwNy0xLjg5OS0xOS4wNjktMS41NTEtMzEuNTAzYTEuNTkgMS41OSAwIDAxMS42NC0xLjU1IDEuNTk0IDEuNTk0IDAgMDExLjU1IDEuNjM5Yy0uNDAxIDE0LjM0MS4xNjggMjcuMzM3IDEuMzI0IDMwLjIyOSAxLjgwNCA0LjUwOSA0LjU0IDguNDUzIDEyLjI3NSA2Ljc5NiA3LjM0My0xLjU3NSAxMC4wOTMtNC4zNTkgMTEuMzE4LTExLjQ2Ljk0LTUuNDQ5IDIuNzk5LTIwLjk1MSAzLjAyOC0yNC4wMWExLjU5MyAxLjU5MyAwIDAxMS43MS0xLjQ3MiAxLjU5NyAxLjU5NyAwIDAxMS40NzIgMS43MWMtLjIzOSAzLjE4NS0yLjA4OSAxOC42NTctMy4wNjUgMjQuMzE1LTEuNDQ2IDguMzg3LTUuMTg1IDEyLjE5MS0xMy43OTQgMTQuMDM3LTEuNDYzLjMxMy0yLjc5Mi40NTMtNCAuNDU0ek0zMS4zMjEgOTAuNDY2YTYuNzEgNi43MSAwIDAxLTIuMTE2LS4zNWMtNS4zNDctMS43ODQtMTAuNDQtMTAuNDkyLTE1LjEzOC0yNS44ODUtMy41NzYtMTEuNzE3LTUuODQyLTIzLjk0Ny02LjA0MS0yNy45MjItLjU4OS0xMS43ODQgMi40NDUtMjAuMTIxIDkuMDItMjQuNzc4IDEzLjAwNy05LjIxNiAzNC44ODgtLjQ0IDM1LjgxMy0uMDYyYTEuNTk2IDEuNTk2IDAgMDEtMS4yMDcgMi45NTVjLS4yMTEtLjA4Ni0yMS4xOTMtOC40OTItMzIuNzY4LS4yODUtNS42MjIgMy45ODYtOC4yMDMgMTEuMzkyLTcuNjcyIDIyLjAxMS4xNjcgMy4zNDkgMi4yODQgMTUuMjg1IDUuOTA2IDI3LjE0OSA0LjE5NCAxMy43NDIgOC45NjcgMjIuNDEzIDEzLjA5NiAyMy43OS42NDguMjE2IDIuNjIuODczIDUuNDM5LTIuNTE3QTI0NS4yNzIgMjQ1LjI3MiAwIDAxNDUuODggNzMuMDQ2YTEuNTk2IDEuNTk2IDAgMDEyLjMwNCAyLjIwOGMtLjA0OC4wNS00Ljg0NyA1LjA2Ny0xMC4wNzcgMTEuMzU5LTIuNDc3IDIuOTc5LTQuODUxIDMuODUzLTYuNzg2IDMuODUzem02OS40MjktMTMuNDQ1YTEuNTk2IDEuNTk2IDAgMDEtMS4zMjItMi40ODdjMTQuODYzLTIyLjA1NSAyMC4wOC00OC43MDQgMTUuNjEyLTU0LjQxNC01LjYyNC03LjE4Ni0xMy41NjUtMTAuOTM5LTIzLjYwNC0xMS4xNTYtNy40MzMtLjE2LTEzLjM0MSAxLjczOC0xNC4zMDcgMi4wNjlsLS4yNDMuMDk5Yy0uOTcxLjMwNS0xLjcxNi0uMjI3LTEuOTk3LS44NDlhMS42IDEuNiAwIDAxLjYzMS0yLjAyNWMuMDQ2LS4wMjcuMTkyLS4wODkuNDI5LS4xNzZsLS4wMjEuMDA2LjAyMS0uMDA3YzEuNjQxLS42MDEgNy42MzktMi40IDE1LjA2OC0yLjMxNSAxMS4xMDguMTE4IDIwLjI4NCA0LjQwMSAyNi41MzQgMTIuMzg4IDIuOTU3IDMuNzc5IDIuOTY0IDEyLjQ4NS4wMTkgMjMuODg3LTMuMDAyIDExLjYyNS04LjY1MSAyNC4xMTgtMTUuNDk3IDM0LjI3Ny0uMzA2LjQ1Ny0uODEuNzAzLTEuMzIzLjcwM3ptLjc2IDEwLjIxYy0yLjUzOCAwLTQuODEzLS4zNTgtNi4xNzUtMS4xNzQtMS40LS44MzktMS42NjctMS45NzktMS43MDItMi41ODQtLjM4Mi02LjcxIDMuMzItNy44NzggNS4yMDgtOC40MTEtLjI2My0uMzk4LS42MzctLjg2Ni0xLjAyNC0xLjM0OS0xLjEwMS0xLjM3Ni0yLjYwOS0zLjI2LTMuNzcxLTYuMDc4LS4xODItLjQ0LS43NTItMS40NjMtMS40MTItMi42NDgtMy41NzktNi40MTgtMTEuMDI2LTE5Ljc3My02LjI0Mi0yNi42MTIgMi4yMTQtMy4xNjUgNi42MjMtNC40MTEgMTMuMTE5LTMuNzE2Qzk3LjYgMjguODM3IDg4LjUgMTAuNjI1IDY2LjkwNyAxMC4yNzFjLTYuNDk0LS4xMDgtMTEuODIgMS44ODktMTUuODIyIDUuOTMtOC45NiA5LjA0OS04LjYzNiAyNS40MjItOC42MzEgMjUuNTg2YTEuNTk1IDEuNTk1IDAgMTEtMy4xOS4wODRjLS4wMi0uNzI3LS4zNTQtMTcuOTA5IDkuNTU0LTI3LjkxNkM1My40NTUgOS4yNzIgNTkuNTU5IDYuOTYgNjYuOTYgNy4wODFjMTMuODE0LjIyNyAyMi43MDYgNy4yNSAyNy43MzIgMTMuMTAxIDUuNDc5IDYuMzc3IDguMTY1IDEzLjQxMSA4LjM4NiAxNS43NTkuMTY1IDEuNzQ2LTEuMDg4IDIuMDk1LTEuMzQxIDIuMTQ3bC0uNTc2LjAxM2MtNi4zNzUtMS4wMjEtMTAuNDY1LS4zMTItMTIuMTU2IDIuMTA0LTMuNjM5IDUuMjAxIDMuNDA2IDE3LjgzNCA2LjQxNCAyMy4yMjkuNzY4IDEuMzc2IDEuMzIyIDIuMzcxIDEuNTc2IDIuOTg1Ljk4OCAyLjM5NiAyLjI3NyA0LjAwNiAzLjMxMiA1LjMuOTExIDEuMTM4IDEuNyAyLjEyNSAxLjk4MiAzLjI4My4xMzEuMjMgMS45OSAyLjk4IDEzLjAyMS43MDMgMi43NjUtLjU3IDQuNDIzLS4wODMgNC45MyAxLjQ1Ljk5NyAzLjAxNS00LjU5NyA2LjUzMi03LjY5NCA3Ljk3LTIuNzc1IDEuMjktNy4yMDQgMi4xMDYtMTEuMDM2IDIuMTA2em0tNC42OTYtNC4wMjFjLjM1LjM1MyAyLjEwMS45NjIgNS43MjcuODA2IDMuMjI0LS4xMzggNi42MjQtLjgzOSA4LjY2NC0xLjc4NiAyLjYwOS0xLjIxMiA0LjM1MS0yLjU2NyA1LjI1My0zLjQ5MmwtLjUuMDkyYy03LjA1MyAxLjQ1Ni0xMi4wNDIgMS4yNjItMTQuODI4LS41NzdhNi4xNjIgNi4xNjIgMCAwMS0uNTQtLjQwMWMtLjMwMi4xMTktLjU4MS4xOTctLjc4LjI1My0xLjU4LjQ0My0zLjIxNC45MDItMi45OTYgNS4xMDV6bS00NS41NjIgOC45MTVjLTEuNzUyIDAtMy41OTYtLjIzOS01LjQ3OS0uNzEtMS45NTEtLjQ4OC01LjI0LTEuOTU3LTUuMTktNC4zNy4wNTctMi43MDcgMy45OTQtMy41MTkgNS40NzYtMy44MjQgNS4zNTQtMS4xMDMgNS43MDMtMS41NDUgNy4zNzYtMy42Ny40ODgtLjYxOSAxLjA5NS0xLjM5IDEuOTIzLTIuMzE0IDEuMjI5LTEuMzc2IDIuNTcyLTIuMDczIDMuOTkyLTIuMDczLjk4OSAwIDEuOC4zMzUgMi4zMzYuNTU4IDEuNzA4LjcwOCAzLjEzMyAyLjQyIDMuNzE5IDQuNDY3LjUyOSAxLjg0Ny4yNzYgMy42MjUtLjcxIDUuMDA2LTMuMjM3IDQuNTMzLTcuODg2IDYuOTMtMTMuNDQzIDYuOTN6bS03LjIyMi00Ljk0M2MuNDgxLjM3MiAxLjQ0NS44NjkgMi41MTggMS4xMzcgMS42MzEuNDA4IDMuMjEzLjYxNSA0LjcwNS42MTUgNC41NDYgMCA4LjE5Ni0xLjg4MiAxMC44NDctNS41OTQuNTUzLS43NzQuMzg3LTEuNzU3LjIzOS0yLjI3NC0uMzEtMS4wODMtMS4wOC0yLjA2OC0xLjg3My0yLjM5Ny0uNDMtLjE3OC0uNzg3LS4zMTQtMS4xMTUtLjMxNC0uMTc2IDAtLjcxMiAwLTEuNjE0IDEuMDA5YTQxLjE0NiA0MS4xNDYgMCAwMC0xLjc5NCAyLjE2MmMtMi4wODQgMi42NDYtMy4wMzkgMy41NDQtOS4yMzkgNC44MjEtMS41MTMuMzEtMi4yODkuNjI2LTIuNjc0LjgzNXptMTIuMjY5LTcuMzZhMS41OTYgMS41OTYgMCAwMS0xLjU3NS0xLjM1NCA4LjIxOCA4LjIxOCAwIDAxLS4wOC0uNzk5Yy00LjA2NC0uMDc2LTcuOTg1LTEuODItMTAuOTYyLTQuOTI2LTMuNzY0LTMuOTI3LTUuNDc3LTkuMzY4LTQuNjk5LTE0LjkyNy44NDUtNi4wMzcuNTI5LTExLjM2Ni4zNTktMTQuMjI5LS4wNDctLjc5Ni0uMDgxLTEuMzcxLS4wNzktMS43NjkuMDAzLS41MDUuMDEzLTEuODQ0IDQuNDg5LTQuMTEzIDEuNTkyLS44MDcgNC43ODQtMi4yMTUgOC4yNzEtMi41NzYgNS43NzctLjU5NyA5LjU4NSAxLjk3NiAxMC43MjUgNy4yNDYgMy4wNzcgMTQuMjI4LjI0NCAyMC41MjEtMS44MjUgMjUuMTE3LS4zODUuODU2LS43NDkgMS42NjQtMS4wNCAyLjQ0N2wtLjI1Ny42OWMtMS4wOTMgMi45MzEtMi4wMzggNS40NjMtMS43NDggNy4zNTRhMS41OTUgMS41OTUgMCAwMS0xLjMzNSAxLjgxOWwtLjI0NC4wMnpNNDIuNDY0IDQyLjI2bC4wNjIgMS4xMzljLjE3NiAyLjk3NC41MDQgOC41MDgtLjM4NCAxNC44Ni0uNjQxIDQuNTg1Ljc1OSA5LjA2IDMuODQzIDEyLjI3NiAyLjQzNyAyLjU0MiA1LjY0NCAzLjk0NSA4Ljk0IDMuOTQ1aC4wNjhjLjM2OS0xLjU1NS45ODItMy4xOTcgMS42NDItNC45NjZsLjI1NS0uNjg2Yy4zMjktLjg4NC43MTQtMS43NCAxLjEyMi0yLjY0NiAxLjk5MS00LjQyNCA0LjQ3LTkuOTMxIDEuNjE1LTIzLjEzMi0uNTY1LTIuNjE1LTEuOTM2LTQuMTI4LTQuMTg5LTQuNjI3LTQuNjI4LTEuMDIyLTExLjUyNSAyLjQ1OS0xMi45NzQgMy44Mzd6bTkuNjMtLjY3N2MtLjA4LjU2NCAxLjAzMyAyLjA3IDIuNDg1IDIuMjcxIDEuNDQ5LjIwMyAyLjY4OS0uOTc1IDIuNzY4LTEuNTM5LjA3OS0uNTY0LTEuMDMzLTEuMTg2LTIuNDg1LTEuMzg4LTEuNDUxLS4yMDItMi42OTEuMDkyLTIuNzY4LjY1NnptMi44MTggMi44MjZsLS40MDctLjAyOGMtLjktLjEyNS0xLjgxLS42OTItMi40MzMtMS41MTgtLjIxOS0uMjktLjU3Ni0uODUyLS41MDUtMS4zNTQuMTAxLS43MzYuOTk5LTEuMTc3IDIuNC0xLjE3Ny4zMTMgMCAuNjM5LjAyMy45NjcuMDY5Ljc2Ni4xMDYgMS40NzcuMzI3IDIuMDAyLjYyLjkxLjUwOC45NzcgMS4wNzUuOTM2IDEuMzY4LS4xMTIuODEzLTEuNDA1IDIuMDItMi45NiAyLjAyem0tMi4yODktMi43MzJjLjA0NS4zNDguOTA3IDEuNDk2IDIuMDI5IDEuNjUxbC4yNjEuMDE4YzEuMDM2IDAgMS44MS0uODE1IDEuOTAxLTEuMDgyLS4wOTYtLjE4Mi0uNzYyLS42MzQtMi4wMjUtLjgxYTUuODIzIDUuODIzIDAgMDAtLjgyMS0uMDU5Yy0uODEyIDAtMS4yNDMuMTgzLTEuMzQ1LjI4MnptNDMuNjA1LTEuMjQ1Yy4wNzkuNTY0LTEuMDMzIDIuMDctMi40ODQgMi4yNzItMS40NS4yMDItMi42OTEtLjk3NS0yLjc3MS0xLjUzOS0uMDc2LS41NjQgMS4wMzYtMS4xODcgMi40ODYtMS4zODggMS40NS0uMjAzIDIuNjg5LjA5MiAyLjc2OS42NTV6bS0yLjgxOSAyLjU2Yy0xLjM5NiAwLTIuNjAxLTEuMDg2LTIuNy0xLjc5MS0uMTE1LS44NDYgMS4yNzgtMS40ODkgMi43MTItMS42ODguMzE2LS4wNDQuNjI5LS4wNjYuOTMtLjA2NiAxLjIzOCAwIDIuMDU4LjM2MyAyLjE0Ljk0OS4wNTMuMzc5LS4yMzguOTY0LS43MzkgMS40OTItLjMzMS4zNDctMS4wMjYuOTQ4LTEuOTczIDEuMDc5bC0uMzcuMDI1em0uOTQzLTMuMDEzYy0uMjc2IDAtLjU2NC4wMjEtLjg1Ni4wNjEtMS40NDEuMjAxLTIuMzAxLjc3OS0yLjI1OSAxLjA4OS4wNDguMzQxLjk2OCAxLjMzMiAyLjE3MyAxLjMzMmwuMjk3LS4wMjFjLjc4Ny0uMTA5IDEuMzc4LS42MjMgMS42Ni0uOTE5LjQ0My0uNDY1LjYxOS0uOTAzLjU5OC0xLjA1Mi0uMDI4LS4xOTgtLjU2LS40OS0xLjYxMy0uNDl6bTMuOTY1IDMyLjg0M2ExLjU5NCAxLjU5NCAwIDAxLTEuMzI0LTIuNDgzYzMuMzk4LTUuMDc1IDIuNzc2LTEwLjI1IDIuMTc1LTE1LjI1NS0uMjU3LTIuMTMyLS41MjEtNC4zMzctLjQ1My02LjQ1My4wNy0yLjE3Ny4zNDctMy45NzMuNjE0LTUuNzEuMzE3LTIuMDU4LjYxNy00LjAwMi40OTMtNi4zMWExLjU5NSAxLjU5NSAwIDExMy4xODYtLjE3MmMuMTQyIDIuNjM4LS4xOTcgNC44MzgtLjUyNSA2Ljk2Ny0uMjUzIDEuNjQzLS41MTUgMy4zNDItLjU3OCA1LjMyNy0uMDYxIDEuODc0LjE3OCAzLjg2NC40MzEgNS45Ny42NCA1LjMyMiAxLjM2NSAxMS4zNTQtMi42OTEgMTcuNDExYTEuNTk2IDEuNTk2IDAgMDEtMS4zMjguNzA4eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"279.34000000000003\" y=\"-158\" width=\"60\" height=\"60\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-96\" value=\"&lt;b&gt;&lt;font&gt;Postgres&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"279.34000000000003\" y=\"-84\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-71\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNMTE5LjUxNyA1MS4xODhINzkuMjkxYTMuNjQxIDMuNjQxIDAgMCAxLTMuNjQtMy42NDJWNS42MkE1LjYwNSA1LjYwNSAwIDAgMCA3MC4wMjggMEg1NS42NmE1LjYwNiA1LjYwNiAwIDAgMC01LjYyNyA1LjYydjQxLjY0NmEzLjkxMyAzLjkxMyAwIDAgMS0zLjkyIDMuOTI1bC0xMy4xODguMDQ3Yy0yLjE3NiAwLTMuOTcyLTEuNzUtMy45MjYtMy45MjZsLjA5NC00MS42ODdBNS42MDYgNS42MDYgMCAwIDAgMjMuNDY3IDBIOS4xYTUuNjEgNS42MSAwIDAgMC01LjYyNiA1LjYyNVYxMjIuOTljMCAyLjczNyAyLjIyIDUuMDEgNS4wMSA1LjAxaDExMS4wMzNhNS4wMTQgNS4wMTQgMCAwIDAgNS4wMDgtNS4wMTFWNTYuMTk1YTQuOTc1IDQuOTc1IDAgMCAwLTUuMDA4LTUuMDA3ek0xMDAuNjYgOTUuMjQyYTYuNTQ1IDYuNTQ1IDAgMCAxLTYuNTI1IDYuNTI0SDgyLjc5MWE2LjU0NSA2LjU0NSAwIDAgMS02LjUyMy02LjUyNFY4My45YTYuNTQ1IDYuNTQ1IDAgMCAxIDYuNTIzLTYuNTI0aDExLjM0M2E2LjU0NSA2LjU0NSAwIDAgMSA2LjUyNSA2LjUyM3ptMCAwIiBmaWxsPSIjZmY2NjAwIi8+PC9zdmc+;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"610\" y=\"-171\" width=\"70\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-133\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=light-dark(#3587f3, #ededed);align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-35\" target=\"PG-S5D8SCmHSsYNVxMVk-73\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1000\" y=\"-625\" as=\"sourcePoint\" />\n            <mxPoint x=\"390\" y=\"-225\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1024\" y=\"-420\" />\n              <mxPoint x=\"510\" y=\"-420\" />\n              <mxPoint x=\"510\" y=\"-240\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-137\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#d79b00;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#ffe6cc;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"390\" y=\"-136.59\" as=\"targetPoint\" />\n            <mxPoint x=\"610\" y=\"-136.59\" as=\"sourcePoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-145\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#D44E4E;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-35\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"843\" y=\"-160\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1024\" y=\"-470\" />\n              <mxPoint x=\"843\" y=\"-470\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-150\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.984;entryY=0.294;entryDx=0;entryDy=0;entryPerimeter=0;shadow=0;strokeColor=#3587F3;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"229\" y=\"-593\" as=\"sourcePoint\" />\n            <mxPoint x=\"389.03999999999996\" y=\"-228.06399999999985\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"229\" y=\"-490\" />\n              <mxPoint x=\"484\" y=\"-490\" />\n              <mxPoint x=\"484\" y=\"-230\" />\n              <mxPoint x=\"394\" y=\"-230\" />\n              <mxPoint x=\"394\" y=\"-228\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-153\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"622.0000000000005\" y=\"-601\" as=\"sourcePoint\" />\n            <mxPoint x=\"998\" y=\"-158\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"622\" y=\"-398\" />\n              <mxPoint x=\"998\" y=\"-398\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-155\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1025\" y=\"-595\" as=\"sourcePoint\" />\n            <mxPoint x=\"1025\" y=\"-160\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1025\" y=\"-167\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-156\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;fontFamily=Helvetica;fontSize=12;labelBackgroundColor=default;fillColor=#b0e3e6;strokeColor=#0e8088;opacity=20;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1120\" y=\"-390\" width=\"630\" height=\"546\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-157\" value=\"&lt;b&gt;&lt;font&gt;Rabbitmq&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"613\" y=\"-90\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-158\" value=\"&lt;b&gt;&lt;font&gt;Redis&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"804.5\" y=\"-84\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-159\" value=\"&lt;b&gt;&lt;font&gt;OpenTelemetry&lt;/font&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;&lt;font&gt;Collector&lt;/font&gt;&lt;/b&gt;&lt;/div&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"965.75\" y=\"-73\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-5\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;\" parent=\"1\" target=\"PG-S5D8SCmHSsYNVxMVk-163\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1590\" y=\"-270\" as=\"sourcePoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-160\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMCAyMDsiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeT0iMHB4IiB4PSIwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiPiYjeGE7PHN0eWxlIHR5cGU9InRleHQvY3NzIj4mI3hhOwkuc3Qwe2ZpbGw6bm9uZTt9JiN4YTsJLnN0MXtmaWxsOiMzQjY5N0U7fSYjeGE7CS5zdDJ7ZmlsbDojRTY1MjJDO30mI3hhOwkuc3Qze2ZpbGw6dXJsKCNTVkdJRF8xXyk7fSYjeGE7CS5zdDR7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDp1cmwoI1NWR0lEXzJfKTt9JiN4YTsJLnN0NXtmaWxsOnVybCgjU1ZHSURfM18pO30mI3hhOwkuc3Q2e2ZpbGw6dXJsKCNTVkdJRF80Xyk7fSYjeGE7CS5zdDd7ZmlsbDp1cmwoI1NWR0lEXzVfKTt9JiN4YTsJLnN0OHtmaWxsOnVybCgjU1ZHSURfNl8pO30mI3hhOwkuc3Q5e2ZpbGw6dXJsKCNTVkdJRF83Xyk7fSYjeGE7CS5zdDEwe2ZpbGw6dXJsKCNTVkdJRF84Xyk7fSYjeGE7CS5zdDExe2ZpbGw6dXJsKCNTVkdJRF85Xyk7fSYjeGE7CS5zdDEye2ZpbGw6dXJsKCNTVkdJRF8xMF8pO30mI3hhOwkuc3QxM3tmaWxsOnVybCgjU1ZHSURfMTFfKTt9JiN4YTsJLnN0MTR7ZmlsbDp1cmwoI1NWR0lEXzEyXyk7fSYjeGE7CS5zdDE1e2ZpbGw6dXJsKCNTVkdJRF8xM18pO30mI3hhOwkuc3QxNntmaWxsOnVybCgjU1ZHSURfMTRfKTt9JiN4YTsJLnN0MTd7ZmlsbDp1cmwoI1NWR0lEXzE1Xyk7fSYjeGE7CS5zdDE4e2ZpbGw6dXJsKCNTVkdJRF8xNl8pO30mI3hhOwkuc3QxOXtmaWxsOiNGMDVBMjc7fSYjeGE7CS5zdDIwe2ZpbGw6dXJsKCNTVkdJRF8xN18pO30mI3hhOwkuc3QyMXtmaWxsOnVybCgjU1ZHSURfMThfKTt9JiN4YTsJLnN0MjJ7ZmlsbDp1cmwoI1NWR0lEXzE5Xyk7fSYjeGE7PC9zdHlsZT4mI3hhOzxnPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg2LjAyODYiIHgyPSI0NTcuNjMxNSIgeTE9IjUxMC41NTIzIiB4MT0iNDU3LjYzMTUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfMV8iPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRkFFRDFFIiBvZmZzZXQ9IjAiLz4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0YxNUIyQiIgb2Zmc2V0PSIxIi8+JiN4YTsJPC9saW5lYXJHcmFkaWVudD4mI3hhOwk8cG9seWdvbiBwb2ludHM9IjUuNywxOS43IDUuNSwxOC4xIDMuOSwxOC40IDQuMSwxOS45IiBjbGFzcz0ic3QzIi8+JiN4YTsJJiN4YTsJCTxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg4NCAtMC4xNTIxIDAuMTUyMSAwLjk4ODQgLTUyNC40MTM5IC00MTEuMDM1OCkiIHkyPSI0ODYuMDI4NiIgeDI9IjQ2Ny45MDUyIiB5MT0iNTEwLjU1MjMiIHgxPSI0NjcuOTA1MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJTVkdJRF8yXyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iMTguMiwxNS4yIDE4LDEzLjYgMTAuOSwxNC43IDExLjIsMTYuMyIgc3R5bGU9ImZpbGw6dXJsKCNTVkdJRF8yXyk7Ii8+JiN4YTsJJiN4YTsJCTxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg4NCAtMC4xNTIxIDAuMTUyMSAwLjk4ODQgLTUyNC40MTM5IC00MTEuMDM1OCkiIHkyPSI0ODYuMDI4NiIgeDI9IjQ2Mi42NTU3IiB5MT0iNTEwLjU1MjMiIHgxPSI0NjIuNjU1NyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJTVkdJRF8zXyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iOC43LDE2LjcgMTAuMywxNi41IDEwLjEsMTQuOSA4LjUsMTUuMSIgY2xhc3M9InN0NSIvPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg2LjAyODYiIHgyPSI0NjAuMTM5NyIgeTE9IjUxMC41NTIzIiB4MT0iNDYwLjEzOTciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfNF8iPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRkFFRDFFIiBvZmZzZXQ9IjAiLz4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0YxNUIyQiIgb2Zmc2V0PSIxIi8+JiN4YTsJPC9saW5lYXJHcmFkaWVudD4mI3hhOwk8cG9seWdvbiBwb2ludHM9IjguMiwxOS4zIDcuOSwxNy43IDYuNCwxOCA2LjYsMTkuNiIgY2xhc3M9InN0NiIvPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg2LjAyODYiIHgyPSI0NTcuNjI3OCIgeTE9IjUxMC41NTIzIiB4MT0iNDU3LjYyNzgiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfNV8iPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRkFFRDFFIiBvZmZzZXQ9IjAiLz4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0YxNUIyQiIgb2Zmc2V0PSIxIi8+JiN4YTsJPC9saW5lYXJHcmFkaWVudD4mI3hhOwk8cG9seWdvbiBwb2ludHM9IjMuNSwxNS45IDMuNywxNy41IDUuMywxNy4yIDUuMSwxNS42IiBjbGFzcz0ic3Q3Ii8+JiN4YTsJJiN4YTsJCTxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg4NCAtMC4xNTIxIDAuMTUyMSAwLjk4ODQgLTUyNC40MTM5IC00MTEuMDM1OCkiIHkyPSI0ODYuMDI4NiIgeDI9IjQ2Ny45MDg5IiB5MT0iNTEwLjU1MjMiIHgxPSI0NjcuOTA4OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJTVkdJRF82XyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iMTEuMywxNy4yIDExLjYsMTguOCAxOC42LDE3LjcgMTguMywxNi4xIiBjbGFzcz0ic3Q4Ii8+JiN4YTsJJiN4YTsJCTxsaW5lYXJHcmFkaWVudCBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg4NCAtMC4xNTIxIDAuMTUyMSAwLjk4ODQgLTUyNC40MTM5IC00MTEuMDM1OCkiIHkyPSI0ODYuMDI4NiIgeDI9IjQ2Mi42NTgyIiB5MT0iNTEwLjU1MjMiIHgxPSI0NjIuNjU4MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJTVkdJRF83XyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iOS4xLDE5LjIgMTAuNywxOC45IDEwLjQsMTcuNCA4LjksMTcuNiIgY2xhc3M9InN0OSIvPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg2LjAyODYiIHgyPSI0NjAuMTQ2MiIgeTE9IjUxMC41NTIzIiB4MT0iNDYwLjE0NjIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfOF8iPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRkFFRDFFIiBvZmZzZXQ9IjAiLz4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0YxNUIyQiIgb2Zmc2V0PSIxIi8+JiN4YTsJPC9saW5lYXJHcmFkaWVudD4mI3hhOwk8cG9seWdvbiBwb2ludHM9IjYsMTUuNSA2LjIsMTcuMSA3LjgsMTYuOCA3LjYsMTUuMyIgY2xhc3M9InN0MTAiLz4mI3hhOwkmI3hhOwkJPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODg0IC0wLjE1MjEgMC4xNTIxIDAuOTg4NCAtNTI0LjQxMzkgLTQxMS4wMzU4KSIgeTI9IjQ4Ni44MTczIiB4Mj0iNDU3LjE2NzkiIHkxPSI1MTAuMDc1OSIgeDE9IjQ1Ny4xNjc5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9IlNWR0lEXzlfIj4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0ZBRUQxRSIgb2Zmc2V0PSIwIi8+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGMTVCMkIiIG9mZnNldD0iMSIvPiYjeGE7CTwvbGluZWFyR3JhZGllbnQ+JiN4YTsJPHBvbHlnb24gcG9pbnRzPSI0LDE0LjkgMi4xLDIuMiAxLjQsMi4zIDMuNCwxNSIgY2xhc3M9InN0MTEiLz4mI3hhOwkmI3hhOwkJPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODg0IC0wLjE1MjEgMC4xNTIxIDAuOTg4NCAtNTI0LjQxMzkgLTQxMS4wMzU4KSIgeTI9IjQ4NS43NDkzIiB4Mj0iNDU4LjA5OTIiIHkxPSI1MTAuNzIwOSIgeDE9IjQ1OC4wOTkyIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9IlNWR0lEXzEwXyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iNSwxNC43IDIuOSwxLjEgMi4yLDEuMiA0LjMsMTQuOCIgY2xhc3M9InN0MTIiLz4mI3hhOwkmI3hhOwkJPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODg0IC0wLjE1MjEgMC4xNTIxIDAuOTg4NCAtNTI0LjQxMzkgLTQxMS4wMzU4KSIgeTI9IjQ4NC44MTA4IiB4Mj0iNDU5LjY4OTkiIHkxPSI1MTEuMjg3NyIgeDE9IjQ1OS42ODk5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9IlNWR0lEXzExXyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iNi41LDE0LjUgNC4zLDAgMy42LDAuMSA1LjksMTQuNiIgY2xhc3M9InN0MTMiLz4mI3hhOwkmI3hhOwkJPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODg0IC0wLjE1MjEgMC4xNTIxIDAuOTg4NCAtNTI0LjQxMzkgLTQxMS4wMzU4KSIgeTI9IjQ4Ni4yNjg4IiB4Mj0iNDYwLjYxNjYiIHkxPSI1MTAuNDA3MiIgeDE9IjQ2MC42MTY2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9IlNWR0lEXzEyXyI+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGQUVEMUUiIG9mZnNldD0iMCIvPiYjeGE7CQk8c3RvcCBzdHlsZT0ic3RvcC1jb2xvcjojRjE1QjJCIiBvZmZzZXQ9IjEiLz4mI3hhOwk8L2xpbmVhckdyYWRpZW50PiYjeGE7CTxwb2x5Z29uIHBvaW50cz0iNy40LDE0LjQgNS40LDEuMiA0LjcsMS4zIDYuOCwxNC41IiBjbGFzcz0ic3QxNCIvPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg3Ljk0OTQiIHgyPSI0NjIuMTk3NCIgeTE9IjUwOS4zOTIyIiB4MT0iNDYyLjE5NzQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfMTNfIj4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0ZBRUQxRSIgb2Zmc2V0PSIwIi8+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGMTVCMkIiIG9mZnNldD0iMSIvPiYjeGE7CTwvbGluZWFyR3JhZGllbnQ+JiN4YTsJPHBvbHlnb24gcG9pbnRzPSI5LDE0LjEgNy4yLDIuNCA2LjUsMi41IDguMywxNC4yIiBjbGFzcz0ic3QxNSIvPiYjeGE7CSYjeGE7CQk8bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk4ODQgLTAuMTUyMSAwLjE1MjEgMC45ODg0IC01MjQuNDEzOSAtNDExLjAzNTgpIiB5Mj0iNDg3LjQzNzIiIHgyPSI0NjMuMTIyOSIgeTE9IjUwOS43MDE2IiB4MT0iNDYzLjEyMjkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iU1ZHSURfMTRfIj4mI3hhOwkJPHN0b3Agc3R5bGU9InN0b3AtY29sb3I6I0ZBRUQxRSIgb2Zmc2V0PSIwIi8+JiN4YTsJCTxzdG9wIHN0eWxlPSJzdG9wLWNvbG9yOiNGMTVCMkIiIG9mZnNldD0iMSIvPiYjeGE7CTwvbGluZWFyR3JhZGllbnQ+JiN4YTsJPHBvbHlnb24gcG9pbnRzPSI5LjksMTQgOCwxLjggNy40LDEuOSA5LjMsMTQuMSIgY2xhc3M9InN0MTYiLz4mI3hhOzwvZz4mI3hhOzwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1520\" y=\"-329\" width=\"79\" height=\"79\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-161\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij4mI3hhOyAgICA8cGF0aCBkPSJNMTEyIDBIMTJ2NDhjMTcuMyAwIDMzLjU0IDQuNDUzIDQ3LjczIDEyLjE4OFptMCAwIiBmaWxsPSIjZjA0ZTk4Ii8+JiN4YTsgICAgPHBhdGggZD0iTTEyIDQ4djY3LjE1Mmw0Ny43My01NC45NkE5OS40MjIgOTkuNDIyIDAgMCAwIDEyIDQ4IiBmaWxsPSIjMzQzNzQxIi8+JiN4YTsgICAgPHBhdGggZD0ibTcwLjA0IDY2LjYyMS00OC45NzQgNTYuNDA2TDE2LjczOCAxMjhoOTMuMjU4Yy01LjEyMS0yNS4yMS0xOS43NTgtNDYuOTQ1LTM5Ljk1Ny02MS4zNzkiIGZpbGw9IiMwMGJmYjMiLz4mI3hhOzwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1360\" y=\"-321.5\" width=\"71.5\" height=\"71.5\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-177\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-162\" target=\"PG-S5D8SCmHSsYNVxMVk-163\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-162\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTIxLjg1IDk5LjE3Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6dXJsKCNsaW5lYXItZ3JhZGllbnQpO308L3N0eWxlPjxsaW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTI9IjU3IiB4Mj0iMjcuMiIgeTE9IjEzLjQiIHgxPSIxNjguNTUiIGlkPSJsaW5lYXItZ3JhZGllbnQiPjxzdG9wIHN0b3AtY29sb3I9IiNmZmYxMDAiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNmMDVhMjgiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxnIGRhdGEtbmFtZT0iTGF5ZXIgNiIgaWQ9IkxheWVyXzYiPjxwYXRoIGQ9Ik00LjY2LDI1SDIuMzdhMi4zNywyLjM3LDAsMCwwLDAsNC43NEg0LjY2YTIuMzcsMi4zNywwLDEsMCwwLTQuNzRaTTQ4LjQ4LDU5LjU3SDQ2LjE5YTIuMzcsMi4zNywwLDEsMCwwLDQuNzRoMi4yOWEyLjM3LDIuMzcsMCwxLDAsMC00Ljc0Wk00Ni41NiwzN2EyLjM3LDIuMzcsMCwwLDAtMi4zNy0yLjM3SDM2LjI3YTIuMzcsMi4zNywwLDAsMCwwLDQuNzRoNy45MkEyLjM3LDIuMzcsMCwwLDAsNDYuNTYsMzdaTTEyMS43MywyMi4xLDExOS4zMiw4LjU2QTkuODgsOS44OCwwLDAsMCwxMDkuMDcsMEgxNi4yNEE2LjI4LDYuMjgsMCwwLDAsOS45LDcuN2wyLjU0LDE0LjRhMy4zOCwzLjM4LDAsMCwwLC4wOC4zNHYwYy4zLDEuNzYtLjU5LDIuNDctMS4zOSwyLjczaDBhMi4zNywyLjM3LDAsMCwwLC43OSw0LjZIMTE1LjM5QTYuMjgsNi4yOCwwLDAsMCwxMjEuNzMsMjIuMVpNOTAuMTUsNzYuNDJjLTEtNS4yNS00LTcuMi03LjM5LTcuMkg1OC4yNGEyLjM5LDIuMzksMCwwLDAtMi4zNywyLjRBMi4zNywyLjM3LDAsMCwwLDU4LDc0aDBjLjc4LjE0LDEuNjIsMS4xNiwyLjE1LDMuNjhsMi41MiwxNGE5LjU5LDkuNTksMCwwLDAsOS4xOSw3LjU0bDE0LjYzLS4wN2E2LjI4LDYuMjgsMCwwLDAsNi40NC03LjYxWk01Ny43Myw2NC40OEg4NC4zNGEyLjI3LDIuMjcsMCwwLDAsLjU5LS4wOWMyLjQ2LS41MiwyLjU4LTIuNTIsMi4yNi00LjUxTDgzLjgsNDEuMjdjLS45My00Ljg0LTMuNzQtNi43NS03LjQzLTYuNzVINTJhMi4zNywyLjM3LDAsMCwwLS4yOCw0LjcyaDBjLjgxLjE1LDEuNywxLjI0LDIuMjIsNGwyLjU3LDE0LjI0djBBMS45MiwxLjkyLDAsMCwxLDU1LDU5Ljg3aDBhMi4zNiwyLjM2LDAsMCwwLC43OSw0LjU5aDEuOVoiIGNsYXNzPSJjbHMtMSIvPjwvZz48L3N2Zz4=;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1532\" y=\"16\" width=\"90.77\" height=\"74\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-163\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48bGluZWFyR3JhZGllbnQgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtLjIzIDI4LjQ2Mikgc2NhbGUoMS40MDExKSIgeTI9IjguODAyIiB4Mj0iNDUuODQyIiB5MT0iODkuNTciIHgxPSI0NS44NDIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0iZ3JhZmFuYS1vcmlnaW5hbC1hIj48c3RvcCBzdG9wLWNvbG9yPSIjZmNlZTFmIiBvZmZzZXQ9IjAiLz48c3RvcCBzdG9wLWNvbG9yPSIjZjE1YjJhIiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGQ9Ik0xMjAuOCA1Ni45Yy0uMi0yLjEtLjYtNC41LTEuMi03LjJzLTEuOC01LjUtMy4yLTguNmMtMS41LTMtMy40LTYuMi01LjktOS4xLTEtMS4yLTIuMS0yLjMtMy4yLTMuNSAxLjgtNi45LTIuMS0xMy0yLjEtMTMtNi43LS40LTEwLjkgMi4xLTEyLjQgMy4yLS4yLS4xLS42LS4yLS44LS4zLTEuMS0uNC0yLjMtLjktMy41LTEuMy0xLjItLjMtMi40LS44LTMuNi0xLTEuMi0uMy0yLjUtLjYtMy45LS44LS4yIDAtLjQtLjEtLjctLjFDNzcuNSA2IDY5LjEgMiA2OS4xIDJjLTkuNiA2LjItMTEuNCAxNC40LTExLjQgMTQuNHMwIC4yLS4xLjRjLS42LjEtMSAuMy0xLjUuNC0uNy4yLTEuNC40LTIuMS44bC0yLjEuOWMtMS40LjctMi44IDEuMy00LjIgMi4xLTEuMy44LTIuNiAxLjUtMy45IDIuNC0uMi0uMS0uMy0uMi0uMy0uMi0xMi45LTUtMjQuMyAxLTI0LjMgMS0xIDEzLjggNS4yIDIyLjMgNi40IDIzLjktLjMuOS0uNiAxLjctLjkgMi41LTEgMy4xLTEuNyA2LjMtMi4xIDkuNi0uMS40LS4xIDEtLjIgMS40QzEwLjUgNjcuNSA3IDc5LjYgNyA3OS42IDE2LjkgOTEgMjguNSA5MS43IDI4LjUgOTEuN2MxLjQgMi42IDMuMiA1LjIgNS4xIDcuNS44IDEgMS43IDEuOSAyLjUgMi45LTMuNiAxMC4zLjYgMTkgLjYgMTkgMTEuMS40IDE4LjQtNC44IDE5LjktNi4xIDEuMS4zIDIuMi43IDMuMyAxIDMuNC45IDYuOSAxLjQgMTAuMyAxLjVoNC41YzUuMiA3LjUgMTQuNCA4LjUgMTQuNCA4LjUgNi41LTYuOSA2LjktMTMuNiA2LjktMTUuMnYtLjZjMS4zLTEgMi42LTIgNC0zLjEgMi42LTIuMyA0LjgtNS4xIDYuOC03LjkuMi0uMi4zLS42LjYtLjggNy40LjQgMTIuNS00LjYgMTIuNS00LjYtMS4yLTcuNy01LjYtMTEuNC02LjUtMTIuMWwtLjEtLjEtLjEtLjEtLjEtLjFjMC0uNC4xLS45LjEtMS40LjEtLjkuMS0xLjcuMS0yLjV2LTMuM2MwLS4yIDAtLjQtLjEtLjdsLS4xLS43LS4xLS43Yy0uMS0uOS0uMy0xLjctLjQtMi41LS44LTMuMy0yLjEtNi41LTMuNy05LjItMS44LTIuOS0zLjktNS4zLTYuMy03LjUtMi40LTIuMS01LjEtMy45LTcuOS01LjEtMi45LTEuMy01LjctMi4xLTguNy0yLjQtMS40LS4yLTMtLjItNC40LS4yaC0yLjNjLS44LjEtMS41LjItMi4yLjMtMyAuNi01LjcgMS43LTguMSAzLjEtMi40IDEuNC00LjUgMy4zLTYuMyA1LjQtMS44IDIuMS0zLjEgNC4zLTQgNi43LS45IDIuMy0xLjQgNC44LTEuNSA3LjJ2Mi42YzAgLjMgMCAuNi4xLjkuMSAxLjIuMyAyLjMuNyAzLjQuNyAyLjIgMS43IDQuMiAzIDUuOXMyLjggMy4xIDQuNCA0LjJjMS43IDEuMSAzLjMgMS45IDUuMSAyLjRzMy40LjggNSAuN2gyLjNjLjIgMCAuNC0uMS42LS4xLjIgMCAuMy0uMS42LS4xLjMtLjEuOC0uMiAxLjEtLjMuNy0uMiAxLjMtLjYgMi0uOC43LS4zIDEuMi0uNyAxLjctMSAuMS0uMS4zLS4yLjQtLjMuNi0uNC43LTEuMi4yLTEuOC0uNC0uNC0xLjEtLjYtMS43LS4zLS4xLjEtLjIuMS0uNC4yLS40LjItMSAuNC0xLjQuNi0uNi4xLTEuMS4zLTEuNy40LS4zIDAtLjYuMS0uOS4xaC0xLjhzLS4xIDAgMCAwaC0uN2MtLjEgMC0uMyAwLS40LS4xLTEuMi0uMi0yLjUtLjYtMy43LTEuMS0xLjItLjYtMi40LTEuMy0zLjQtMi4zLTEuMS0xLTItMi4xLTIuOC0zLjQtLjgtMS4zLTEuMi0yLjgtMS40LTQuMi0uMS0uOC0uMi0xLjUtLjEtMi4zdi0uN2MwIC4xIDAgMCAwIDBWNzBjMC0uNC4xLS44LjItMS4yLjYtMy4zIDIuMi02LjUgNC43LTguOS43LS43IDEuMy0xLjIgMi4xLTEuNy44LS42IDEuNS0xIDIuMy0xLjMuOC0uMyAxLjctLjcgMi41LS45LjktLjIgMS44LS40IDIuNi0uNC40IDAgLjktLjEgMS4zLS4xaC44Yy4xIDAgMCAwIDAgMGguNGMxIC4xIDIgLjIgMi45LjQgMS45LjQgMy43IDEuMSA1LjUgMi4xIDMuNSAyIDYuNSA1IDguMyA4LjYuOSAxLjggMS41IDMuNyAxLjkgNS44LjEuNi4xIDEgLjIgMS41djIuN2MwIC42LS4xIDEuMS0uMSAxLjctLjEuNi0uMSAxLjEtLjIgMS43cy0uMiAxLjEtLjMgMS43Yy0uMiAxLjEtLjcgMi4xLTEgMy4yLS44IDIuMS0xLjkgNC4xLTMuMiA1LjgtMi42IDMuNi02LjMgNi42LTEwLjMgOC41LTIuMS45LTQuMiAxLjctNi40IDItMS4xLjItMi4yLjMtMy4zLjNoLTEuNmMuMSAwIDAgMCAwIDBoLS4xYy0uNiAwLTEuMiAwLTEuOC0uMS0yLjQtLjItNC43LS43LTctMS4zLTIuMy0uNy00LjUtMS41LTYuNi0yLjYtNC4yLTIuMi03LjktNS40LTEwLjktOS0xLjQtMS45LTIuOC0zLjktMy45LTUuOXMtMS45LTQuMy0yLjUtNi41Yy0uNy0yLjItMS00LjUtMS4xLTYuOHYtMy41YzAtMS4xLjEtMi4zLjMtMy41LjEtMS4yLjMtMi4zLjYtMy41LjItMS4yLjYtMi4zLjktMy41LjctMi4zIDEuNC00LjUgMi40LTYuNiAyLTQuMiA0LjUtNy45IDcuNS0xMC45LjgtLjggMS41LTEuNCAyLjQtMi4xLjMtLjMgMS4xLTEgMi0xLjVzMS44LTEuMSAyLjgtMS41Yy40LS4yLjktLjQgMS40LS43LjItLjEuNC0uMi44LS4zLjItLjEuNC0uMi44LS4zIDEtLjQgMi0uOCAzLTEuMS4yLS4xLjYtLjEuOC0uMi4yLS4xLjYtLjEuOC0uMi42LS4xIDEtLjIgMS41LS40LjItLjEuNi0uMS44LS4yLjIgMCAuNi0uMS44LS4xLjIgMCAuNi0uMS44LS4xbC40LS4xLjQtLjFjLjIgMCAuNi0uMS44LS4xLjMgMCAuNi0uMS45LS4xLjIgMCAuNy0uMS45LS4xLjIgMCAuMyAwIC42LS4xaC43Yy4zIDAgLjYgMCAuOS0uMWguNHMuMSAwIDAgMGg0LjFjMiAuMSA0IC4zIDUuOC43IDMuNy43IDcuNCAxLjkgMTAuNiAzLjUgMy4yIDEuNSA2LjIgMy41IDguNiA1LjYuMS4xLjMuMi40LjQuMS4xLjMuMi40LjQuMy4yLjYuNi45LjguMy4yLjYuNi45LjguMi4zLjYuNi44LjkgMS4xIDEuMSAyLjEgMi4zIDMgMy40IDEuOCAyLjMgMy4yIDQuNiA0LjMgNi44LjEuMS4xLjIuMi40LjEuMS4xLjIuMi40cy4yLjYuNC44Yy4xLjIuMi42LjMuOC4xLjIuMi42LjMuOC40IDEgLjggMiAxLjEgMyAuNiAxLjUuOSAyLjkgMS4yIDQgLjEuNC42LjggMSAuOC42IDAgLjktLjQuOS0xLS4zLTEuNy0uMy0zLjEtLjQtNC44eiIgZmlsbD0idXJsKCNncmFmYW5hLW9yaWdpbmFsLWEpIi8+PC9zdmc+;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1610\" y=\"-158\" width=\"88\" height=\"88\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-6\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-164\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"1610\" y=\"-120\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"1340\" y=\"65\" />\n              <mxPoint x=\"1340\" y=\"-120\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-164\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij4mI3hhOyAgICA8cGF0aCBkPSJNMzguNDIyIDExMy42OGMtMS44MDUuNDE0LTcuMTE3IDMuMjg5LTExLjcxMSA0LjE2LTQuNTkuODc1LTguNTYzIDEuMzM2LTkuOTU3IDEuODUxLTEuMzkuNTEyLTIuNDczIDEuNTQuMjU4IDIuNTY3IDIuNzM4IDEuMDI3IDE1Ljk5MiAxLjM4NyAxNy4xOCAwIDEuMTg3LTEuMzg3LS44Mi0xLjk4OC0zLjcxNS0xLjk1LTIuMDYzLjAyNC0xLjgxMy0uNjktMS44MDUtLjc3MyAwIDAgLjEyOS0uODk4IDMuMy0xLjMzNiAzLjE2OS0uNDMzIDE3LjE4LTEuNzQyIDE2LjkyMy0zLjIzNC0uMjU4LTEuNDg4LTguNjY4LTEuNjk1LTEwLjQ3My0xLjI4NVptLTYuNDA2IDEwLjQxYy0uMDk0LS40MjYtMS4zNzUtLjUyLTIuODU2LS4xOTUtMS40ODQuMzI0LTIuNjEuOTMtMi41MTUgMS4zNTkuMDkzLjQzIDEuMzcuNTIgMi44NTUuMiAxLjQ4NC0uMzI1IDIuNjA1LS45MzQgMi41MTYtMS4zNjRabS02LjE2NC0uMDA0Yy0uMDM2LS40MjItMS4zNTItLjY2OC0yLjk0Mi0uNTQzLTEuNTkuMTI5LTIuODUxLjU3NC0yLjgyIDEgLjAzNS40MjIgMS4zNTEuNjY0IDIuOTQxLjUzNSAxLjU5NC0uMTIxIDIuODU2LS41NjYgMi44Mi0uOTkyWm0tNi4wNDMtLjY2NGMtLjA0Ny0uMzI4LS45NDItLjQ4LTItLjMzNi0xLjA2My4xNC0xLjg4My41MjctMS44MzYuODYuMDQzLjMyNy45NDEuNDggMiAuMzM1IDEuMDU4LS4xNDQgMS44NzktLjUyNyAxLjgzNi0uODZabS0zLjgyLS41ODZjLS4wNC0uMjYyLS45LS4zNi0xLjkyMy0uMjExLTEuMDIzLjE0NS0xLjgxNi40OC0xLjc4Ljc0Ni4wMzguMjcuOTAyLjM2NyAxLjkyMS4yMTkgMS4wMi0uMTQ5IDEuODItLjQ4NSAxLjc3Ny0uNzU0Wm0tLjg1Mi0xLjA1Yy0uMDQtLjI3LS44OTktLjM2NC0xLjkyMi0uMjE2LTEuMDI0LjE0OS0xLjgyLjQ4NS0xLjc4MS43NS4wMzkuMjY2LjkwMi4zNjQgMS45MjEuMjE1IDEuMDI0LS4xNDQgMS44Mi0uNDg0IDEuNzgyLS43NVptLS40NjUtMS4xNTdjLS4wMzUtLjIzLS43ODEtLjMxNy0xLjY3Mi0uMTg4LS44ODcuMTMzLTEuNTc4LjQyMi0xLjU0My42NTcuMDMxLjIzLjc3Ny4zMTIgMS42NjguMTgzLjg5LS4xMjUgMS41ODItLjQxOCAxLjU0Ny0uNjUyWm01MS4yOTctNS41MTJjLTMuMTQ1LjE1Ni0xMC4yNjYtLjIwMy0xMS4yNDYgMS40NDItLjk4IDEuNjQgMi44OSAyLjI1NyA4Ljk3NiAxLjc0NiA2LjA5LS41MTYgMTQuNzAzLTEuMTg0IDE1LjA2Ny0zLjAzMi4zNTktMS44NDctMS42MDItMS40OTItMS44MDktMi42NjgtLjIwNy0xLjE4MyAyLjE2OC0xLjE4MyAyLjYzMy0yLjkzLjQ2NS0xLjc0NS0zLjE5NS0xLjU0Mi02LjQ1LTEuNTQyLTMuMjUgMC04LjY2My4zMDgtOS4xODMgMi4wMDQtLjUxNiAxLjY5NSAyLjQ3NyAxLjY5NSA0LjU5NCAyLjEwNSAyLjExMy40MTQgMS40OTYgMS4xODQgMS40OTYgMS4xODQtLjEwNiAxLjA3OC0uOTMgMS41MzktNC4wNzggMS42OTFabS01LjY4NCA0LjUxMmMwLS40OTItMS4yMjItLjg4Ny0yLjczLS44ODdzLTIuNzI3LjM5NS0yLjcyNy44ODdjMCAuNDg0IDEuMjE5Ljg4MyAyLjcyNy44ODMgMS41MDggMCAyLjczLS4zOTkgMi43My0uODgzWm02LjExMy0uMTk1YzAtLjQ1LS44MTYtLjgwOS0xLjgyLS44MDlzLTEuODIuMzYtMS44Mi44MDljMCAuNDQ1LjgxNi44MDggMS44Mi44MDhzMS44Mi0uMzYzIDEuODItLjgwOFptNS44NC0uNTc5YzAtLjM2My0uODk0LS42NTYtMS45OTItLjY1Ni0xLjEwMSAwLTEuOTk2LjI5My0xLjk5Ni42NTYgMCAuMzY0Ljg5NS42NTcgMS45OTYuNjU3IDEuMDk4IDAgMS45OTItLjI5MyAxLjk5Mi0uNjU3Wm0zLjgzMi0uNzNjMC0uMzgzLS42NDgtLjY5NS0xLjQ1My0uNjk1LS44IDAtMS40NTMuMzEyLTEuNDUzLjY5NSAwIC4zODMuNjUyLjY5MSAxLjQ1My42OTEuODA1IDAgMS40NTMtLjMwOCAxLjQ1My0uNjkxWm0zLjc5My0uNzljMC0uMzc0LS42Ni0uNjc1LTEuNDcyLS42NzUtLjgxMyAwLTEuNDcuMy0xLjQ3LjY3NiAwIC4zNzEuNjU3LjY3MiAxLjQ3LjY3Mi44MTIgMCAxLjQ3Mi0uMzAxIDEuNDcyLS42NzJaTTE0LjIzOCA5OC4zOTJjMCAuODc5IDEuOTIyIDEuNzA3IDUuMzI4IDIuNDQ1LS4yNDItMS43NjItLjA5My0zLjUzMS4xMzMtNC45MS0zLjQ5Mi43NDItNS40NiAxLjU4Mi01LjQ2IDIuNDY5Wm0xMDAuNTU5LTIuMjY2YTcuNjA0IDcuNjA0IDAgMCAxLTEuOTUzIDIuOThjLTEuNTQgMS40NTQtMi44ODcgMi4zMjUtNC4wOTQgMi42NDEgNi42Ni0uOTMzIDEwLjYxMy0yLjA5NCAxMC42MTMtMy4zNTEgMC0uODEtMS42MzYtMS41NzktNC41NjYtMi4yN1ptMCAwIiBmaWxsPSIjMjMxZjIwIi8+JiN4YTsgICAgPHBhdGggZD0iTTEwMy40MDYgOTQuMjgxYy0uNDIyLTMuMDktMS43NDYtNC40NzYtMi45MTgtNS42OTktMS4wODYtMS4xNC0yLjExNy0yLjIxNS0xLjc4NS00LjE5MS4zMDktMS44MjkgMS43NjYtMi45NSA0LjE1Mi0zLjI0My0xLjQ0OS05Ljc1LTMuNTc0LTIyLjA0Ni02LjMtMzIuNTM1LTEuMzY0LTUuMjM4LTMuNTE2LTguODc1LTYuNDA3LTExLjI5Ny0zLjMwOCAxLjY4OC03LjI4IDMuNTQtMTEuNzIyIDUuNDU3YTMwNi41MiAzMDYuNTIgMCAwIDEtOS42NzYgMy45NzNjLTIuNTMxIDIuNzA3LTUuMzA1IDUuMzc5LTcuMDA0IDYuMTQtMS4yMDcuNTQtMi4yODUuNzU5LTMuMjE5Ljc1OS0yLjAyIDAtMy4zODYtMS4wMTItNC4wNDMtMS45MS0uNzcuMjAzLTEuMzgyLjMzNS0xLjc5Ny4zNzQtLjQ5Ni4wNTUtMS4yMy4xMTgtMi4xNDguMTg0YTIuOCAyLjggMCAwIDEtLjQ2IDIuODA1Yy0uNzQ3Ljg5LTEuOTQ2IDEuMzQtMy42NDUgMS4zNC0yLjQ0MiAwLTUuOTE4LS45MjYtMTAuNTctMi44MDEtLjYzLS4yNTQtMS4yNTktLjUtMS44OTEtLjczOS0uMzU2LjAwNC0uNzExLjAwNC0xLjA2Ny4wMDRoLS4wMDRjLTQuNDQ1IDAtNy45MTQtLjEzNi0xMC42MzYtLjM1OS0yLjk4NSA2LjE0NS0xLjY4OCAxMi45Ni0uNTk4IDE4LjU5IDEuMDQ3IDUuMzk4IDQuNjc2IDE0Ljk5NiA4LjA0MyAyMy4yNDYgMS4xMzcgMi43ODkgMi4zIDUuNTcgMy40ODggOC4zNCA5LjExLjggMjAuNzkzIDEuMjgxIDMzLjUzMSAxLjI4MSAxNS4xNiAwIDI4LjgxLS42ODQgMzguNDI2LTEuNzc3LS43MDMtMi44NjgtMS41ODYtNi44Ni0xLjc0Mi03Ljg4Wk0yOC4zMiA2OC4wMTFjMC01LjggNC43MjctMTAuNSAxMC41NTUtMTAuNSA1LjgyNCAwIDEwLjU0NyA0LjcgMTAuNTQ3IDEwLjUgMCAyLjg5MS0xLjE3NiA1LjUwOS0zLjA3NCA3LjQxYTEwLjY4MiAxMC42ODIgMCAwIDEtMi4xMzcgMS42NSAxMC40OTkgMTAuNDk5IDAgMCAxLTUuMzM2IDEuNDRjLTUuODI4IDAtMTAuNTU1LTQuNjk4LTEwLjU1NS0xMC41Wk01Ni41IDkwLjI0N2MtMi4yMjMuNjYtMy4wMjMtMS44ODMtMy4yNjItMi45ODguMDE2LS4wMDguMDMyLS4wMi4wNDctLjAzMSAxLjAzNS0uNjQ1IDIuMjM4LTEuMzgzIDMuNTktMS44OTkuMTU2LjQyMi40MDIgMS4xNC41NSAxLjg5OS4yNDcgMS4yOC4yMjMgMi42OC0uOTI1IDMuMDJabTMuNjEzLS44OThjLS41NTQtLjIwNy0uOTcyLTEuMTIxLTEuMjctMi4xMjFhMTguNzE5IDE4LjcxOSAwIDAgMS0uNTE1LTIuMzQ0Yy4yNTgtLjA1OS41MjctLjEwNi43OTctLjE0NS4xMzMtLjAyLjQxOC0uMDM5IDEuMDE2LS4wMzkuNTQ3IDAgMS4yMDcuMDIgMS45MS4wNC4xOTkuMDAzLjQwNi4wMTEuNjE3LjAxMS4wNTkuNDc3LjEyMSAxLjE3Mi4yIDIuMTg0LjAxLjEwNS4wMS4xOTkuMDEuMjkzLjAzMiAyLjUzLTIuMTg3IDIuMzQtMi43NjUgMi4xMlptOS40OTYtNi4zODdjLTEuMDc4LjQ3Ny0yLjY1Ni42OC01LjI5My42OC0uODk0IDAtMS44MTYtLjAyLTIuNjI5LS4wNGE2My4wODIgNjMuMDgyIDAgMCAwLTEuOTI1LS4wMzhjLS41MDggMC0uODguMDE1LTEuMTAyLjA0Mi0yLjQ4OC4zMjktNC41NDMgMS42MS02LjE5NSAyLjY0MS0uNDguMy0uOTM4LjU4Mi0xLjM2LjgxNy0uNjg3LjM3NC0xLjUyMy41NzQtMi40My41NzQtMS42NzEgMC0zLjI0MS0uNjUzLTQuMjA2LTEuNzQ2LS43OTctLjkwNy0xLjEzMy0yLjA0My0uOTY5LTMuMjgyLjUtMy43MTQgNS44MzYtNS42MTMgNi40NDEtNS44MTZsLjk3Ny0uMzMyYTEuNDk2IDEuNDk2IDAgMCAxLS4wNzQtLjI5Yy0uMjktMS43MyAxLjk4LTMuNTQ2IDUuMDctNC4wNThsLjQxNC0uMDU4YzIuNTU5LS4zMTcgNC44MDUuMzk4IDUuNTA0IDEuNjkxbDEuMTkxLjAwOGMyLjcxMS4wMjMgNC45NTQuMzg3IDYuNjUzIDEuMDgyIDEuNzE1LjY5NSAyLjc2MSAxLjcwNyAyLjk1MyAyLjg0OC4zODcgMi4yOTMtLjc0NiA0LjI2NS0zLjAyIDUuMjc3Wm0xLjk1NC0xMi4wMTZjLTUuODI1IDAtMTAuNTQ3LTQuNzAzLTEwLjU0Ny0xMC41MDQgMC01LjggNC43MjItMTAuNTA0IDEwLjU0Ny0xMC41MDQgNS44MjQgMCAxMC41NSA0LjcwNCAxMC41NSAxMC41MDQgMCA1LjgwMS00LjcyMiAxMC41MDQtMTAuNTUgMTAuNTA0Wm0wIDAiIGZpbGw9IiM2N2NmZTMiLz4mI3hhOyAgICA8cGF0aCBkPSJtODUuMDc0IDI1LjA1NS0uMDgyLS4xMzctLjEwMS0uMTMzYy0uMDk4LS4xNTYtLjQ4NS0uMzk0LS41MTYtLjM5OGwtLjA0LS4wMi0uMDE5LS4wMTItLjA3NC0uMDM1aC0uMDA4bC0uMDE1LS4wMDgtLjEwNi0uMDM1LS4yMTUtLjA3NGMtLjE0NC0uMDUtLjMwNC0uMDctLjQ1Ny0uMTAxLS4xNTYtLjAyOC0uMzItLjAyOC0uNDgtLjAzNmE0LjA0NyA0LjA0NyAwIDAgMC0uNDg4LjA0IDMuNTI2IDMuNTI2IDAgMCAwLTEuNjU3Ljc5NiA1LjI3NSA1LjI3NSAwIDAgMC0xLjA0MyAxLjIyIDguNiA4LjYgMCAwIDAtMS4wMyAyLjQxNyA5LjkxNyA5LjkxNyAwIDAgMC0uMzEzIDEuNzljLS4wMjQuMjE4LS4wMjQuMzktLjAyOC41MDctLjAwNC4xMTcgMCAuMTggMCAuMThsLjMzMi0uNTk4Yy4yMTEtLjM3NS41MDQtLjkwNi44NjQtMS41MjMuMzY3LS42MS44MDQtMS4zMSAxLjMzMi0xLjk0Mi4yNjUtLjMxNi41NTgtLjYxLjg2Ny0uODM2LjMwOC0uMjE5LjYyNS0uMzc1Ljk0MS0uNDIyLjA3OC0uMDExLjE2LS4wMjMuMjM5LS4wMy4wODIuMDEuMTYgMCAuMjQyLjAxOS4wODYuMDIuMTY4LjAxNS4yNTQuMDQzbC4yMDMuMDU0LjA2Mi4wMzItLjAwOC0uMDA4aC4wMTJjMCAuMDA0LjAwNC4wMDguMDA4LjAxMWwuMDA0LjAwNC4wMjMuMDA4aC0uMDExYy0uMDA0IDAtLjAwOCAwLS4wMTItLjAwNC4wMTIuMDA4LjAyLjAyLjAyNy4wNDMuMDQzLjA3NC4wNzguMjMuMDkuMzk5LjAxNi4zODItLjAxNi43NjEtLjA5IDEuMTM2LS4wNTguMzc1LS4xMzYuNzM5LS4yMjYgMS4xMDYtLjE2LjY5NS0uMzIgMS4yODUtLjQyMiAxLjcwMy0uMTEuNDE4LS4xNjguNjYtLjE2OC42NnMuMTgzLS4xNzYuNDU3LS41MTZjLjM3NS0uNDc2LjcxNS0uOTggMS4wMDgtMS41MDdhOC4zNiA4LjM2IDAgMCAwIC41MjMtMS4xMjFjLjE2LS40MTguMzA5LS44OC4zNTYtMS40MzhhMi41MDMgMi41MDMgMCAwIDAtLjExOC0uOTYgMS40MDcgMS40MDcgMCAwIDAtLjExNy0uMjc0Wm0wIDAiIGZpbGw9IiMwMDAiLz4mI3hhOyAgICA8cGF0aCBkPSJtODMuNzUgMjUuODE2LS4wMTItLjAwMy4wMTIuMDExaC4wMDRsLS4wMDQtLjAwNFptMCAwIiBmaWxsPSIjMDAwIi8+JiN4YTsgICAgPHBhdGggZD0iTTE5LjY0OCA0NS4xMjloLjE0NWMtLjA1LS4wODYtLjA5OC0uMTc2LS4xNDUtLjI2MlptMS4yOS00LjA3NGMuMjUuNDk2LjU0Ni45NjguODkgMS40MDYuMTIxLjE2LjIyNy4yNzMuMy4zNTUuMDY3LjA4Mi4xMS4xMjEuMTEuMTIxcy0uMDQzLS4yMjYtLjEyLS42MDljLS4wNzEtLjM4Ny0uMTkyLS45MjYtLjI5NC0xLjU1OGExMS4zMSAxMS4zMSAwIDAgMS0uMTItMWMtLjAxNy0uMzM2LS4wMTctLjcuMDU0LS45NjFhLjczMS43MzEgMCAwIDEgLjEzNy0uMjkuMzQyLjM0MiAwIDAgMSAuMTQ4LS4wODFsLjA0Ny0uMDEyLjA4Mi0uMDE2Yy4wMjMtLjAwNC0uMDA4LjAxNi0uMDEyLjAxNi0uMDA0LjAwNC0uMDE1LjAwNC0uMDIzLjAwNGgtLjAxNmwuMDA4LjAwNGMuMDIuMDA3LjAzMS4wMDcuMDQ3LjAxMS4wNzguMDI4LjE5NS4wOTQuMzIuMTg0LjI2Mi4xODcuNTMxLjQ4Ljc5Ljc3My4yNTcuMzA5LjUwMy42MjEuNzM3Ljk0Mi40NzMuNjQuOTEgMS4yNjEgMS4yOTMgMS43OTcuMzEzLjQzNy42My44NzUuOTU3IDEuMy4xMjIuMTY0LjI1NC4zMjkuMzg3LjQ4OWwtLjAyLS4xNjRjLS4wMTUtLjEwMi0uMDM1LS4yNjItLjA3NC0uNDU3YTExLjgzNSAxMS44MzUgMCAwIDAtLjQxNC0xLjU4NiAxMy40MTIgMTMuNDEyIDAgMCAwLS45MTQtMi4xNDEgOC45NTMgOC45NTMgMCAwIDAtLjcyMi0xLjE0NSA1LjMwMyA1LjMwMyAwIDAgMC0xLjA1NS0xLjA5NyAyLjkxOCAyLjkxOCAwIDAgMC0uODQ0LS40M2MtLjA5NC0uMDItLjE4My0uMDM5LS4yNzctLjA1bC0uMDc0LS4wMTJoLS4wOTRjLS4wNjcgMC0uMTI1LjAwNC0uMTkyLjAwNy0uMDU0LjAwOC0uMTQ0LjAxNi0uMTcxLjAyNGwtLjA3OS4wMi0uMDc4LjAyMy0uMTA1LjAzMS0uMDMxLjAxMi0uMDU5LjAyN2ExLjc3MyAxLjc3MyAwIDAgMC0uODI0LjcwNyAyLjA4MiAyLjA4MiAwIDAgMC0uMjkuODk1Yy0uMDUuNTUuMDYuOTk2LjE2OSAxLjM5OC4xMTMuMzY3LjI1NC43MjMuNDI1IDEuMDYzWm0wIDAiIGZpbGw9IiMyMzFmMjAiLz4mI3hhOyAgICA8cGF0aCBkPSJNMjUuODA1IDEwNS41NzRjMi40NzIgMCA0LjIxLTEuMzQgNS40MzctMy4wNzhhMzYyLjM5IDM2Mi4zOSAwIDAgMS01Ljg4My0xNC4zOTRjLS41OTMuNS0xLjI3MyAxLjI1My0yLjAxNSAyLjM5LTEuODM2IDIuODQtMy4zNTIgOS40MzgtMS40NDYgMTIuOTI2Ljc5NyAxLjQ1IDIuMDc1IDIuMTU2IDMuOTA3IDIuMTU2Wm04Ny4zMDgtMTYuMzU1Yy0xLjQ1My0zLjczLTQuNTM1LTYuMzgzLTcuNS02LjQ0NmwtLjEwMS0uMDExYy0uMDA4IDAtLjU3OC0uMDgyLTEuMzQ0LS4wODItMS42MTMgMC0zLjU5NC4zNC0zLjg2NyAxLjk3Ni0uMTkyIDEuMTMzLjMwNCAxLjcxMSAxLjM2IDIuODE3IDEuMjAyIDEuMjYxIDIuODUgMi45ODQgMy4zNDcgNi41OTMuNTY2IDQuMTI1IDEuNTc4IDYuMjIzIDMuMDEyIDYuMjIzLjY2OCAwIDEuODgyLS4zOTggMy44OTgtMi4zIDIuNDgtMi4zNCAyLjI0Mi02LjA2MyAxLjE5NS04Ljc3Wm0wIDAiIGZpbGw9IiNkZmNhYTMiLz4mI3hhOyAgICA8cGF0aCBkPSJNNDEuMjQ2IDcxLjcwM2EzLjMyIDMuMzIgMCAwIDEtMy4zMjQgMy4zMTMgMy4zMiAzLjMyIDAgMCAxLTMuMzI4LTMuMzEzIDMuMzIgMy4zMiAwIDAgMSAzLjMyOC0zLjMxMiAzLjI5NyAzLjI5NyAwIDAgMSAyLjM0OC45NjhjLjYyNS42MjEuOTc2IDEuNDY1Ljk3NiAyLjM0NFptMzIuMjE1LTcuNzYyYTMuMzE0IDMuMzE0IDAgMCAxLTMuMzI0IDMuMzEzIDMuMzE4IDMuMzE4IDAgMCAxLTMuMzI4LTMuMzEzYzAtMS44MjggMS40OTItMy4zMDggMy4zMjgtMy4zMDhhMy4zMTYgMy4zMTYgMCAwIDEgMy4zMjQgMy4zMDhabTAgMCIgZmlsbD0iIzIzMWYyMCIvPiYjeGE7ICAgIDxwYXRoIGQ9Ik0yOC44OTUgMzQuNzA3YzIuNTk3LjY5NSA1LjUzIDEuMDQ3IDguNzI2IDEuMDQ3IDUuMTI5IDAgMTYuMDItLjk4OCAzMS4zMjgtNy42MzNsLjM0NC0uMTUyYTkuMDQ5IDkuMDQ5IDAgMCAxIC4yMS0yLjUxMmMuMzM3LTEuNTM1IDEuMDEzLTIuODQgMS44MzctMy43MDMtLjE1Ni0uNTktLjI5LTEuMDItLjM4My0xLjIzOC0xLjc2Ni0uOTM4LTE2LjMyNC02LjMzNi0yMy45MjItNi4zMzYtLjc2MiAwLTEuNDIyLjA1NC0xLjk2OS4xNjQtNi43MyAxLjM3LTE2Ljk2IDEzLjAyMy0xNy4zMjQgMTQuNjcyLS4xMS43MTQtLjA3OCAyLjk1Ny4wMDQgNS4zODJabS0uMTMgMTYuNTQzYTUuNDEgNS40MSAwIDAgMC0uNjYtLjExIDIuODIyIDIuODIyIDAgMCAxLTIuOTQ1LTIuMzA0IDIuNjcgMi42NyAwIDAgMS0uMDQzLS40MyAzMC4xNCAzMC4xNCAwIDAgMC0yLjI0MiAxLjM5bC0xLjI3Ljg3Ni0uOTM3LTEuMjI3YTMyLjU4IDMyLjU4IDAgMCAxLTIuNzg1LTQuNDE4Yy0yLjI1IDEuMDU5LTQuMDEyIDIuMjE1LTQuNDQyIDMuMzEzLS4wODIuMjA3LS4wNDYuMzIuMDM2LjQ0MS4zNjcuNTM1IDIuNTUgMi4xNzIgMTUuMjg5IDIuNDY5Wm0yNi40NTQtMy41OWEyLjg0IDIuODQgMCAwIDEgMy40NjguMzMyYy4xNDEtLjAyMy4zODMtLjA4Mi43MzUtLjI0MiAxLjM5OC0uNjYgNi40MjYtNi4wMDggMTAuMjUtMTAuNTg2LjEzNy0uMTYuMjg1LS4zMDUuNDU3LS40MzQtOC43MzQgMy43NTgtMjAuOTM4IDcuODY0LTMyLjU1OSA3Ljg2NC0xLjg2NyAwLTMuNjQtLjEwNi01LjI4OS0uMzJsLjI1OC43NDYtMS40NTMuNTU0YTMzLjkxIDMzLjkxIDAgMCAwLS42OC4yNzRjMS44NzEuNDMzIDQuNDAzIDEuMjg5IDcuNTc4IDIuNTcgNS44MDkgMi4zMzIgOC4wMzIgMi40MjIgOC41ODYgMi4zOWEyLjg1IDIuODUgMCAwIDEgMi41NjMtLjAzNSA4OC45NTUgODguOTU1IDAgMCAwIDMuMzgzLS4yNjFjLjMyLS4wMzUuNzk3LS4xMzMgMS4zOTgtLjI5YTIuODAyIDIuODAyIDAgMCAxIDEuMzA1LTIuNTYyWk04OS4wNSAzMC40NzNjLS40MjIgMi41MTEtMS4yMzkgNS4yNy0xLjc3NCA2LjAybC0uNTA3LjcwMmExMTguMTE2IDExOC4xMTYgMCAwIDAgNi4wNy0zLjEzM2M2LjAzNS0zLjM2NyA2Ljc4OS00Ljg0IDYuODc1LTUuMjE0LjA1NS0uMjQ2LS4wMDQtLjMyLS4wMzEtLjM1Mi0uMDY3LS4wODItLjQ5My0uNDkyLTIuMzk5LS40OTItMi4wODIgMC00Ljk5Ni40NzYtOC4wMzkgMS4xMzMtLjA1NS40NDktLjEyMS44OTQtLjE5NSAxLjMzNlptLTIuMzUyIDYuNzU3LS44Ny0uMDY2YTQ4Ljg0NCA0OC44NDQgMCAwIDAtMy43ODItLjEzM2MtMi4yNSAwLTUuMjE5LjEzNy03LjY1Mi43MTEuNDguOTkyLjMzNSAyLjE3Mi0uMzcyIDMuMDJhMTU5LjUxMyAxNTkuNTEzIDAgMCAxLTIuODEyIDMuMjc3YzIuMi0uODkgNC4zOS0xLjgwNSA2LjU2Ni0yLjc0NmEyMTguMTMgMjE4LjEzIDAgMCAwIDguOTE4LTQuMDYzWm0wIDAiIGZpbGw9IiM2NDhjMWEiLz4mI3hhOyAgICA8cGF0aCBkPSJNNjkuNTk0IDI5LjU5NGMtNi4xMTcgMi42NTYtMTkuNTIgNy43NzMtMzEuOTczIDcuNzczLTMuMTU2IDAtNi4yNDYtLjMyOC05LjE0NC0xLjExLjMxNi40NzcuNjE3Ljk2Ni44OTggMS40NjIgMS4wNzggMS44ODMgMS44NjMgMy43NDYgMi4yOTMgNC44NDMgMS41MDguMjM1IDMuNDczLjQyMiA1LjkwMi40MjIgNy4xNTMgMCAxOC4zMzYtMS42MjkgMzMuNjgtOC41MDQuMjkzLS45MjUuNjEzLTEuODQuOTU3LTIuNzQ2LS4wMzEgMC0uMDYyLjAwOC0uMDk0LjAwOC0uMTYgMC0uMzI0LS4wMi0uNDgtLjA1NS0uOTUzLS4yMDctMS42Ni0uOTgtMi4wNC0yLjA5M1ptMCAwIiBmaWxsPSIjZGZjYWEzIi8+JiN4YTsgICAgPHBhdGggZD0iTTE5Ljc5MyA0NS4xMjlhMzIuMTI3IDMyLjEyNyAwIDAgMCAyLjE2NCAzLjM0NGMzLjcwMy0yLjU1NSA4LjU1LTQuMzk5IDguNTUtNC4zOTlzLS4xMjQtLjM2My0uMzU5LS45NmMtLjE0LS4zNi0uMjg5LS43Mi0uNDQxLTEuMDc1YTMyLjQ4MyAzMi40ODMgMCAwIDAtMS4zOS0yLjg5OCAyMy41OTcgMjMuNTk3IDAgMCAwLTEuMjQzLTIuMDdjLTEuNDg0LTIuMjIzLTMuMzctNC4xMTQtNS40ODQtNC4xMTQtLjY2NCAwLTEuMzU2LjE4OC0yLjA1OS42MTMtMy44NzkgMi4zMzYtMS44NzUgNy42ODQuMTE3IDExLjI5Ny4wNDcuMDkuMDk4LjE3Ni4xNDUuMjYyWm0uNTUtNi41MzVjLjAyOC0uMjc4LjEwMi0uNTg2LjI5LS44OTUuMTkxLS4zMTYuNDgtLjU2Mi44MjQtLjcwN2wuMDU5LS4wMjcuMDI3LS4wMTIuMTEtLjAzMS4wNzctLjAyNC4wNzktLjAyYy4wMjctLjAwNy4xMTctLjAxNS4xNzEtLjAyMy4wNjctLjAwMy4xMjUtLjAwNy4xOTItLjAwN2guMDk0bC4wNzQuMDExYy4wOS4wMTIuMTg3LjAzMi4yNzcuMDUxLjM0NC4xMDYuNjEuMjY2Ljg0NC40My40NS4zNDQuNzcuNzE1IDEuMDU1IDEuMDk3LjI4NS4zNzYuNTE1Ljc2Ni43MjIgMS4xNDUuMzY3LjY4OC42NzIgMS40MDIuOTE0IDIuMTQuMTc2LjUyLjMxMyAxLjA1MS40MTQgMS41OS4wNC4xOTIuMDU5LjM1Mi4wNzUuNDU0bC4wMi4xNjRzLS4xNS0uMTc2LS4zODgtLjQ4OWE0MC4yODIgNDAuMjgyIDAgMCAxLS45NTctMS4zYy0uMzgyLS41MzYtLjgyLTEuMTU3LTEuMjkzLTEuNzk3LS4yMzQtLjMyLS40OC0uNjMzLS43MzgtLjk0Mi0uMjU4LS4yOTMtLjUyNy0uNTg2LS43ODktLjc3YTEuMzI0IDEuMzI0IDAgMCAwLS4zMi0uMTg3Yy0uMDItLjAwNC0uMDI4LS4wMDQtLjA0My0uMDExbC0uMDA4LS4wMDRoLjAwOGMuMDEyIDAgLjAyMyAwIC4wMjctLjAwNC4wMDQgMCAuMDM1LS4wMi4wMTItLjAxNmwtLjA4Mi4wMi0uMDQ3LjAwOGEuMzI1LjMyNSAwIDAgMC0uMTQ4LjA4Mi43MzEuNzMxIDAgMCAwLS4xMzcuMjg5Yy0uMDcuMjYxLS4wNy42MjUtLjA1NS45Ni4wMjQuMzQ0LjA3LjY4NC4xMjEuOTk3LjEwMi42MzIuMjIzIDEuMTc1LjI5MyAxLjU2Mi4wNzguMzgzLjEyMS42MS4xMjEuNjFzLS4wNDMtLjA0LS4xMS0uMTIyYy0uMDczLS4wODItLjE3OS0uMTk1LS4zLS4zNTVhOC4zNzUgOC4zNzUgMCAwIDEtLjg5LTEuNDA2IDYuNDAyIDYuNDAyIDAgMCAxLS40MjItMS4wNjNjLS4xMTQtLjQwMi0uMjIzLS44NDctLjE3Mi0xLjM5OFptMS4yNDctNi40NDJ2LjgwNVptMCAwIiBmaWxsPSIjNjdjZmUzIi8+JiN4YTsgICAgPHBhdGggZD0iTTczLjU3NCAyMC42MzdjLjE2NCAwIC4zMjQuMDIuNDg1LjA1IDEuMTg3LjI2NiAxLjk4OCAxLjM5OSAyLjI1NyAyLjk3NyAyLjI1OC0zLjE2IDQuNzMtNC43NjIgNy4zNjQtNC43NjIgMS4xMSAwIDIuMDg2LjI2MiAyLjkwMi43NjYuNzczLS45MzQgMS41MzUtMS44ODMgMi4yNzctMi44NDQtMS4wNDYuMTg4LTMuMjMuNDczLTMuMjMuNDczQzkzLjg5NSAxNC4yNyA5My4yMyA2LjAzNSA5My4yMyA2LjAzNWMwIDEuNDIyLTQuMjc3IDQuODI4LTQuMjc3IDQuODI4LjE5Mi0xLjIzLS40NzMtMi44NC0uNDczLTIuODQuMTg4IDEuNjEtNC45NCA1Ljc3NC00Ljk0IDUuNzc0LjM3OC0uNzU4LjA4OS0yLjA4Mi4wODktMi4wODItLjI4NSAxLjUxMi0yLjU2MyAyLjA4Mi0yLjU2MyAyLjA4MiAxLjQyMi0xLjcwMyA0LjA4Ni0xMC42OTIgMi4wOS0xMS4yNjItMS45OTYtLjU2Ni00Ljc1NCA1Ljg2My00Ljc1NCA1Ljg2My0uMDkzLTEuNTExLS45NDktMS41MTEtLjk0OS0xLjUxMS4zODMgNC43My0zLjQxOCA4LjUxNS0zLjQxOCA4LjUxNS0uMjg1LS45NDUtMS44MDgtMS40MjItMS44MDgtMS40MjIuNDkyIDEuMDU1LS4wNjcgNS44NTItLjIzOSA3LjIwNy41MDQtLjM1MSAxLjA0My0uNTUgMS41ODYtLjU1Wm0wIDAiIGZpbGw9IiNkZmNhYTMiLz4mI3hhOyAgICA8cGF0aCBkPSJNNzEuNTQ3IDI5Ljg0NHYuMDA0Yy4wNDMuMDQ3LjA4Ni4wODYuMTI5LjEyLjAxNS4wMTIuMDMxLjAyLjA0Ny4wMzIuMDMuMDIuMDYyLjA0My4wOTcuMDU5YS42NDEuNjQxIDAgMCAwIC4xNi4wNTguODY0Ljg2NCAwIDAgMCAuMjY2LjAwNGMuMjQ2LS4wMzkuNTItLjE5MS43OTctLjQ0NWE0Mi41MSA0Mi41MSAwIDAgMSAuODA1LTEuNzc0Yy4yNTctLjUyNy41MjMtMS4wNS44MDgtMS41NjYuNDA2LTIuMTQtLjE0NC0zLjg5OC0uOTQ1LTQuMDc0YS41MjUuNTI1IDAgMCAwLS4xMzctLjAxMmMtLjgyNCAwLTIuMDIzIDEuNDI2LTIuNDkyIDMuNTU1LS4zNCAxLjU0My0uMTg0IDIuOTE0LjIxOSAzLjY4bC4wMDQuMDAzYy4wNy4xNC4xNDguMjYyLjIzOC4zNTZabTAgMCIgZmlsbD0iIzAwMCIvPiYjeGE7ICAgIDxwYXRoIGQ9Ik04My43NDIgMjUuODA1aC0uMDEybC4wMDguMDA4LjAxMi4wMDNjLS4wMDQtLjAwMy0uMDA0LS4wMDctLjAwOC0uMDExWm0uMDM1LjAyMy0uMDIzLS4wMDgtLjAwNC0uMDA0di4wMDRsLjAwNC4wMDRjLjAwNC4wMDQuMDA4LjAwNC4wMTIuMDA0Wm0wIDAiIGZpbGw9IiM2N2NmZTMiLz4mI3hhOyAgICA8cGF0aCBkPSJNODMuNjggMjAuNTEyYy00LjcwNyAwLTguMTY4IDcuMDU0LTkuOTggMTEuODQ3YTU2LjY5IDU2LjY5IDAgMCAwLS44ODQgMi41MjRjLS4xNC40MzctLjI3My44NzktLjQwMiAxLjMyLjIyNy4wNDMuNDUuMTI1LjY2LjIyNyAyLjc0Mi0uODE3IDYuMjk3LTEuMDA0IDguOTczLTEuMDA0IDIuMjcgMCAzLjkxLjEzMyAzLjkxLjEzMy43MTUtLjk5NiA0Ljg1Mi0xNS4wNDctMi4yNzctMTUuMDQ3Wm0xLjYyOSA1Ljc3N2E1LjA2MyA1LjA2MyAwIDAgMS0uMzU2IDEuNDM4IDguMzYgOC4zNiAwIDAgMS0uNTIzIDEuMTIgMTEuNzg1IDExLjc4NSAwIDAgMS0xLjAwOCAxLjUwOGMtLjI3NC4zNC0uNDU3LjUxNi0uNDU3LjUxNnMuMDU4LS4yNDIuMTY4LS42NmMuMTAxLS40MTguMjYyLTEuMDA4LjQyMi0xLjcwMy4wODItLjM0NC4xNjgtLjcxOS4yMjYtMS4xMDYuMDc0LS4zNzUuMTA2LS43NTQuMDktMS4xMzYtLjAxMi0uMTY4LS4wNDctLjMyNS0uMDktLjM5OS0uMDA4LS4wMjMtLjAxNS0uMDM1LS4wMjctLjA0M2gtLjAwNGE2NC43NCA2NC43NCAwIDAgMC0uMDEyLS4wMTJsLS4wNjItLjAzLS4yMDMtLjA1NWMtLjA4Ni0uMDI4LS4xNjgtLjAyNC0uMjU0LS4wNDMtLjA4Mi0uMDItLjE2LS4wMDgtLjI0Mi0uMDJhNS41OCA1LjU4IDAgMCAxLS4yMzkuMDI3Yy0uMzE2LjA1MS0uNjMzLjIwNy0uOTQxLjQyNmE1LjMyIDUuMzIgMCAwIDAtLjg2Ny44MzZjLS41MjguNjMzLS45NjUgMS4zMzItMS4zMjggMS45NDItLjM2NC42MTctLjY1NyAxLjE0OC0uODY4IDEuNTIzbC0uMzMyLjU5OHMtLjAwNC0uMDYzIDAtLjE4Yy4wMDQtLjExNy4wMDQtLjI5LjAyOC0uNTA4LjA1LS42MDUuMTUyLTEuMjAzLjMxMi0xLjc4OS4xOTUtLjczLjUtMS41NzQgMS4wMzEtMi40MjJhNS40MzcgNS40MzcgMCAwIDEgMS4wNDMtMS4yMTUgMy41MjYgMy41MjYgMCAwIDEgMS42NTctLjc5N2MuMTYtLjAyMy4zMjQtLjAzNS40ODQtLjAzOS4xNjQuMDA4LjMyOC4wMDguNDg0LjAzNi4xNTMuMDMuMzEzLjA1LjQ1Ny4xMDFsLjIxNS4wNzQuMTA2LjAzNS4wMTUuMDA4aC4wMDhsLjA3NC4wMzUuMDIuMDEyLjAzOS4wMmMuMDMxLjAwNC40MTguMjQyLjUxNi4zOThsLjEwMS4xMzMuMDgyLjEzN2ExLjIgMS4yIDAgMCAxIC4xMTcuMjczYy4xMjEuMzYuMTMzLjY3Ni4xMTguOTYxWm0wIDAiIGZpbGw9IiM2N2NmZTMiLz4mI3hhOyAgICA8cGF0aCBkPSJNNTguNTI3IDUxLjk0MWMuNzc0IDAgMS42MTgtLjIwNyAyLjUxNi0uNjA1IDEuODc5LS44NDQgNi40NTMtNS40MTggMTEuNjY0LTExLjY2LjI3Ny0uMzMyLjMzNi0uNzkzLjE1Mi0xLjE4OGExLjExNCAxLjExNCAwIDAgMC0xLjAxMS0uNjM2IDEuMTE3IDEuMTE3IDAgMCAwLS44NjQuMzk4Yy0yLjI2MSAyLjcxOS04LjYzMiAxMC0xMC44MjQgMTEuMDM1bC0uMDMxLjAyYTQuNzggNC43OCAwIDAgMS0xLjE3Ni4zNjdsLS44MzYuMTMzLS42MS0uNTgyYTEuMTUgMS4xNSAwIDAgMC0uNzczLS4zMDFjLS4yMTQgMC0uNDIyLjA2Mi0uNTk3LjE3NmExLjExIDEuMTEgMCAwIDAtLjM0NCAxLjUzNWMuMDg2LjEzMy44OSAxLjMwOCAyLjczNCAxLjMwOFptLTEwLjYyOS4yNDZjLS4xOCAwLS4zNjMuMDQzLS41MjMuMTI2bC0uMzMyLjE3MS0uMzY3LjAyOGMtLjA5LjAwNC0uMTguMDA0LS4yNy4wMDQtMS4wNDMgMC0zLjYxLS4zMjUtOS4wNjYtMi41Mi02LjAxNi0yLjQxOC04LjQwMy0yLjc4MS05LjI4NS0yLjc4MWExLjY2IDEuNjYgMCAwIDAtLjMxMy4wMiAxLjEwNCAxLjEwNCAwIDAgMC0uOTAyIDEuMjkzIDEuMTMgMS4xMyAwIDAgMCAxLjA5NC45MTdjLjAyMyAwIC4wNDYgMCAuMDctLjAwNGwuMTI1LS4wMDcuMTIxLjAxMWMuNjY0LjA1NSAyLjc5My40MjIgOC4yNTQgMi42MTQgNC40MTQgMS43NzcgNy43NTQgMi42NzUgOS45MyAyLjY3NSAxLjE0NCAwIDEuOTI1LS4yNDYgMi4zMjQtLjcyMmExLjExNCAxLjExNCAwIDAgMC0uMTQ1LTEuNTcgMS4wODMgMS4wODMgMCAwIDAtLjcxNS0uMjU1Wm0wIDAiIGZpbGw9IiMwMDAiLz4mI3hhOyAgICA8cGF0aCBkPSJNNjMuMDA4IDc1LjM2cy0uMzEzIDMuNjcxLTUuNTA4IDQuNDM3Yy0uOTg0LjE0LTEuODI4LjIwNy0yLjU1NS4yMDctMi43NjEgMC0zLjg1MS0uOTA2LTQuNDkyLTEuNjk1IDAgMC00Ljk3NiAxLjY3MS01LjM1NSA0LjUxNS0uMjg1IDIuMTIxIDEuNzcgMy4yMTEgMy41NzggMy4yMTEuNjEgMCAxLjE5MS0uMTI1IDEuNjQ4LS4zNzUgMS44MDktLjk5MiA0LjUxMi0zLjE2OCA4LjEyNS0zLjY0NC4zMjgtLjA0Ljc3OC0uMDU1IDEuMzEzLS4wNTUgMS4yMzQgMCAyLjkyMi4wODIgNC41NTQuMDgyIDEuODU2IDAgMy42NDUtLjEwNiA0LjYzNy0uNTQ3IDIuMjMtLjk5MiAyLjIzLTIuNjk1IDIuMDktMy41NDctLjE2LS45NDEtMi40My0yLjU0My04LjAzNS0yLjU5Wm0wIDAiIGZpbGw9IiNkZmNhYTMiLz4mI3hhOyAgICA8cGF0aCBkPSJtNTYuOTU3IDc4LjM4My4xODQtLjAzMS4yMDMtLjA0M2MyLjcwMy0uNTUxIDQuNjkxLTIuMTA2IDQuNzEtMy42NmExLjg2IDEuODYgMCAwIDAtLjIyMi0uOTAzYy0uNy0xLjI5My0yLjk0NS0yLjAwOC01LjUwNC0xLjY5MWwtLjQxNC4wNThjLTMuMDkuNTEyLTUuMzYzIDIuMzI4LTUuMDc0IDQuMDU5LjAyLjEwMS4wNDMuMi4wNzguMjkzLjUzMSAxLjU1IDMuMTI5IDIuNDAyIDYuMDM5IDEuOTE4Wm0wIDAiIGZpbGw9IiMyMzFmMjAiLz4mI3hhOzwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1170\" y=\"4\" width=\"110\" height=\"110\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-165\" value=\"&lt;b&gt;&lt;font&gt;Ingress&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"871.66\" y=\"-1030\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-175\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-168\" target=\"PG-S5D8SCmHSsYNVxMVk-163\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <Array as=\"points\">\n              <mxPoint x=\"1360\" y=\"-103\" />\n              <mxPoint x=\"1360\" y=\"-103\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-168\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBmaWxsPSIjZTc1MjI1IiBkPSJNNjMuNjYgMi40NzdjMzMuNDc3LjAwNyA2MC45NTcgMjcuMjk2IDYwLjkxNCA2MC41LS4wNDMgMzMuNzAzLTI3LjQxIDYwLjYxNy02MS42MTMgNjAuNTkzLTMzLjQ0MS0uMDIzLTYwLjQ3Ny0yNy4zNDMtNjAuNDUzLTYxLjA4NkMyLjUzIDI5LjQ4OCAzMC4wNjYgMi40NyA2My42NiAyLjQ3N3ptLTE4LjUwNCAyMS4yNWMuNzY2IDMuNzc3LjAyNCA3LjMtMS4xMTMgMTAuNzY1LS43ODUgMi4zOTktMS44NzEgNC43MTEtMi41MiA3LjE0NS0xLjA3IDQuMDA4LTIuMjggOC4wMzktMi43MjYgMTIuMTM2LS42NCA1Ljg5NSAxLjY3NiAxMS4wODYgNS42NCAxNi4yNWwtMTguMjIyLTMuODM1Yy4wMzEuNTc0IDAgLjc5Mi4wNjIuOTc2IDEuNzI3IDUuMDc0IDQuNzY2IDkuMzQ4IDguMTcyIDEzLjM3OS4zNi40MjYgMS4xOC42NDQgMS43OS42NDQgMTguMTY3LjAzNiAzNi4zMzUuMDMyIDU0LjUwMy4wMDguNTYzIDAgMS4zMTctLjEwNSAxLjY2LS40NjggMy44OTUtNC4wOTQgNi44NzEtOC43NTggOC43MzUtMTQuNjNsLTE5LjI5IDMuNzc4YzEuMjc0LTIuNDk2IDIuNzIzLTQuNjg4IDMuNTYtNy4wOTggMi44NTUtOC4yNDIgMS42NzEtMTYuMjEtMi40MjctMjMuNzI2LTMuMjg5LTYuMDMxLTYuMzI0LTEyLjAzNS00LjY4My0xOS4zMDUtMy40NzMgMy40MzQtNC44MDkgNy44LTUuNjU2IDEyLjMtLjgzMiA0LjQzNC0xLjMyNSA4LjkzLTEuOTcgMTMuNDMtLjA5My0uMTM2LS4yMS0uMjM4LS4yMy0uMzU1YTEzLjMxNyAxMy4zMTcgMCAwMS0uMTY4LTEuNDIyYy0uMzk0LTcuMzY3LTEuODMyLTE0LjQ2NS00Ljg3LTIxLjI0Ni0xLjc4Ni0zLjk4OC0zLjc1OC04LjA3LTEuOTE1LTEyLjgzMi0xLjI0Ni42Ni0yLjM3NSAxLjMxMy0zLjE4MyAyLjI0Ni0yLjQxIDIuNzg1LTMuNDA3IDYuMTMtMy42NjQgOS43OTMtLjIyIDMuMTMtLjUyIDYuMjc0LTEuMTAyIDkuMzUyLS42MSAzLjIzNC0xLjU3NCA2LjQwMi0zLjc1IDkuMzc1LS44NzUtNi4zNDgtLjk3My0xMi42My02LjYzMy0xNi42NnpNOTIgODYuNzVIMzUuMDE2djkuODk4SDkyem0tNDUuNjg0IDE1LjAxNmMtLjA0NiA4LjI0MiA4LjM0OCAxNC4zODIgMTguNzIzIDEzLjkzNyA4LjYwMi0uMzcxIDE2LjIxMS03LjEzNyAxNS41NTktMTMuOTM3em0wIDAiLz48L3N2Zz4=;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"-140\" width=\"80\" height=\"80\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-169\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZS1taXRlcmxpbWl0PSIxLjQxNCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHBhdGggZD0iTTMuODUgMi4yNzNjLjI4Ni0uMTY3LjU4My0uMzE1Ljg5My0uNDQ0LjY1NS0uMjggMS4zMy0uNDQgMi4wMjQtLjUxbC43NTIuODUtLjM1Ljg4Yy0uNjguMTMtMS4zMi4zOC0xLjkyLjc0bC0uMTMuMDhMNSAyLjcxbC0xLjE1LS40NHoiIGZpbGw9IiM1QUI1NTIiLz48cGF0aCBkPSJNMy41MjMgMi40OGwxLjE5NC40Ni4xMjUgMS4xNGMtLjY0Ni40NzUtMS4xNSAxLjA4Mi0xLjUxIDEuODItLjAzNC4wNjYtLjA2NC4xMzItLjA5My4yTDIuNCA1LjA4bC0xLjM3LjI5Yy4zNC0uNzM2LjgtMS4zOTQgMS4zNzUtMS45NzQuMzQ0LS4zNDcuNzE0LS42NTIgMS4xMTItLjkxN3ptNy44NTcgOC4wMzZjLjEzLS4yMTYuMjM1LS40MzUuMzItLjY2bDEuMjkyIDEuNTY3IDIuMTctLjQ2OGMtLjEyNC4zNDItLjI3Mi42NzctLjQ0MiAxLjAwNS0uNDQ2Ljg2LTEuMDM0IDEuNjA2LTEuNzY1IDIuMjQtLjc0Mi42NDItMS41OCAxLjExLTIuNTE1IDEuNDA2LS4wMTguMDA2LS4wMzcuMDEtLjA1NS4wMTdsLTEuNjA4LTEuMzYuNDItMS44NS4wMzMtLjAxNGMuOTItLjQgMS42MzgtMS4wMiAyLjE1LTEuODl6IiBmaWxsPSIjNUFCNTUyIi8+PHBhdGggZD0iTTE0LjA5NyAzLjJjLjEzMy4xODMuMjU3LjM3My4zNzUuNTcuNDk1LjgzMi44MzcgMS43MjIgMS4wMjcgMi42Ny4xOC45NC4yMSAxLjg4Ni4wOCAyLjgzNS0uMDcuNDU2LS4xNy45LS4zMSAxLjMzNWwtMi4xNy40NjYtMS4zLTEuNTcyYy4xNS0uNTc4LjE3LTEuMTguMDQtMS44MDYtLjE1LS43NDMtLjQ4LTEuMzc3LS45Ny0xLjlsMi4zNC0uMjguODctMi4zMTh6TS44ODUgNS43MmwxLjQtLjI5Ni44MjQgMS4wMDZjLS4yNi43MjMtLjMyIDEuNDc0LS4xOSAyLjI1NC4wMy4yMjIuMDguNDM3LjE0LjY0NmwtMS40OC0uMzM3LTEuMDYgMS4yNTRDLjM5IDkuNjkyLjMzIDkuMTI0LjMzIDguNTQ0Yy4wMDItLjk2Ny4xOC0xLjkuNTM4LTIuOGwuMDEtLjAyNXoiIGZpbGw9IiM1QUI1NTIiLz48cGF0aCBkPSJNMy4xOCA5LjY3N2MuMjEzLjU2Mi41MjYgMS4wNzYuOTQgMS41NDQuMzEuMzYuNjYuNjUgMS4wNDIuODhsLTEuNDY3Ljg0LjA4IDEuOTFjLS40ODQtLjMtLjkzLS42Ni0xLjMzNC0xLjA3LS42OC0uNy0xLjItMS41LTEuNTYtMi40LS4xLS4yNS0uMTgtLjUtLjI1LS43NWwxLjA5LTEuMjggMS40OC4zNHoiIGZpbGw9IiM1QUI1NTIiLz48cGF0aCBkPSJNNS40ODIgMTIuMjc2Yy4zMTUuMTU3LjY1My4yNzcgMS4wMTIuMzYuODA1LjE4NiAxLjU5LjE1NSAyLjM1My0uMDk0TDguNDMgMTQuMzhsMS41OTIgMS4zNDdjLS43OTYuMjA4LTEuNjEuMjk3LTIuNDQuMjY3LS45Ny0uMDMtMS45MDItLjIzNi0yLjc5NC0uNjE2LS4yNC0uMTAyLS40Ny0uMjE1LS42OTQtLjM0bC0uMDgtMS45MjIgMS40NjgtLjg0em04LjM5LTkuMzdsLS44NzUgMi4zMjUtMi40MS4yOWMtLjA3LS4wNi0uMTQyLS4xMi0uMjE4LS4xNy0uNzktLjYtMS42OC0uOTUtMi42Ny0xLjA1LS4yMy0uMDItLjQ1LS4wMi0uNjYtLjAybC44NC0yLjE1TDYuMDYuMDZDNi42MTIgMCA3LjE1Mi0uMDEgNy43IDBjLjMyNy4wMS42NS4wMzQuOTczLjA3NS40NTMuMDYuOS4xNiAxLjM0My4yOC45MzcuMjY3IDEuNzkuNjkgMi41NjIgMS4yODcuNDg2LjM3My45MTguNzk1IDEuMjk1IDEuMjY1eiIgZmlsbD0iIzVBQjU1MiIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1597\" y=\"-718\" width=\"58\" height=\"58\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-180\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;shadow=0;dashed=1;dashPattern=8 8;strokeColor=#23445d;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;fillColor=#bac8d3;exitX=0.5;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-170\" target=\"PG-S5D8SCmHSsYNVxMVk-163\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <Array as=\"points\">\n              <mxPoint x=\"1402\" y=\"-92\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-170\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZmlsbD0iI2ZlNzEzOSIgZD0ibTEwMC45MTc5NjkgMTEuMTY3OTY5YzIuMzAwNzgxIDMuMzc4OTA2IDQuMzcxMDkzIDYuOTE3OTY5IDYuNSAxMC40MTAxNTYgMi40MDIzNDMgNC4wNzAzMTMgNS4xMzI4MTIgNy44Mzk4NDQgNy4zNzEwOTMgMTEuOTk2MDk0IDIuMjMwNDY5IDQuMTg3NSA0LjkxNzk2OSA3Ljk2MDkzNyA3LjM2NzE4OCAxMi4wMTU2MjUgMi42Njc5NjkgNC42MDE1NjIgNS43MDcwMzEgOC45NzY1NjIgOC4yNDIxODggMTMuNjQ0NTMxIDQuMDI3MzQzIDYuNzY5NTMxIDguMzYzMjgxIDEzLjMzOTg0NCAxMi40MDIzNDMgMjAuMTAxNTYzIDIuNDI5Njg4IDQuNTUwNzgxIDUuNDI1NzgxIDguNzYxNzE4IDguMDExNzE5IDEzLjIyMjY1NiAyLjQ5MjE4OCA0LjM2MzI4MSA1LjUxMTcxOSA4LjM1MTU2MiA3Ljc4OTA2MiAxMi44Mzk4NDQgNC42NzE4NzYgNy44MDA3ODEgOS42ODc1IDE1LjM5NDUzMSAxNC4yNjU2MjYgMjMuMjYxNzE4IDQuNDU3MDMxIDcuNjQ0NTMyIDkuMzYzMjgxIDE1IDEzLjg4MjgxMiAyMi42MDU0NjktMy4yMTA5MzggMS40MzM1OTQtNi4zMDA3ODEgMy4xMzI4MTMtOS41MzEyNSA0LjUxMTcxOS0zLjY0ODQzOCAxLjQ1NzAzMS03LjAxOTUzMSAzLjQ4ODI4MS0xMC42MDE1NjIgNS4xMDkzNzUtNi45MjE4NzYgMy4yMzQzNzUtMTMuNjM2NzE5IDYuOTcyNjU2LTIwLjY2MDE1NyA5Ljk2MDkzNy04LjY2Nzk2OSA0LjIxODc1LTE3LjI5Mjk2OSA4LjU1MDc4Mi0yNS45NjQ4NDMgMTIuNzUtNC43NSAxLjk5MjE4OC05LjI0MjE4OCA0LjQ5MjE4OC0xMy45MjE4NzYgNi42NDg0MzgtLjAwNzgxMi0zNC4xMjg5MDYtLjA3MDMxMi02OC4yODEyNS4wMzEyNS0xMDIuNDEwMTU2IDIuNTExNzE5IDQuMzc4OTA2IDQuODk4NDM4IDguODMyMDMxIDcuNSAxMy4xNjc5NjggMS45NDE0MDcgMy44NTU0NjkgMy45NTMxMjYgNy42NjQwNjMgNi4xNDg0MzggMTEuMzg2NzE5IDIuOTg4MjgxIDQuOTgwNDY5IDUuNjMyODEyIDEwLjE1NjI1IDguNjAxNTYyIDE1LjE1NjI1IDEuNDUzMTI2IDIuNzc3MzQ0IDIuODQzNzUgNS41ODk4NDQgNC40NDE0MDcgOC4yODkwNjMtMy43MzgyODEgMS44NzUtNy4yMTA5MzggNC4wMjM0MzctMTEuMDU0Njg4IDUuNzEwOTM3LTIuMDc0MjE5LjkwMjM0NC00LjA3NDIxOSAxLjk1NzAzMS02LjA2MjUgMy4wNDI5NjktLjAyNzM0MyAzLjk4ODI4MS0uMDM5MDYyIDcuOTg0Mzc1LjAxMTcxOSAxMS45NzY1NjIgNy40OTIxODgtMi44MTI1IDE0LjY0NDUzMS02LjU0Mjk2OCAyMi4wMDc4MTItOS42ODc1IDQuMjUzOTA3LTEuNzkyOTY4IDguMzA0Njg4LTMuOTY4NzUgMTIuNjI1LTUuNjAxNTYyLTIuNTkzNzUtNC4xMzY3MTktNS4yMjY1NjItOC4yMzQzNzUtNy41NzAzMTItMTIuNTE1NjI1LTMuNTQyOTY5LTUuNDU3MDMxLTYuNzczNDM4LTExLjEwOTM3NS0xMC4zNTU0NjktMTYuNTQ2ODc1LTIuMzQzNzUtMy41NTQ2ODgtNC4yMTQ4NDMtNy4zNzg5MDYtNi41MzEyNS0xMC45NjA5MzgtMy42OTkyMTktNS43MDcwMzEtNy4yMzA0NjktMTEuNTE5NTMxLTEwLjc3NzM0My0xNy4zMjQyMTgtNC42NjAxNTctOC4wODk4NDQtOS44NjcxODgtMTUuNzg5MDYzLTE0LjY0ODQzOC0yMy43OTI5NjktMi4yMzgyODEgMy40Njg3NS00LjI2MTcxOSA3LjA2NjQwNi02LjU0Mjk2OSAxMC41MTE3MTktNC41NTg1OTMgNy4xNjc5NjgtOC43NjE3MTkgMTQuNTMxMjUtMTMuMjYxNzE5IDIxLjczMDQ2OC0yLjkzMzU5MyA1LjAxMTcxOS02LjI4MTI1IDkuNjQ4NDM4LTkuMDE1NjI0IDE0Ljc2OTUzMi0xLjQ0MTQwNyAyLjY3NTc4MS0zLjEzNjcxOSA1LjE1NjI1LTQuNzUzOTA3IDcuNzE4NzUtMi44OTQ1MzEgNC42MTcxODctNS42NTYyNSA5LjMxNjQwNi04LjYwNTQ2OSAxMy44OTg0MzctMi4yNzczNDMgNC4xMzI4MTMtNC43ODkwNjIgOC4xMTMyODEtNy4yNjk1MzEgMTIuMTIxMDk0IDIuMzQzNzUuNzgxMjUgNC41MzUxNTcgMS43NSA2LjcxODc1IDIuODk4NDM3IDUuNDY4NzUgMi42Nzk2ODggMTEuMDUwNzgxIDUuMTA1NDY5IDE2LjQ4MDQ2OSA3Ljg1NTQ2OSAzLjY0NDUzMSAxLjYzNjcxOSA3LjE1NjI1IDMuNTc0MjE5IDEwLjkxNzk2OSA0LjgzOTg0NC4zMTI1LTMuOTQ1MzEzLjQ4ODI4MS03Ljg5MDYyNS42MDU0NjktMTEuODQzNzUtMS44OTA2MjYtMS4wODk4NDQtMy44MjQyMTktMi4xMDkzNzUtNS44MjQyMTktMi45ODgyODEtMy45MjU3ODEtMS43NS03LjQ4ODI4MS0zLjg1MTU2My0xMS4yODUxNTctNS44MzIwMzIgNS4xOTE0MDctOS43MzgyODEgMTAuNjM2NzE5LTE5LjI0MjE4NyAxNi4wOTM3NS0yOC44MzU5MzcgMy4yMTA5MzgtNi40ODQzNzUgNi45OTIxODgtMTIuNjcxODc1IDEwLjUzMTI1LTE4Ljk3NjU2My0uMDYyNSA1LjM3NS4wNzgxMjYgMTAuNzQyMTg4LjAxMTcxOSAxNi4xMTcxODgtLjE4MzU5MyAyOC43MTQ4NDQtLjIyNjU2MiA1Ny40MjE4NzUtLjUwNzgxMiA4Ni4xMzI4MTItMy4xNjc5NjktMS41MzEyNS02LjMzMjAzMS0zLjA3MDMxMi05LjQ2ODc1LTQuNjU2MjUtNS4zMTI1LTIuMjU3ODEyLTEwLjUwMzkwNy00Ljg1MTU2Mi0xNS42NDg0MzgtNy40Njg3NS00LjYyMTA5My0yLjI1NzgxMi05LjMwMDc4MS00LjM2NzE4Ny0xMy44NTU0NjktNi43NTc4MTItOC4zNTkzNzQtMy41MTU2MjUtMTYuMjgxMjUtNy45MDYyNS0yNC41MjczNDMtMTEuNzEwOTM4LTUuNDE3OTY5LTIuOTE0MDYyLTExLjE2Nzk2OS01LjA0Mjk2OC0xNi42MTMyODEtNy45MTQwNjIgMy43NTc4MTItNi4xNDA2MjUgNy42NzU3ODEtMTIuMTcxODc1IDExLjQxNDA2Mi0xOC4zMjgxMjUgNC42MDE1NjItNy44Mzk4NDQgOS4zOTQ1MzEtMTUuNTgyMDMxIDE0LjI4MTI1LTIzLjI0NjA5NCAyLjA1NDY4OC0zLjE5OTIxOSAzLjY5NTMxMi02LjYyNSA1Ljc5Mjk2OS05LjgwMDc4MSAzLjU3NDIxOS01LjQ0MTQwNiA2LjgxMjUtMTEuMDg1OTM4IDEwLjMzMjAzMS0xNi41NjY0MDYgNC40NjA5MzgtNy45NDUzMTMgOS41MzkwNjItMTUuNDQ1MzEzIDE0LjIxODc1LTIzLjI0NjA5NCAyLjY2Nzk2OS00Ljk1MzEyNSA1LjkyOTY4OC05LjU0Mjk2OSA4Ljc0MjE4OC0xNC40MjE4NzUgMS44OTA2MjQtMy4yNzczNDQgNC4xNTYyNS02LjMxMjUgNi05LjYxMzI4MSAyLjM1MTU2Mi00LjQwNjI1IDUuMTEzMjgxLTguNjA1NDY5IDcuODA4NTkzLTEyLjgwODU5NCAyLjU1MDc4MS00LjE5MTQwNiA1LjA4NTkzOC04LjM5ODQzOCA3LjcxMDkzOC0xMi41NDY4NzV6bTAgMCIvPjwvc3ZnPg==;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1351\" y=\"-4\" width=\"104\" height=\"104\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-24\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-172\" target=\"PG-S5D8SCmHSsYNVxMVk-161\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <Array as=\"points\">\n              <mxPoint x=\"1340\" y=\"-290\" />\n              <mxPoint x=\"1340\" y=\"-290\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-172\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIG1lZXQiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiBoZWlnaHQ9IjgwMHB4IiB3aWR0aD0iODAwcHgiPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0yNTUuOTYgMTM0LjM5M2MwLTIxLjUyMS0xMy4zNzMtNDAuMTE3LTMzLjIyMy00Ny40M2E3NS4yMzkgNzUuMjM5IDAgMCAwIDEuMjUzLTEzLjc5MWMwLTM5LjkwOS0zMi4zODYtNzIuMjk1LTcyLjI5NS03Mi4yOTUtMjMuMTkzIDAtNDQuOTIzIDExLjA3NC01OC41MDUgMzAuMDg4LTYuNjg2LTUuMjI0LTE0LjgzNS03Ljk0LTIzLjQwMi03Ljk0LTIxLjEwNCAwLTM4LjQ0NiAxNy4xMzMtMzguNDQ2IDM4LjQ0NiAwIDQuNTk3LjgzNiA5LjE5NCAyLjI5OCAxMy4zNzNDMTMuNTgyIDgxLjczOSAwIDEwMC45NjIgMCAxMjIuMjc0YzAgMjEuNTIyIDEzLjM3MyA0MC4zMjcgMzMuNDMxIDQ3LjY0LS44MzUgNC4zODgtMS4yNTMgOC45ODUtMS4yNTMgMTMuNzkgMCAzOS43IDMyLjM4NiA3Mi4wODcgNzIuMDg2IDcyLjA4NyAyMy40MDIgMCA0NC45MjQtMTEuMjgzIDU4LjUwNS0zMC4wODggNi42ODYgNS4yMjMgMTUuMDQ0IDguMTQ5IDIzLjYxMSA4LjE0OSAyMS4xMDQgMCAzOC40NDYtMTcuMTM0IDM4LjQ0Ni0zOC40NDYgMC00LjU5Ny0uODM2LTkuMTk0LTIuMjk4LTEzLjM3MyAxOS42NC03LjEwNCAzMy40MzEtMjYuMzI3IDMzLjQzMS00Ny42NHoiLz48cGF0aCBmaWxsPSIjRjRCRDE5IiBkPSJNMTAwLjA4NSAxMTAuMzY0bDU3LjA0MyAyNi4xMTkgNTcuNjY5LTUwLjU2NWE2NC4zMTIgNjQuMzEyIDAgMCAwIDEuMjUzLTEyLjc0NmMwLTM1LjUyLTI4LjgzNC02NC4zNTUtNjQuMzU1LTY0LjM1NS0yMS4zMTMgMC00MS4xNjIgMTAuNDQ3LTUzLjA3MiAyNy45OThsLTkuNjEyIDQ5LjczIDExLjA3NCAyMy44MnoiLz48cGF0aCBmaWxsPSIjM0NCRUIxIiBkPSJNNDAuOTUzIDE3MC43NWMtLjgzNSA0LjE3OS0xLjI1MyA4LjU2Ny0xLjI1MyAxMi45NTUgMCAzNS41MiAyOS4wNDMgNjQuNTY0IDY0LjU2NCA2NC41NjQgMjEuNTIyIDAgNDEuMzcyLTEwLjY1NiA1My40OS0yOC4yMDhsOS40MDMtNDkuNzI5LTEyLjc0Ni0yNC4yMzgtNTcuMjUxLTI2LjExOC01Ni4yMDcgNTAuNzc0eiIvPjxwYXRoIGZpbGw9IiNFOTQ3OEMiIGQ9Ik00MC41MzYgNzEuOTE4bDM5LjA3MyA5LjE5NCA4Ljc3NS00NC41MDZjLTUuNDMyLTQuMTc5LTExLjkxLTYuMjY4LTE4LjgwNS02LjI2OC0xNi45MjUgMC0zMC45MjQgMTMuNzktMzAuOTI0IDMwLjkyNCAwIDMuNTUyLjYyNyA3LjMxMyAxLjg4IDEwLjY1NnoiLz48cGF0aCBmaWxsPSIjMkM0NThGIiBkPSJNMzcuMTkyIDgxLjMyYy0xNy41NTEgNS42NDItMjkuNjcgMjIuNTY3LTI5LjY3IDQwLjk1NCAwIDE3Ljk3IDExLjA3NCAzNC4wNTkgMjcuNzkgNDAuMzI3bDU0Ljk1My00OS43My0xMC4wMy0yMS41Mi00My4wNDMtMTAuMDN6Ii8+PHBhdGggZmlsbD0iIzk1QzYzRCIgZD0iTTE2Ny43ODQgMjE5Ljg1MmM1LjQzMiA0LjE4IDExLjkxIDYuNDc4IDE4LjU5NiA2LjQ3OCAxNi45MjUgMCAzMC45MjQtMTMuNzkgMzAuOTI0LTMwLjkyNCAwLTMuNzYxLS42MjctNy4zMTQtMS44OC0xMC42NTdsLTM5LjA3My05LjE5My04LjU2NyA0NC4yOTZ6Ii8+PHBhdGggZmlsbD0iIzE3NjY1NSIgZD0iTTE3NS43MjQgMTY1LjMxN2w0My4wNDMgMTAuMDNjMTcuNTUxLTUuODUgMjkuNjctMjIuNTY2IDI5LjY3LTQwLjk1NCAwLTE3Ljk3LTExLjA3NC0zMy44NDktMjcuNzktNDAuMzI2bC01Ni40MTUgNDkuMzExIDExLjQ5MiAyMS45NHoiLz48L3N2Zz4=;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1174\" y=\"-329\" width=\"79\" height=\"79\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-183\" value=\"&lt;b&gt;OBSERVABILITY&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=15;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1210\" y=\"-370\" width=\"188\" height=\"20\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"PG-S5D8SCmHSsYNVxMVk-184\" value=\"\" style=\"image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/monitor/SAP_Azure_Monitor.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1169\" y=\"-374\" width=\"37.5\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"0iA1YntF7toAf9QrZkA3-6\" value=\"&lt;b&gt;&lt;font&gt;Inbox&lt;/font&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;&lt;font&gt;Processor&lt;/font&gt;&lt;/b&gt;&lt;/div&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"98\" y=\"-239\" width=\"145\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-14\" value=\"&lt;b&gt;&lt;font&gt;Kibana&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1360\" y=\"-250\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-15\" value=\"&lt;b&gt;&lt;font&gt;Loki&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1529\" y=\"-250\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-16\" value=\"&lt;b&gt;Prometheus&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"-60\" width=\"85\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-17\" value=\"&lt;b&gt;Grafana&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1613\" y=\"-70\" width=\"85\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-18\" value=\"&lt;b&gt;Tempo&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1550\" y=\"105\" width=\"85\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-21\" value=\"&lt;b&gt;Zipkin&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1366.25\" y=\"105\" width=\"85\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-22\" value=\"&lt;b&gt;Jaeger&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1180\" y=\"105\" width=\"85\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-13\" value=\"&lt;b&gt;&lt;font&gt;Elastic&lt;/font&gt;&lt;/b&gt;\" style=\"text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontFamily=Comic Sans MS;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"1178.5\" y=\"-250\" width=\"70\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"npFnTr0Nz-ztX7RqOmGq-26\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.008;entryY=0.333;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;\" parent=\"1\" source=\"PG-S5D8SCmHSsYNVxMVk-172\" target=\"PG-S5D8SCmHSsYNVxMVk-163\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <Array as=\"points\">\n              <mxPoint x=\"1214\" y=\"-210\" />\n              <mxPoint x=\"1340\" y=\"-210\" />\n              <mxPoint x=\"1340\" y=\"-129\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"7DCv9Lc5Xf6xtuzZQ5PP-6\" style=\"edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#d79b00;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=none;endFill=0;endSize=8;flowAnimation=0;fillColor=#ffe6cc;startArrow=open;startFill=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"390\" y=\"-126.59\" as=\"targetPoint\" />\n            <mxPoint x=\"610\" y=\"-126.59\" as=\"sourcePoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"9mUb7co-KRWEO0rwhaxW-1\" value=\"\" style=\"shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;image=data:image/png,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQF706fP/A5hinewUUnz6AAAAAElFTkSuQmCC;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"41.07\" y=\"-1170\" width=\"228.93\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n      </root>\n    </mxGraphModel>\n  </diagram>\n</mxfile>\n"
  },
  {
    "path": "assets/vertical-slice-architecture.excalidraw",
    "content": "{\n  \"type\": \"excalidraw\",\n  \"version\": 2,\n  \"source\": \"https://excalidraw.com\",\n  \"elements\": [\n    {\n      \"type\": \"rectangle\",\n      \"version\": 242,\n      \"versionNonce\": 1509780320,\n      \"isDeleted\": false,\n      \"id\": \"80OGzNPG6Gk8NAvbV3XaF\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 648,\n      \"y\": 187,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#a8bffe\",\n      \"width\": 538,\n      \"height\": 62,\n      \"seed\": 246982778,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [\n        {\n          \"type\": \"text\",\n          \"id\": \"46GLDhDwmnc8RGy3v8OK8\"\n        }\n      ],\n      \"updated\": 1679316672934,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 137,\n      \"versionNonce\": 703919968,\n      \"isDeleted\": false,\n      \"id\": \"46GLDhDwmnc8RGy3v8OK8\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 897.848014831543,\n      \"y\": 201.2,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 38.30397033691406,\n      \"height\": 33.6,\n      \"seed\": 2080176422,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949309,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Api\",\n      \"textAlign\": \"center\",\n      \"verticalAlign\": \"middle\",\n      \"containerId\": \"80OGzNPG6Gk8NAvbV3XaF\",\n      \"originalText\": \"Api\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 358,\n      \"versionNonce\": 356515488,\n      \"isDeleted\": false,\n      \"id\": \"nZuYK7wbLObwRvpRRLHay\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 648,\n      \"y\": 263,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#fea8d5\",\n      \"width\": 538,\n      \"height\": 62,\n      \"seed\": 287502970,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [\n        {\n          \"type\": \"text\",\n          \"id\": \"OALII-DXtatRPgn_EkHfp\"\n        }\n      ],\n      \"updated\": 1679316735759,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 246,\n      \"versionNonce\": 1126108000,\n      \"isDeleted\": false,\n      \"id\": \"OALII-DXtatRPgn_EkHfp\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 845.628044128418,\n      \"y\": 277.2,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 142.74391174316406,\n      \"height\": 33.6,\n      \"seed\": 1016531494,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949309,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Application\",\n      \"textAlign\": \"center\",\n      \"verticalAlign\": \"middle\",\n      \"containerId\": \"nZuYK7wbLObwRvpRRLHay\",\n      \"originalText\": \"Application\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 282,\n      \"versionNonce\": 787808928,\n      \"isDeleted\": false,\n      \"id\": \"za_4vz64MSfPF5TWmD7wj\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 650,\n      \"y\": 338,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#f30358\",\n      \"width\": 538,\n      \"height\": 62,\n      \"seed\": 676018342,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [\n        {\n          \"type\": \"text\",\n          \"id\": \"6CqYCSOKHqhqJ8nf4b-Sv\"\n        }\n      ],\n      \"updated\": 1679316783390,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 189,\n      \"versionNonce\": 1441177440,\n      \"isDeleted\": false,\n      \"id\": \"6CqYCSOKHqhqJ8nf4b-Sv\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 816.618049621582,\n      \"y\": 352.2,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 204.76390075683594,\n      \"height\": 33.6,\n      \"seed\": 1067355322,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949309,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Infrastructure\",\n      \"textAlign\": \"center\",\n      \"verticalAlign\": \"middle\",\n      \"containerId\": \"za_4vz64MSfPF5TWmD7wj\",\n      \"originalText\": \"Infrastructure\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 326,\n      \"versionNonce\": 1669046112,\n      \"isDeleted\": false,\n      \"id\": \"t2sZwLLvmq3y2ndIbEomB\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 70,\n      \"angle\": 0,\n      \"x\": 648,\n      \"y\": 413,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#9d9ca2\",\n      \"width\": 538,\n      \"height\": 62,\n      \"seed\": 1173221990,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [\n        {\n          \"type\": \"text\",\n          \"id\": \"b3wdaWjaVmgHpzMD26uKD\"\n        }\n      ],\n      \"updated\": 1679316844215,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 224,\n      \"versionNonce\": 1385935712,\n      \"isDeleted\": false,\n      \"id\": \"b3wdaWjaVmgHpzMD26uKD\",\n      \"fillStyle\": \"hachure\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 70,\n      \"angle\": 0,\n      \"x\": 886.5500106811523,\n      \"y\": 427.2,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"transparent\",\n      \"width\": 60.89997863769531,\n      \"height\": 33.6,\n      \"seed\": 1307397882,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949310,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Core\",\n      \"textAlign\": \"center\",\n      \"verticalAlign\": \"middle\",\n      \"containerId\": \"t2sZwLLvmq3y2ndIbEomB\",\n      \"originalText\": \"Core\"\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 202,\n      \"versionNonce\": 1461187232,\n      \"isDeleted\": false,\n      \"id\": \"FQZImjU2-VUOATU9Yeyly\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 678,\n      \"y\": 154,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#fefda8\",\n      \"width\": 48,\n      \"height\": 361,\n      \"seed\": 1254939642,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [],\n      \"updated\": 1679316609154,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"rectangle\",\n      \"version\": 249,\n      \"versionNonce\": 1540775776,\n      \"isDeleted\": false,\n      \"id\": \"_Vw9EnXAyzxRDEzXCTfeL\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 0,\n      \"x\": 742,\n      \"y\": 153.5,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#fefda8\",\n      \"width\": 48,\n      \"height\": 361,\n      \"seed\": 523058342,\n      \"groupIds\": [],\n      \"roundness\": {\n        \"type\": 3\n      },\n      \"boundElements\": [],\n      \"updated\": 1679316594766,\n      \"link\": null,\n      \"locked\": false\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 249,\n      \"versionNonce\": 871687840,\n      \"isDeleted\": false,\n      \"id\": \"hyJiOwPt7LFndn5R0xgfL\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 100,\n      \"angle\": 4.707547804955119,\n      \"x\": 637.1248451774691,\n      \"y\": 317.9455509364301,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#f9e79f\",\n      \"width\": 130.73194885253906,\n      \"height\": 33.6,\n      \"seed\": 678740006,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315961675,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Feature 1\",\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\",\n      \"containerId\": null,\n      \"originalText\": \"Feature 1\"\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 182,\n      \"versionNonce\": 1494113120,\n      \"isDeleted\": false,\n      \"id\": \"7KOHd5JA_wVMmwXPVT1N3\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 80,\n      \"angle\": 4.7123889803846915,\n      \"x\": 695.6880416870117,\n      \"y\": 313.20000000000005,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#f9e79f\",\n      \"width\": 143.07994079589844,\n      \"height\": 33.6,\n      \"seed\": 1387191482,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949310,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Feature 2\",\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\",\n      \"containerId\": null,\n      \"originalText\": \"Feature 2\"\n    },\n    {\n      \"type\": \"text\",\n      \"version\": 163,\n      \"versionNonce\": 1243581088,\n      \"isDeleted\": false,\n      \"id\": \"SuFNrbzZGowiIybusnadN\",\n      \"fillStyle\": \"solid\",\n      \"strokeWidth\": 1,\n      \"strokeStyle\": \"solid\",\n      \"roughness\": 1,\n      \"opacity\": 70,\n      \"angle\": 0,\n      \"x\": 748,\n      \"y\": 96,\n      \"strokeColor\": \"#000000\",\n      \"backgroundColor\": \"#f9e79f\",\n      \"width\": 360.47186279296875,\n      \"height\": 33.6,\n      \"seed\": 2006173690,\n      \"groupIds\": [],\n      \"roundness\": null,\n      \"boundElements\": [],\n      \"updated\": 1679315949310,\n      \"link\": null,\n      \"locked\": false,\n      \"fontSize\": 28,\n      \"fontFamily\": 1,\n      \"text\": \"Vertical Slice Architecture\",\n      \"textAlign\": \"left\",\n      \"verticalAlign\": \"top\",\n      \"containerId\": null,\n      \"originalText\": \"Vertical Slice Architecture\"\n    }\n  ],\n  \"appState\": {\n    \"gridSize\": null,\n    \"viewBackgroundColor\": \"#ffffff\"\n  },\n  \"files\": {}\n}"
  },
  {
    "path": "booking-microservices.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{CD4A4407-C3B0-422D-BB8C-2A810CED9938}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"ApiGateway\", \"ApiGateway\", \"{CDFA86FA-BBBA-4A5B-A833-3BE219E373E5}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Services\", \"Services\", \"{B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"BuildingBlocks\", \"BuildingBlocks\", \"{C734CEF7-A2AC-3076-84D8-694B7490AA9D}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Flight\", \"Flight\", \"{A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Booking\", \"Booking\", \"{C6034A5C-F49A-5FA4-86A6-65B2CB19613F}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Passenger\", \"Passenger\", \"{9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Identity\", \"Identity\", \"{B465D535-05D9-3A0A-08BF-35A1C18CEC46}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{A2834164-BF04-BF13-ADC5-A97145852861}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{1B4FBE3A-43F5-1B1E-2877-3036AC5431EF}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{773BFBD8-04CD-79F8-8301-C81308C3ED45}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{4B043475-1AFA-C467-FE09-A46D09CD6936}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{5CED3889-AECF-A6CD-55DC-F680D3C18861}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tests\", \"tests\", \"{54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Booking.Api\", \"src\\Services\\Booking\\src\\Booking.Api\\Booking.Api.csproj\", \"{D3BF565A-C413-4185-9528-BE1B4F46993C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Booking\", \"src\\Services\\Booking\\src\\Booking\\Booking.csproj\", \"{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flight\", \"src\\Services\\Flight\\src\\Flight\\Flight.csproj\", \"{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flight.Api\", \"src\\Services\\Flight\\src\\Flight.Api\\Flight.Api.csproj\", \"{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Identity\", \"src\\Services\\Identity\\src\\Identity\\Identity.csproj\", \"{BCDEAB10-6373-46E7-B408-846A3B0B508B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Identity.Api\", \"src\\Services\\Identity\\src\\Identity.Api\\Identity.Api.csproj\", \"{B0EC74C5-9B2D-492C-ABAE-3E868397B122}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Passenger\", \"src\\Services\\Passenger\\src\\Passenger\\Passenger.csproj\", \"{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Passenger.Api\", \"src\\Services\\Passenger\\src\\Passenger.Api\\Passenger.Api.csproj\", \"{101FFD12-17A4-4615-9438-F347BBF4CC85}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"BuildingBlocks\", \"src\\BuildingBlocks\\BuildingBlocks.csproj\", \"{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{427BE8BE-DA7B-FC74-412B-547671E05463}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ApiGateway\", \"src\\ApiGateway\\src\\ApiGateway.csproj\", \"{C015BF35-6977-407B-8948-636A9C81C5BE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"src\\Services\\Booking\\tests\\IntegrationTest\\Integration.Test.csproj\", \"{19A89F36-FD3A-448D-90D1-04A1B67BB255}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"EndToEnd.Test\", \"src\\Services\\Flight\\tests\\EndToEndTest\\EndToEnd.Test.csproj\", \"{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"src\\Services\\Flight\\tests\\IntegrationTest\\Integration.Test.csproj\", \"{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Unit.Test\", \"src\\Services\\Flight\\tests\\UnitTest\\Unit.Test.csproj\", \"{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"src\\Services\\Identity\\tests\\IntegrationTest\\Integration.Test.csproj\", \"{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"src\\Services\\Passenger\\tests\\IntegrationTest\\Integration.Test.csproj\", \"{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Aspire\", \"Aspire\", \"{D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{C4287034-6833-4505-A6EB-704A86392ECB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"AppHost\", \"src\\Aspire\\src\\AppHost\\AppHost.csproj\", \"{490BCB11-314C-473C-9B85-A32164783507}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ServiceDefaults\", \"src\\Aspire\\src\\ServiceDefaults\\ServiceDefaults.csproj\", \"{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x64.Build.0 = Release|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C}.Release|x86.Build.0 = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x64.Build.0 = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8}.Release|x86.Build.0 = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x64.Build.0 = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279}.Release|x86.Build.0 = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x64.Build.0 = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2}.Release|x86.Build.0 = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122}.Release|x86.Build.0 = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x64.Build.0 = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538}.Release|x86.Build.0 = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x64.Build.0 = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85}.Release|x86.Build.0 = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x64.Build.0 = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE}.Release|x86.Build.0 = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x64.Build.0 = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4}.Release|x86.Build.0 = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB}.Release|x86.Build.0 = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x64.Build.0 = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5}.Release|x86.Build.0 = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|x64.Build.0 = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{490BCB11-314C-473C-9B85-A32164783507}.Release|x86.Build.0 = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x64.Build.0 = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{CDFA86FA-BBBA-4A5B-A833-3BE219E373E5} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}\n\t\t{B19FD14B-4DFE-26B6-646B-3D5D94CC4D36} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}\n\t\t{C734CEF7-A2AC-3076-84D8-694B7490AA9D} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}\n\t\t{A3579DE0-F7C5-67E8-3CF8-3AC89B64E059} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}\n\t\t{C6034A5C-F49A-5FA4-86A6-65B2CB19613F} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}\n\t\t{9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}\n\t\t{B465D535-05D9-3A0A-08BF-35A1C18CEC46} = {B19FD14B-4DFE-26B6-646B-3D5D94CC4D36}\n\t\t{A2834164-BF04-BF13-ADC5-A97145852861} = {C6034A5C-F49A-5FA4-86A6-65B2CB19613F}\n\t\t{1B4FBE3A-43F5-1B1E-2877-3036AC5431EF} = {C6034A5C-F49A-5FA4-86A6-65B2CB19613F}\n\t\t{DDEDC5E0-5D13-A45C-2393-A774DD4A1A07} = {A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}\n\t\t{51D8F471-B8EB-AD1C-0E89-AA84C5D0C759} = {A3579DE0-F7C5-67E8-3CF8-3AC89B64E059}\n\t\t{773BFBD8-04CD-79F8-8301-C81308C3ED45} = {B465D535-05D9-3A0A-08BF-35A1C18CEC46}\n\t\t{4B043475-1AFA-C467-FE09-A46D09CD6936} = {B465D535-05D9-3A0A-08BF-35A1C18CEC46}\n\t\t{5CED3889-AECF-A6CD-55DC-F680D3C18861} = {9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}\n\t\t{54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352} = {9D4F3958-FE6E-C048-E6F9-6F53D8AF03CA}\n\t\t{D3BF565A-C413-4185-9528-BE1B4F46993C} = {A2834164-BF04-BF13-ADC5-A97145852861}\n\t\t{3EA375C7-2900-4927-B1E5-C9D31E67F4A8} = {A2834164-BF04-BF13-ADC5-A97145852861}\n\t\t{BCC8A8A6-C2ED-42D2-86BB-A05C790D7279} = {DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}\n\t\t{836D1466-3C20-4D74-B54A-FA09C0EE0FA2} = {DDEDC5E0-5D13-A45C-2393-A774DD4A1A07}\n\t\t{BCDEAB10-6373-46E7-B408-846A3B0B508B} = {773BFBD8-04CD-79F8-8301-C81308C3ED45}\n\t\t{B0EC74C5-9B2D-492C-ABAE-3E868397B122} = {773BFBD8-04CD-79F8-8301-C81308C3ED45}\n\t\t{9B4BDD42-56F3-4DB9-B3E5-74ABB7C19538} = {5CED3889-AECF-A6CD-55DC-F680D3C18861}\n\t\t{101FFD12-17A4-4615-9438-F347BBF4CC85} = {5CED3889-AECF-A6CD-55DC-F680D3C18861}\n\t\t{AEDB3219-5E1D-4716-8DE2-F5F9391913A2} = {C734CEF7-A2AC-3076-84D8-694B7490AA9D}\n\t\t{427BE8BE-DA7B-FC74-412B-547671E05463} = {CDFA86FA-BBBA-4A5B-A833-3BE219E373E5}\n\t\t{C015BF35-6977-407B-8948-636A9C81C5BE} = {427BE8BE-DA7B-FC74-412B-547671E05463}\n\t\t{19A89F36-FD3A-448D-90D1-04A1B67BB255} = {1B4FBE3A-43F5-1B1E-2877-3036AC5431EF}\n\t\t{B27759CD-5A7D-43A4-A55C-FE1154DC4CC4} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}\n\t\t{BD23EEF8-9196-4E0F-BF33-E14E99D34C1B} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}\n\t\t{B52D6341-AAD9-43CB-82AF-2DBE39CBF1DB} = {51D8F471-B8EB-AD1C-0E89-AA84C5D0C759}\n\t\t{0DAACE48-4EA6-4DB7-8A5C-99B86BCB1E01} = {4B043475-1AFA-C467-FE09-A46D09CD6936}\n\t\t{A85AE27D-81ED-485A-BA4B-161B25BEB8A5} = {54BCCDE8-25E6-6FCB-4A9E-D5D2AF76D352}\n\t\t{D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA} = {CD4A4407-C3B0-422D-BB8C-2A810CED9938}\n\t\t{C4287034-6833-4505-A6EB-704A86392ECB} = {D1B6353A-63F5-4DD9-90E6-42B2CFDF1DEA}\n\t\t{490BCB11-314C-473C-9B85-A32164783507} = {C4287034-6833-4505-A6EB-704A86392ECB}\n\t\t{5B7BF918-E47F-4932-B5C5-E8C2C35890E4} = {C4287034-6833-4505-A6EB-704A86392ECB}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "booking.rest",
    "content": "\n## uncommnet this line for use kubernetes ingress controller instead of Yarp\n//@api-gateway=https://booking-microservices.com\n@api-gateway=https://localhost:5000\n@identity-api=http://localhost:6005\n@flight-api=http://localhost:5004\n@passenger-api=http://localhost:6012\n@booking-api=http://localhost:6010\n\n@contentType = application/json\n@flightid = \"3c5c0000-97c6-fc34-2eb9-08db322230c9\"\n@passengerId = \"8c9c0000-97c6-fc34-2eb9-66db322230c9\"\n\n################################# Identity API #################################\n\n###\n# @name ApiRoot_Identity\nGET {{identity-api}}\n###\n\n\n###\n# @name Authenticate\nPOST {{api-gateway}}/identity/connect/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password\n&client_id=client\n&client_secret=secret\n&username=samh\n&password=Admin@123456\n&scope=flight-api role\n\n### change scope base on microservices scope (eg. passenger-api, ...)\n###\n\n\n\n###\n# @name Register_New_User\nPOST {{api-gateway}}/identity/api/v1/identity/register-user\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"firstName\": \"John\",\n  \"lastName\": \"Do\",\n  \"username\": \"admin\",\n  \"passportNumber\": \"41290000\",\n  \"email\": \"admin@admin.com\",\n  \"password\": \"Admin@12345\",\n  \"confirmPassword\": \"Admin@12345\"\n}\n###\n\n################################# Flight API #################################\n\n###\n# @name ApiRoot_Flight\nGET {{flight-api}}\n###\n\n###\n# @name Create_Seat\nPost {{api-gateway}}/flight/api/v1/flight/seat\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"seatNumber\": \"1255\",\n  \"type\": 1,\n  \"class\": 1,\n  \"flightId\": \"3c5c0000-97c6-fc34-2eb9-08db322230c9\"\n}\n###\n\n\n###\n# @name Reserve_Seat\nPost {{api-gateway}}/flight/api/v1/flight/reserve-seat\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"flightId\": \"3c5c0000-97c6-fc34-2eb9-08db322230c9\",\n  \"seatNumber\": \"1255\"\n}\n###\n\n\n###\n# @name Get_Available_Seats\nGET {{api-gateway}}/flight/api/v1/flight/get-available-seats/{{flightid}}\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n###\n\n\n###\n# @name Get_Flight_By_Id\nGET {{api-gateway}}/flight/api/v1/flight/{{flightid}}\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n###\n\n\n###\n# @name Get_Available_Flights\nGET {{api-gateway}}/flight/api/v1/flight/get-available-flights\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n###\n\n\n###\n# @name Create_Flights\nPOST {{api-gateway}}/flight/api/v1/flight\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"flightNumber\": \"12BB\",\n  \"aircraftId\": \"3c5c0000-97c6-fc34-fcd3-08db322230c8\",\n  \"departureAirportId\": \"3c5c0000-97c6-fc34-a0cb-08db322230c8\",\n  \"departureDate\": \"2022-03-01T14:55:41.255Z\",\n  \"arriveDate\": \"2022-03-01T14:55:41.255Z\",\n  \"arriveAirportId\": \"3c5c0000-97c6-fc34-fc3c-08db322230c8\",\n  \"durationMinutes\": 120,\n  \"flightDate\": \"2022-03-01T14:55:41.255Z\",\n  \"status\": 1,\n  \"price\": 8000\n}\n###\n\n\n###\n# @name Update_Flights\nPUT  {{api-gateway}}/flight/api/v1/flight\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"id\": 1,\n  \"flightNumber\": \"BD467\",\n  \"aircraftId\": \"3c5c0000-97c6-fc34-fcd3-08db322230c8\",\n  \"departureAirportId\": \"3c5c0000-97c6-fc34-a0cb-08db322230c8\",\n  \"departureDate\": \"2022-04-23T12:17:45.140Z\",\n  \"arriveDate\": \"2022-04-23T12:17:45.140Z\",\n  \"arriveAirportId\": \"3c5c0000-97c6-fc34-fc3c-08db322230c8\",\n  \"durationMinutes\": 120,\n  \"flightDate\": \"2022-04-23T12:17:45.140Z\",\n  \"status\": 4,\n  \"isDeleted\": false,\n  \"price\": 99000\n}\n###\n\n\n###\n# @name Delete_Flights\nDELETE   {{api-gateway}}/flight/api/v1/flight/{{flightid}}\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n###\n\n\n###\n# @name Create_Airport\nPOST {{api-gateway}}/flight/api/v1/flight/airport\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"name\": \"mehrabad\",\n  \"address\": \"tehran\",\n  \"code\": \"12YD\"\n}\n###\n\n\n\n###\n# @name Create_Aircraft\nPOST {{api-gateway}}/flight/api/v1/flight/aircraft\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"name\": \"airbus2\",\n  \"model\": \"322\",\n  \"manufacturingYear\": 2012\n}\n###\n\n\n################################# Passenger API #################################\n\n###\n# @name ApiRoot_Passenger\nGET {{passenger-api}}\n###\n\n\n###\n# @name Complete_Registration_Passenger\nPOST {{api-gateway}}/passenger/api/v1/passenger/complete-registration\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"passportNumber\": \"41290000\",\n  \"passengerType\": 1,\n  \"age\": 30\n}\n###\n\n\n###\n# @name Get_Passenger_By_Id\nGET  {{api-gateway}}/passenger/api/v1/passenger/{{passengerId}}\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n###\n\n\n################################# Booking API #################################\n\n###\n# @name ApiRoot_Booking\nGET {{booking-api}}\n###\n\n\n###\n# @name Create_Booking\nPOST {{api-gateway}}/booking/api/v1/booking\naccept: application/json\nContent-Type: application/json\nauthorization: bearer {{Authenticate.response.body.access_token}}\n\n{\n  \"passengerId\": \"8c9c0000-97c6-fc34-2eb9-66db322230c9\",\n  \"flightId\": \"3c5c0000-97c6-fc34-2eb9-08db322230c9\",\n  \"description\": \"I want to fly to iran\"\n}\n###\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = {\n    extends: [\"@commitlint/config-conventional\"],\n  }"
  },
  {
    "path": "deployments/configs/dashboards.md",
    "content": "# Dashboards\n\n- [Introducing ASP.NET Core metrics and Grafana dashboards in .NET 8](https://devblogs.microsoft.com/dotnet/introducing-aspnetcore-metrics-and-grafana-dashboards-in-dotnet-8/)\n- [ASP.NET Core](https://grafana.com/grafana/dashboards/19924-asp-net-core/)\n- [ASP.NET Core Endpoint](https://grafana.com/grafana/dashboards/19925-asp-net-core-endpoint/)\n- [Node Exporter Quickstart and Dashboard](https://grafana.com/grafana/dashboards/13978-node-exporter-quickstart-and-dashboard/)\n- [PostgreSQL Exporter Quickstart and Dashboard](https://grafana.com/grafana/dashboards/14114-postgres-overview/)\n- [RabbitMQ-Overview](https://grafana.com/grafana/dashboards/10991-rabbitmq-overview/)\n"
  },
  {
    "path": "deployments/configs/grafana/dashboards/dotnet-core-endpoint.json",
    "content": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY\",\n      \"label\": \"Managed_Prometheus_jamesnk-telemetry\",\n      \"description\": \"\",\n      \"type\": \"datasource\",\n      \"pluginId\": \"prometheus\",\n      \"pluginName\": \"Prometheus\"\n    }\n  ],\n  \"__elements\": {},\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"9.4.8\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"1.0.0\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"stat\",\n      \"name\": \"Stat\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"table\",\n      \"name\": \"Table\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"timeseries\",\n      \"name\": \"Time series\",\n      \"version\": \"\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": {\n          \"type\": \"grafana\",\n          \"uid\": \"-- Grafana --\"\n        },\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"target\": {\n          \"limit\": 100,\n          \"matchAny\": false,\n          \"tags\": [],\n          \"type\": \"dashboard\"\n        },\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"editable\": true,\n  \"fiscalYearStartMonth\": 0,\n  \"graphTooltip\": 0,\n  \"id\": null,\n  \"links\": [\n    {\n      \"asDropdown\": false,\n      \"icon\": \"dashboard\",\n      \"includeVars\": false,\n      \"keepTime\": true,\n      \"tags\": [],\n      \"targetBlank\": false,\n      \"title\": \" ASP.NET Core\",\n      \"tooltip\": \"\",\n      \"type\": \"link\",\n      \"url\": \"/d/KdDACDp4z/asp-net-core-metrics\"\n    }\n  ],\n  \"liveNow\": false,\n  \"panels\": [\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"dark-green\",\n            \"mode\": \"continuous-GrYlRd\",\n            \"seriesBy\": \"max\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"axisSoftMin\": 0,\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 50,\n            \"gradientMode\": \"opacity\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"smooth\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"s\"\n        },\n        \"overrides\": [\n          {\n            \"__systemRef\": \"hideSeriesFrom\",\n            \"matcher\": {\n              \"id\": \"byNames\",\n              \"options\": {\n                \"mode\": \"exclude\",\n                \"names\": [\n                  \"p50\"\n                ],\n                \"prefix\": \"All except:\",\n                \"readOnly\": true\n              }\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hideFrom\",\n                \"value\": {\n                  \"legend\": false,\n                  \"tooltip\": false,\n                  \"viz\": false\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"id\": 40,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"min\",\n            \"max\"\n          ],\n          \"displayMode\": \"table\",\n          \"placement\": \"right\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.50, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"legendFormat\": \"p50\",\n          \"range\": true,\n          \"refId\": \"p50\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.75, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p75\",\n          \"range\": true,\n          \"refId\": \"p75\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.90, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p90\",\n          \"range\": true,\n          \"refId\": \"p90\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.95, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p95\",\n          \"range\": true,\n          \"refId\": \"p95\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.98, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p98\",\n          \"range\": true,\n          \"refId\": \"p98\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.99, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p99\",\n          \"range\": true,\n          \"refId\": \"p99\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.999, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p99.9\",\n          \"range\": true,\n          \"refId\": \"p99.9\"\n        }\n      ],\n      \"title\": \"Requests Duration - $method $route\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\",\n            \"seriesBy\": \"max\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 50,\n            \"gradientMode\": \"opacity\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"smooth\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"percentunit\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"All\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"dark-orange\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"4XX\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"yellow\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"5XX\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"dark-red\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 0\n      },\n      \"id\": 46,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"min\",\n            \"max\"\n          ],\n          \"displayMode\": \"table\",\n          \"placement\": \"right\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\", status_code=~\\\"4..|5..\\\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m]))\",\n          \"legendFormat\": \"All\",\n          \"range\": true,\n          \"refId\": \"All\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\", status_code=~\\\"4..\\\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m]))\",\n          \"hide\": false,\n          \"legendFormat\": \"4XX\",\n          \"range\": true,\n          \"refId\": \"4XX\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\", status_code=~\\\"5..\\\"}[5m]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[5m]))\",\n          \"hide\": false,\n          \"legendFormat\": \"5XX\",\n          \"range\": true,\n          \"refId\": \"5XX\"\n        }\n      ],\n      \"title\": \"Errors Rate - $method $route\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"cellOptions\": {\n              \"type\": \"auto\"\n            },\n            \"inspect\": false\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Requests\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.width\",\n                \"value\": 300\n              },\n              {\n                \"id\": \"custom.cellOptions\",\n                \"value\": {\n                  \"mode\": \"gradient\",\n                  \"type\": \"gauge\"\n                }\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"mode\": \"continuous-YlRd\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Route\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"links\",\n                \"value\": [\n                  {\n                    \"title\": \"\",\n                    \"url\": \"/d/NagEsjE4z/asp-net-core-endpoint-details?var-route=${__data.fields.Route}&var-method=${__data.fields.Method}&${__url_time_range}\"\n                  }\n                ]\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 9\n      },\n      \"hideTimeOverride\": false,\n      \"id\": 44,\n      \"options\": {\n        \"footer\": {\n          \"countRows\": false,\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"showHeader\": true,\n        \"sortBy\": [\n          {\n            \"desc\": true,\n            \"displayName\": \"Value\"\n          }\n        ]\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"sum by (exception_name) (\\r\\n  max_over_time(http_server_request_duration_s_count{route=\\\"$route\\\", method=\\\"$method\\\", exception_name!=\\\"\\\"}[$__rate_interval])\\r\\n)\",\n          \"format\": \"table\",\n          \"instant\": true,\n          \"interval\": \"\",\n          \"legendFormat\": \"{{route}}\",\n          \"range\": false,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Unhandled Exceptions\",\n      \"transformations\": [\n        {\n          \"id\": \"organize\",\n          \"options\": {\n            \"excludeByName\": {\n              \"Time\": true,\n              \"method\": false\n            },\n            \"indexByName\": {\n              \"Time\": 0,\n              \"Value\": 2,\n              \"exception_name\": 1\n            },\n            \"renameByName\": {\n              \"Value\": \"Requests\",\n              \"exception_name\": \"Exception\",\n              \"method\": \"Method\",\n              \"route\": \"Route\"\n            }\n          }\n        }\n      ],\n      \"type\": \"table\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"blue\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 9\n      },\n      \"id\": 42,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"max\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"value_and_name\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum by (status_code) (\\r\\n    max_over_time(http_server_request_duration_s_count{route=\\\"$route\\\", method=\\\"$method\\\"}[$__rate_interval])\\r\\n  )\",\n          \"legendFormat\": \"Status {{status_code}}\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Requests HTTP Status Code\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"green\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 13\n      },\n      \"id\": 48,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"max\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"value_and_name\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum by (scheme) (\\r\\n    max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[$__rate_interval])\\r\\n  )\",\n          \"legendFormat\": \"{{scheme}}\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Requests Secured\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"purple\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 13\n      },\n      \"id\": 50,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"max\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"value_and_name\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum by (protocol) (\\r\\n    max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route=\\\"$route\\\", method=\\\"$method\\\"}[$__rate_interval])\\r\\n  )\",\n          \"legendFormat\": \"{{protocol}}\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Requests HTTP Protocol\",\n      \"type\": \"stat\"\n    }\n  ],\n  \"refresh\": \"\",\n  \"revision\": 1,\n  \"schemaVersion\": 38,\n  \"style\": \"dark\",\n  \"tags\": [\n    \"dotnet\",\n    \"prometheus\",\n    \"aspnetcore\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_current_requests, job)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Job\",\n        \"multi\": false,\n        \"name\": \"job\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_current_requests, job)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_current_requests{job=~\\\"$job\\\"}, instance)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Instance\",\n        \"multi\": false,\n        \"name\": \"instance\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_current_requests{job=~\\\"$job\\\"}, instance)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_request_duration_s_count, route)\",\n        \"description\": \"Route\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Route\",\n        \"multi\": false,\n        \"name\": \"route\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_request_duration_s_count, route)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_request_duration_s_count{route=~\\\"$route\\\"}, method)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Method\",\n        \"multi\": false,\n        \"name\": \"method\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_request_duration_s_count{route=~\\\"$route\\\"}, method)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-30m\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {},\n  \"timezone\": \"\",\n  \"title\": \"ASP.NET Core Endpoint\",\n  \"uid\": \"NagEsjE4z\",\n  \"version\": 10,\n  \"weekStart\": \"\"\n}\n"
  },
  {
    "path": "deployments/configs/grafana/dashboards/dotnet-core.json",
    "content": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY\",\n      \"label\": \"Managed_Prometheus_jamesnk-telemetry\",\n      \"description\": \"\",\n      \"type\": \"datasource\",\n      \"pluginId\": \"prometheus\",\n      \"pluginName\": \"Prometheus\"\n    }\n  ],\n  \"__elements\": {},\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"9.4.8\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"1.0.0\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"stat\",\n      \"name\": \"Stat\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"table\",\n      \"name\": \"Table\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"timeseries\",\n      \"name\": \"Time series\",\n      \"version\": \"\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": {\n          \"type\": \"grafana\",\n          \"uid\": \"-- Grafana --\"\n        },\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"target\": {\n          \"limit\": 100,\n          \"matchAny\": false,\n          \"tags\": [],\n          \"type\": \"dashboard\"\n        },\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"description\": \"ASP.NET Core metrics from OpenTelemetry NuGet\",\n  \"editable\": true,\n  \"fiscalYearStartMonth\": 0,\n  \"gnetId\": 17706,\n  \"graphTooltip\": 0,\n  \"id\": null,\n  \"links\": [],\n  \"liveNow\": false,\n  \"panels\": [\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"dark-green\",\n            \"mode\": \"continuous-GrYlRd\",\n            \"seriesBy\": \"max\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"axisSoftMin\": 0,\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 50,\n            \"gradientMode\": \"opacity\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"smooth\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"s\"\n        },\n        \"overrides\": [\n          {\n            \"__systemRef\": \"hideSeriesFrom\",\n            \"matcher\": {\n              \"id\": \"byNames\",\n              \"options\": {\n                \"mode\": \"exclude\",\n                \"names\": [\n                  \"p50\"\n                ],\n                \"prefix\": \"All except:\",\n                \"readOnly\": true\n              }\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hideFrom\",\n                \"value\": {\n                  \"legend\": false,\n                  \"tooltip\": false,\n                  \"viz\": false\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"id\": 40,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"min\",\n            \"max\"\n          ],\n          \"displayMode\": \"table\",\n          \"placement\": \"right\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.50, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"legendFormat\": \"p50\",\n          \"range\": true,\n          \"refId\": \"p50\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.75, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p75\",\n          \"range\": true,\n          \"refId\": \"p75\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.90, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p90\",\n          \"range\": true,\n          \"refId\": \"p90\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.95, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p95\",\n          \"range\": true,\n          \"refId\": \"p95\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.98, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p98\",\n          \"range\": true,\n          \"refId\": \"p98\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.99, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p99\",\n          \"range\": true,\n          \"refId\": \"p99\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.999, sum(rate(http_server_request_duration_s_bucket{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])) by (le))\",\n          \"hide\": false,\n          \"legendFormat\": \"p99.9\",\n          \"range\": true,\n          \"refId\": \"p99.9\"\n        }\n      ],\n      \"title\": \"Requests Duration\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\",\n            \"seriesBy\": \"max\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 50,\n            \"gradientMode\": \"opacity\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"smooth\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"percentunit\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"All\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"dark-orange\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"4XX\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"yellow\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"5XX\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"dark-red\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 0\n      },\n      \"id\": 47,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"min\",\n            \"max\"\n          ],\n          \"displayMode\": \"table\",\n          \"placement\": \"right\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", status_code=~\\\"4..|5..\\\"}[$__rate_interval]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval]))\",\n          \"legendFormat\": \"All\",\n          \"range\": true,\n          \"refId\": \"All\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", status_code=~\\\"4..\\\"}[$__rate_interval]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval]))\",\n          \"hide\": false,\n          \"legendFormat\": \"4XX\",\n          \"range\": true,\n          \"refId\": \"4XX\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", status_code=~\\\"5..\\\"}[$__rate_interval]) or vector(0)) / sum(rate(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval]))\",\n          \"hide\": false,\n          \"legendFormat\": \"5XX\",\n          \"range\": true,\n          \"refId\": \"5XX\"\n        }\n      ],\n      \"title\": \"Errors Rate\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 9\n      },\n      \"id\": 49,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": false\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(kestrel_current_connections{job=\\\"$job\\\", instance=\\\"$instance\\\"})\",\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Current Connections\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 9\n      },\n      \"id\": 55,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": false\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(http_server_current_requests{job=\\\"$job\\\", instance=\\\"$instance\\\"})\",\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Current Requests\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"blue\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 9\n      },\n      \"id\": 58,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"center\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"text\": {},\n        \"textMode\": \"value\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"sum(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"})\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Total Requests\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"dark-red\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 9\n      },\n      \"id\": 59,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"center\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"text\": {},\n        \"textMode\": \"value\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"sum(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", exception_name!=\\\"\\\"})\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Total Unhandled Exceptions\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"green\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 13\n      },\n      \"id\": 60,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"max\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"value_and_name\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum by (scheme) (\\r\\n    max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])\\r\\n  )\",\n          \"legendFormat\": \"{{scheme}}\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Requests Secured\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"fixedColor\": \"purple\",\n            \"mode\": \"fixed\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 13\n      },\n      \"id\": 42,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"max\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"value_and_name\"\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum by (protocol) (\\r\\n    max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\"}[$__rate_interval])\\r\\n  )\",\n          \"legendFormat\": \"{{protocol}}\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Requests HTTP Protocol\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"cellOptions\": {\n              \"type\": \"auto\"\n            },\n            \"inspect\": false\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Requests\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.width\",\n                \"value\": 300\n              },\n              {\n                \"id\": \"custom.cellOptions\",\n                \"value\": {\n                  \"mode\": \"gradient\",\n                  \"type\": \"gauge\"\n                }\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"mode\": \"continuous-BlPu\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Endpoint\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"links\",\n                \"value\": [\n                  {\n                    \"targetBlank\": false,\n                    \"title\": \"Test\",\n                    \"url\": \"/d/NagEsjE4z/asp-net-core-endpoint-details?var-route=${__data.fields.route}&var-method=${__data.fields.method}&${__url_time_range}\"\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"route\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": true\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"method\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": true\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 17\n      },\n      \"hideTimeOverride\": false,\n      \"id\": 51,\n      \"options\": {\n        \"footer\": {\n          \"countRows\": false,\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"showHeader\": true,\n        \"sortBy\": [\n          {\n            \"desc\": true,\n            \"displayName\": \"Value\"\n          }\n        ]\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"  topk(10,\\r\\n  sum by (route, method, method_route) (\\r\\n    label_join(max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route!=\\\"\\\"}[$__rate_interval]), \\\"method_route\\\", \\\" \\\", \\\"method\\\", \\\"route\\\")\\r\\n  ))\",\n          \"format\": \"table\",\n          \"instant\": true,\n          \"interval\": \"\",\n          \"legendFormat\": \"{{route}}\",\n          \"range\": false,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Top 10 Requested Endpoints\",\n      \"transformations\": [\n        {\n          \"id\": \"organize\",\n          \"options\": {\n            \"excludeByName\": {\n              \"Time\": true,\n              \"method\": false,\n              \"route\": false\n            },\n            \"indexByName\": {\n              \"Time\": 0,\n              \"Value\": 4,\n              \"method\": 2,\n              \"method_route\": 3,\n              \"route\": 1\n            },\n            \"renameByName\": {\n              \"Value\": \"Requests\",\n              \"method\": \"\",\n              \"method_route\": \"Endpoint\",\n              \"route\": \"\"\n            }\n          }\n        }\n      ],\n      \"type\": \"table\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"cellOptions\": {\n              \"type\": \"auto\"\n            },\n            \"inspect\": false\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Requests\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.width\",\n                \"value\": 300\n              },\n              {\n                \"id\": \"custom.cellOptions\",\n                \"value\": {\n                  \"mode\": \"gradient\",\n                  \"type\": \"gauge\"\n                }\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"mode\": \"continuous-YlRd\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Endpoint\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"links\",\n                \"value\": [\n                  {\n                    \"title\": \"\",\n                    \"url\": \"/d/NagEsjE4z/asp-net-core-endpoint-details?var-route=${__data.fields.route}&var-method=${__data.fields.method}&${__url_time_range}\"\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"route\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": true\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"method\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": true\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 17\n      },\n      \"hideTimeOverride\": false,\n      \"id\": 54,\n      \"options\": {\n        \"footer\": {\n          \"countRows\": false,\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"showHeader\": true,\n        \"sortBy\": [\n          {\n            \"desc\": true,\n            \"displayName\": \"Value\"\n          }\n        ]\n      },\n      \"pluginVersion\": \"9.4.8\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"  topk(10,\\r\\n  sum by (route, method, method_route) (\\r\\n    label_join(max_over_time(http_server_request_duration_s_count{job=\\\"$job\\\", instance=\\\"$instance\\\", route!=\\\"\\\", exception_name!=\\\"\\\"}[$__rate_interval]), \\\"method_route\\\", \\\" \\\", \\\"method\\\", \\\"route\\\")\\r\\n  ))\",\n          \"format\": \"table\",\n          \"instant\": true,\n          \"interval\": \"\",\n          \"legendFormat\": \"{{route}}\",\n          \"range\": false,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Top 10 Unhandled Exception Endpoints\",\n      \"transformations\": [\n        {\n          \"id\": \"organize\",\n          \"options\": {\n            \"excludeByName\": {\n              \"Time\": true,\n              \"method\": false\n            },\n            \"indexByName\": {\n              \"Time\": 0,\n              \"Value\": 4,\n              \"method\": 2,\n              \"method_route\": 3,\n              \"route\": 1\n            },\n            \"renameByName\": {\n              \"Value\": \"Requests\",\n              \"method\": \"\",\n              \"method_route\": \"Endpoint\",\n              \"route\": \"\"\n            }\n          }\n        }\n      ],\n      \"type\": \"table\"\n    }\n  ],\n  \"refresh\": \"\",\n  \"revision\": 1,\n  \"schemaVersion\": 38,\n  \"style\": \"dark\",\n  \"tags\": [\n    \"dotnet\",\n    \"prometheus\",\n    \"aspnetcore\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_current_requests, job)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Job\",\n        \"multi\": false,\n        \"name\": \"job\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_current_requests, job)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_MANAGED_PROMETHEUS_JAMESNK-TELEMETRY}\"\n        },\n        \"definition\": \"label_values(http_server_current_requests{job=~\\\"$job\\\"}, instance)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Instance\",\n        \"multi\": false,\n        \"name\": \"instance\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(http_server_current_requests{job=~\\\"$job\\\"}, instance)\",\n          \"refId\": \"StandardVariableQuery\"\n        },\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"type\": \"query\"\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-30m\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {},\n  \"timezone\": \"\",\n  \"title\": \"ASP.NET Core\",\n  \"uid\": \"KdDACDp4z\",\n  \"version\": 5,\n  \"weekStart\": \"\"\n}\n"
  },
  {
    "path": "deployments/configs/grafana/dashboards/node-exporter.json",
    "content": "{\n  \"__inputs\": [],\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"7.4.3\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"graph\",\n      \"name\": \"Graph\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"1.0.0\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": []\n  },\n  \"editable\": false,\n  \"gnetId\": 13978,\n  \"graphTooltip\": 0,\n  \"hideControls\": false,\n  \"id\": null,\n  \"links\": [],\n  \"refresh\": \"\",\n  \"rows\": [\n    {\n      \"collapse\": false,\n      \"collapsed\": false,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 1,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 2,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": true,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"(\\n  (1 - rate(node_cpu_seconds_total{job=\\\"node\\\", mode=\\\"idle\\\", instance=\\\"$instance\\\"}[$__interval]))\\n/ ignoring(cpu) group_left\\n  count without (cpu)( node_cpu_seconds_total{job=\\\"node\\\", mode=\\\"idle\\\", instance=\\\"$instance\\\"})\\n)\\n\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 5,\n              \"legendFormat\": \"{{cpu}}\",\n              \"refId\": \"A\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"CPU Usage\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"percentunit\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": 1,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"percentunit\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": 1,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 0,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 3,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"node_load1{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"1m load average\",\n              \"refId\": \"A\"\n            },\n            {\n              \"expr\": \"node_load5{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"5m load average\",\n              \"refId\": \"B\"\n            },\n            {\n              \"expr\": \"node_load15{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"15m load average\",\n              \"refId\": \"C\"\n            },\n            {\n              \"expr\": \"count(node_cpu_seconds_total{job=\\\"node\\\", instance=\\\"$instance\\\", mode=\\\"idle\\\"})\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"logical cores\",\n              \"refId\": \"D\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Load Average\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\",\n      \"type\": \"row\"\n    },\n    {\n      \"collapse\": false,\n      \"collapsed\": false,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 1,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 4,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 9,\n          \"stack\": true,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"(\\n  node_memory_MemTotal_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\\n-\\n  node_memory_MemFree_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\\n-\\n  node_memory_Buffers_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\\n-\\n  node_memory_Cached_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\\n)\\n\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"memory used\",\n              \"refId\": \"A\"\n            },\n            {\n              \"expr\": \"node_memory_Buffers_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"memory buffers\",\n              \"refId\": \"B\"\n            },\n            {\n              \"expr\": \"node_memory_Cached_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"memory cached\",\n              \"refId\": \"C\"\n            },\n            {\n              \"expr\": \"node_memory_MemFree_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"}\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"memory free\",\n              \"refId\": \"D\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Memory Usage\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"cacheTimeout\": null,\n          \"colorBackground\": false,\n          \"colorValue\": false,\n          \"colors\": [\n            \"rgba(50, 172, 45, 0.97)\",\n            \"rgba(237, 129, 40, 0.89)\",\n            \"rgba(245, 54, 54, 0.9)\"\n          ],\n          \"datasource\": \"$datasource\",\n          \"format\": \"percent\",\n          \"gauge\": {\n            \"maxValue\": 100,\n            \"minValue\": 0,\n            \"show\": true,\n            \"thresholdLabels\": false,\n            \"thresholdMarkers\": true\n          },\n          \"gridPos\": {},\n          \"id\": 5,\n          \"interval\": null,\n          \"links\": [],\n          \"mappingType\": 1,\n          \"mappingTypes\": [\n            {\n              \"name\": \"value to text\",\n              \"value\": 1\n            },\n            {\n              \"name\": \"range to text\",\n              \"value\": 2\n            }\n          ],\n          \"maxDataPoints\": 100,\n          \"nullPointMode\": \"connected\",\n          \"nullText\": null,\n          \"postfix\": \"\",\n          \"postfixFontSize\": \"50%\",\n          \"prefix\": \"\",\n          \"prefixFontSize\": \"50%\",\n          \"rangeMaps\": [\n            {\n              \"from\": \"null\",\n              \"text\": \"N/A\",\n              \"to\": \"null\"\n            }\n          ],\n          \"span\": 3,\n          \"sparkline\": {\n            \"fillColor\": \"rgba(31, 118, 189, 0.18)\",\n            \"full\": false,\n            \"lineColor\": \"rgb(31, 120, 193)\",\n            \"show\": false\n          },\n          \"tableColumn\": \"\",\n          \"targets\": [\n            {\n              \"expr\": \"100 -\\n(\\n  avg(node_memory_MemAvailable_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"})\\n/\\n  avg(node_memory_MemTotal_bytes{job=\\\"node\\\", instance=\\\"$instance\\\"})\\n* 100\\n)\\n\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"\",\n              \"refId\": \"A\"\n            }\n          ],\n          \"thresholds\": \"80, 90\",\n          \"title\": \"Memory Usage\",\n          \"type\": \"singlestat\",\n          \"valueFontSize\": \"80%\",\n          \"valueMaps\": [\n            {\n              \"op\": \"=\",\n              \"text\": \"N/A\",\n              \"value\": \"null\"\n            }\n          ],\n          \"valueName\": \"current\"\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\",\n      \"type\": \"row\"\n    },\n    {\n      \"collapse\": false,\n      \"collapsed\": false,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 0,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 6,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [\n            {\n              \"alias\": \"/ read| written/\",\n              \"yaxis\": 1\n            },\n            {\n              \"alias\": \"/ io time/\",\n              \"yaxis\": 2\n            }\n          ],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"rate(node_disk_read_bytes_total{job=\\\"node\\\", instance=\\\"$instance\\\", device!=\\\"\\\"}[$__interval])\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"{{device}} read\",\n              \"refId\": \"A\"\n            },\n            {\n              \"expr\": \"rate(node_disk_written_bytes_total{job=\\\"node\\\", instance=\\\"$instance\\\", device!=\\\"\\\"}[$__interval])\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"{{device}} written\",\n              \"refId\": \"B\"\n            },\n            {\n              \"expr\": \"rate(node_disk_io_time_seconds_total{job=\\\"node\\\", instance=\\\"$instance\\\", device!=\\\"\\\"}[$__interval])\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"{{device}} io time\",\n              \"refId\": \"C\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Disk I/O\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"s\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 1,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 7,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [\n            {\n              \"alias\": \"used\",\n              \"color\": \"#E0B400\"\n            },\n            {\n              \"alias\": \"available\",\n              \"color\": \"#73BF69\"\n            }\n          ],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": true,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"sum(\\n  max by (device) (\\n    node_filesystem_size_bytes{job=\\\"node\\\", instance=\\\"$instance\\\", fstype!=\\\"\\\"}\\n  -\\n    node_filesystem_avail_bytes{job=\\\"node\\\", instance=\\\"$instance\\\", fstype!=\\\"\\\"}\\n  )\\n)\\n\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"used\",\n              \"refId\": \"A\"\n            },\n            {\n              \"expr\": \"sum(\\n  max by (device) (\\n    node_filesystem_avail_bytes{job=\\\"node\\\", instance=\\\"$instance\\\", fstype!=\\\"\\\"}\\n  )\\n)\\n\",\n              \"format\": \"time_series\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"available\",\n              \"refId\": \"B\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Disk Space Usage\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\",\n      \"type\": \"row\"\n    },\n    {\n      \"collapse\": false,\n      \"collapsed\": false,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 0,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 8,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"rate(node_network_receive_bytes_total{job=\\\"node\\\", instance=\\\"$instance\\\", device!=\\\"lo\\\"}[$__interval])\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"{{device}}\",\n              \"refId\": \"A\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Network Received\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"$datasource\",\n          \"fill\": 0,\n          \"fillGradient\": 0,\n          \"gridPos\": {},\n          \"id\": 9,\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"rightSide\": false,\n            \"show\": true,\n            \"sideWidth\": null,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"repeat\": null,\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"expr\": \"rate(node_network_transmit_bytes_total{job=\\\"node\\\", instance=\\\"$instance\\\", device!=\\\"lo\\\"}[$__interval])\",\n              \"format\": \"time_series\",\n              \"interval\": \"1m\",\n              \"intervalFactor\": 2,\n              \"legendFormat\": \"{{device}}\",\n              \"refId\": \"A\"\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Network Transmitted\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            },\n            {\n              \"format\": \"bytes\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": 0,\n              \"show\": true\n            }\n          ]\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\",\n      \"type\": \"row\"\n    }\n  ],\n  \"schemaVersion\": 14,\n  \"style\": \"dark\",\n  \"tags\": [],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {\n          \"text\": \"Prometheus\",\n          \"value\": \"Prometheus\"\n        },\n        \"hide\": 0,\n        \"label\": null,\n        \"name\": \"datasource\",\n        \"options\": [],\n        \"query\": \"prometheus\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"type\": \"datasource\"\n      },\n      {\n        \"allValue\": null,\n        \"current\": {},\n        \"datasource\": \"$datasource\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": null,\n        \"multi\": false,\n        \"name\": \"instance\",\n        \"options\": [],\n        \"query\": \"label_values(node_exporter_build_info{job=\\\"node\\\"}, instance)\",\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"sort\": 0,\n        \"tagValuesQuery\": \"\",\n        \"tags\": [],\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-1h\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"5s\",\n      \"10s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"15m\",\n      \"30m\",\n      \"1h\",\n      \"2h\",\n      \"1d\"\n    ],\n    \"time_options\": [\n      \"5m\",\n      \"15m\",\n      \"1h\",\n      \"6h\",\n      \"12h\",\n      \"24h\",\n      \"2d\",\n      \"7d\",\n      \"30d\"\n    ]\n  },\n  \"timezone\": \"browser\",\n  \"title\": \"Node Exporter Quickstart and Dashboard\",\n  \"version\": 0,\n  \"description\": \"A quickstart to setup Prometheus Node Exporter with preconfigured dashboards, alerting rules, and recording rules.\"\n}\n"
  },
  {
    "path": "deployments/configs/grafana/dashboards/postgresql.json",
    "content": "{\n  \"__inputs\": [],\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"7.2.0\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"graph\",\n      \"name\": \"Graph\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"1.0.0\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": \"-- Grafana --\",\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"description\": \"A quickstart to setup the Prometheus PostgreSQL Exporter with preconfigured dashboards, alerting rules, and recording rules.\",\n  \"editable\": true,\n  \"gnetId\": 14114,\n  \"graphTooltip\": 0,\n  \"id\": 1,\n  \"iteration\": 1603191461722,\n  \"links\": [],\n  \"panels\": [\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"grid\": {},\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 20,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"hiddenSeries\": false,\n      \"id\": 1,\n      \"isNew\": true,\n      \"legend\": {\n        \"alignAsTable\": true,\n        \"avg\": true,\n        \"current\": false,\n        \"max\": true,\n        \"min\": true,\n        \"rightSide\": true,\n        \"show\": true,\n        \"total\": false,\n        \"values\": true\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"connected\",\n      \"options\": {\n        \"alertThreshold\": true\n      },\n      \"percentage\": false,\n      \"pluginVersion\": \"7.2.1\",\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"alias\": \"fetched\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_tup_fetched{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"fetched\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"tup_fetched\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 120,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"fetched\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_tup_returned{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"returned\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"B\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"tup_fetched\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 120,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"fetched\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_tup_inserted{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"inserted\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"C\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"tup_fetched\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 120,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"fetched\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_tup_updated{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"updated\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"D\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"tup_fetched\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 120,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"fetched\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_tup_deleted{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"deleted\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"E\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"tup_fetched\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 120,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"Rows\",\n      \"tooltip\": {\n        \"msResolution\": true,\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"cumulative\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"cacheTimeout\": null,\n      \"colorBackground\": false,\n      \"colorValue\": false,\n      \"colors\": [\n        \"rgba(245, 54, 54, 0.9)\",\n        \"rgba(237, 129, 40, 0.89)\",\n        \"rgba(50, 172, 45, 0.97)\"\n      ],\n      \"datasource\": \"$datasource\",\n      \"decimals\": 0,\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"format\": \"none\",\n      \"gauge\": {\n        \"maxValue\": 100,\n        \"minValue\": 0,\n        \"show\": false,\n        \"thresholdLabels\": false,\n        \"thresholdMarkers\": true\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 0\n      },\n      \"height\": \"55px\",\n      \"id\": 11,\n      \"interval\": null,\n      \"isNew\": true,\n      \"links\": [],\n      \"mappingType\": 1,\n      \"mappingTypes\": [\n        {\n          \"name\": \"value to text\",\n          \"value\": 1\n        },\n        {\n          \"name\": \"range to text\",\n          \"value\": 2\n        }\n      ],\n      \"maxDataPoints\": 100,\n      \"nullPointMode\": \"connected\",\n      \"nullText\": null,\n      \"postfix\": \"\",\n      \"postfixFontSize\": \"50%\",\n      \"prefix\": \"\",\n      \"prefixFontSize\": \"50%\",\n      \"rangeMaps\": [\n        {\n          \"from\": \"null\",\n          \"text\": \"N/A\",\n          \"to\": \"null\"\n        }\n      ],\n      \"sparkline\": {\n        \"fillColor\": \"rgba(31, 118, 189, 0.18)\",\n        \"full\": true,\n        \"lineColor\": \"rgb(31, 120, 193)\",\n        \"show\": true\n      },\n      \"tableColumn\": \"\",\n      \"targets\": [\n        {\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(irate(pg_stat_database_xact_commit{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m])) + sum(irate(pg_stat_database_xact_rollback{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"xact_commit\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [\n                  \"10s\"\n                ],\n                \"type\": \"non_negative_derivative\"\n              }\n            ]\n          ],\n          \"step\": 1800,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        }\n      ],\n      \"thresholds\": \"\",\n      \"title\": \"QPS\",\n      \"transparent\": true,\n      \"type\": \"singlestat\",\n      \"valueFontSize\": \"80%\",\n      \"valueMaps\": [\n        {\n          \"op\": \"=\",\n          \"text\": \"N/A\",\n          \"value\": \"null\"\n        }\n      ],\n      \"valueName\": \"avg\"\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"decimals\": 1,\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"grid\": {},\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 7\n      },\n      \"hiddenSeries\": false,\n      \"id\": 2,\n      \"isNew\": true,\n      \"legend\": {\n        \"alignAsTable\": true,\n        \"avg\": true,\n        \"current\": false,\n        \"hideZero\": true,\n        \"max\": true,\n        \"min\": true,\n        \"rightSide\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": true\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"links\": [],\n      \"nullPointMode\": \"connected\",\n      \"options\": {\n        \"alertThreshold\": true\n      },\n      \"percentage\": false,\n      \"pluginVersion\": \"7.2.1\",\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"alias\": \"Buffers Allocated\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"irate(pg_stat_bgwriter_buffers_alloc{instance=~'$instance'}[5m])\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"buffers_alloc\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"buffers_alloc\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"Buffers Allocated\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"irate(pg_stat_bgwriter_buffers_backend_fsync{instance=~'$instance'}[5m])\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"buffers_backend_fsync\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"B\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"buffers_alloc\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"Buffers Allocated\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"irate(pg_stat_bgwriter_buffers_backend{instance=~'$instance'}[5m])\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"buffers_backend\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"C\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"buffers_alloc\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"Buffers Allocated\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"irate(pg_stat_bgwriter_buffers_clean{instance=~'$instance'}[5m])\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"buffers_clean\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"D\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"buffers_alloc\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"Buffers Allocated\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"irate(pg_stat_bgwriter_buffers_checkpoint{instance=~'$instance'}[5m])\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"buffers_checkpoint\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"E\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"buffers_alloc\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"Buffers\",\n      \"tooltip\": {\n        \"msResolution\": false,\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"cumulative\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": 0,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"grid\": {},\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 7\n      },\n      \"hiddenSeries\": false,\n      \"id\": 3,\n      \"isNew\": true,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 2,\n      \"links\": [],\n      \"nullPointMode\": \"connected\",\n      \"options\": {\n        \"alertThreshold\": true\n      },\n      \"percentage\": false,\n      \"pluginVersion\": \"7.2.1\",\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"alias\": \"conflicts\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(rate(pg_stat_database_deadlocks{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"deadlocks\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"conflicts\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        },\n        {\n          \"alias\": \"deadlocks\",\n          \"dsType\": \"prometheus\",\n          \"expr\": \"sum(rate(pg_stat_database_conflicts{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}[5m]))\",\n          \"format\": \"time_series\",\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"conflicts\",\n          \"measurement\": \"postgresql\",\n          \"policy\": \"default\",\n          \"refId\": \"B\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"deadlocks\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"difference\"\n              }\n            ]\n          ],\n          \"step\": 240,\n          \"tags\": [\n            {\n              \"key\": \"instance\",\n              \"operator\": \"=~\",\n              \"value\": \"/^$instance$/\"\n            }\n          ]\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"Conflicts/Deadlocks\",\n      \"tooltip\": {\n        \"msResolution\": false,\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"cumulative\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": 0,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"grid\": {},\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 14\n      },\n      \"hiddenSeries\": false,\n      \"id\": 12,\n      \"isNew\": true,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 2,\n      \"links\": [],\n      \"nullPointMode\": \"connected\",\n      \"options\": {\n        \"alertThreshold\": true\n      },\n      \"percentage\": true,\n      \"pluginVersion\": \"7.2.1\",\n      \"pointradius\": 1,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"sum(pg_stat_database_blks_hit{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}) / (sum(pg_stat_database_blks_hit{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}) + sum(pg_stat_database_blks_read{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}))\",\n          \"format\": \"time_series\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"cache hit rate\",\n          \"refId\": \"A\",\n          \"step\": 240\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"Cache hit ratio\",\n      \"tooltip\": {\n        \"msResolution\": false,\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"cumulative\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"percentunit\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": false,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"$datasource\",\n      \"editable\": true,\n      \"error\": false,\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"grid\": {},\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 14\n      },\n      \"hiddenSeries\": false,\n      \"id\": 13,\n      \"isNew\": true,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 2,\n      \"links\": [],\n      \"nullPointMode\": \"connected\",\n      \"options\": {\n        \"alertThreshold\": true\n      },\n      \"percentage\": false,\n      \"pluginVersion\": \"7.2.1\",\n      \"pointradius\": 5,\n      \"points\": false,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"expr\": \"pg_stat_database_numbackends{datname=~\\\"$db\\\",instance=~\\\"$instance\\\"}\",\n          \"format\": \"time_series\",\n          \"intervalFactor\": 2,\n          \"legendFormat\": \"{{__name__}}\",\n          \"refId\": \"A\",\n          \"step\": 240\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"Number of active connections\",\n      \"tooltip\": {\n        \"msResolution\": false,\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"cumulative\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    }\n  ],\n  \"refresh\": false,\n  \"schemaVersion\": 26,\n  \"style\": \"dark\",\n  \"tags\": [\n    \"postgres\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"allValue\": \".*\",\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"All\",\n          \"value\": \"$__all\"\n        },\n        \"datasource\": \"$datasource\",\n        \"definition\": \"\",\n        \"hide\": 0,\n        \"includeAll\": true,\n        \"label\": null,\n        \"multi\": false,\n        \"name\": \"instance\",\n        \"options\": [],\n        \"query\": \"label_values(up{job=~\\\"postgres.*\\\"},instance)\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 0,\n        \"tagValuesQuery\": \"\",\n        \"tags\": [],\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      },\n      {\n        \"allValue\": \".*\",\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"All\",\n          \"value\": \"$__all\"\n        },\n        \"datasource\": \"$datasource\",\n        \"definition\": \"label_values(pg_stat_database_tup_fetched{instance=~\\\"$instance\\\",datname!~\\\"template.*|postgres\\\"},datname)\",\n        \"hide\": 0,\n        \"includeAll\": true,\n        \"label\": \"db\",\n        \"multi\": false,\n        \"name\": \"db\",\n        \"options\": [],\n        \"query\": \"label_values(pg_stat_database_tup_fetched{instance=~\\\"$instance\\\",datname!~\\\"template.*|postgres\\\"},datname)\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 0,\n        \"tagValuesQuery\": \"\",\n        \"tags\": [],\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      },\n      {\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"Postgres Overview\",\n          \"value\": \"Postgres Overview\"\n        },\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"datasource\",\n        \"multi\": false,\n        \"name\": \"datasource\",\n        \"options\": [],\n        \"query\": \"prometheus\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"type\": \"datasource\"\n      },\n      {\n        \"allValue\": null,\n        \"current\": {\n          \"selected\": true,\n          \"text\": \"postgres\",\n          \"value\": \"postgres\"\n        },\n        \"datasource\": \"$datasource\",\n        \"definition\": \"label_values(pg_up, job)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"job\",\n        \"multi\": false,\n        \"name\": \"job\",\n        \"options\": [\n          {\n            \"selected\": true,\n            \"text\": \"postgres\",\n            \"value\": \"postgres\"\n          }\n        ],\n        \"query\": \"label_values(pg_up, job)\",\n        \"refresh\": 0,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 0,\n        \"tagValuesQuery\": \"\",\n        \"tags\": [],\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-1h\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"5s\",\n      \"10s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"15m\",\n      \"30m\",\n      \"1h\",\n      \"2h\",\n      \"1d\"\n    ],\n    \"time_options\": [\n      \"5m\",\n      \"15m\",\n      \"1h\",\n      \"6h\",\n      \"12h\",\n      \"24h\",\n      \"2d\",\n      \"7d\",\n      \"30d\"\n    ]\n  },\n  \"timezone\": \"browser\",\n  \"title\": \"PostgreSQL Exporter Quickstart and Dashboard\",\n  \"uid\": \"wGgaPlciz\",\n  \"version\": 5\n}\n"
  },
  {
    "path": "deployments/configs/grafana/dashboards/rabbitmq.json",
    "content": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_PROMETHEUS\",\n      \"label\": \"prometheus\",\n      \"description\": \"\",\n      \"type\": \"datasource\",\n      \"pluginId\": \"prometheus\",\n      \"pluginName\": \"Prometheus\"\n    }\n  ],\n  \"__elements\": [],\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"8.3.4\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"prometheus\",\n      \"name\": \"Prometheus\",\n      \"version\": \"1.0.0\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"stat\",\n      \"name\": \"Stat\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"table\",\n      \"name\": \"Table\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"timeseries\",\n      \"name\": \"Time series\",\n      \"version\": \"\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": \"-- Grafana --\",\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"target\": {\n          \"limit\": 100,\n          \"matchAny\": false,\n          \"tags\": [],\n          \"type\": \"dashboard\"\n        },\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"description\": \"A new RabbitMQ Management Overview\",\n  \"editable\": true,\n  \"fiscalYearStartMonth\": 0,\n  \"graphTooltip\": 1,\n  \"id\": null,\n  \"iteration\": 1659711638455,\n  \"links\": [\n    {\n      \"icon\": \"doc\",\n      \"tags\": [],\n      \"targetBlank\": true,\n      \"title\": \"Monitoring with Prometheus & Grafana\",\n      \"tooltip\": \"\",\n      \"type\": \"link\",\n      \"url\": \"https://www.rabbitmq.com/prometheus.html\"\n    }\n  ],\n  \"liveNow\": false,\n  \"panels\": [\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#37872D\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 10000\n              },\n              {\n                \"color\": \"#C4162A\",\n                \"value\": 100000\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": []\n      },\n      \"id\": 64,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"hide\": false,\n          \"instant\": false,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Ready messages\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": -1\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 50\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 0\n      },\n      \"id\": 62,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Incoming messages / s\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 12,\n        \"y\": 0\n      },\n      \"id\": 66,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_global_publishers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Publishers\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 16,\n        \"y\": 0\n      },\n      \"id\": 37,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Connections\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 0\n      },\n      \"id\": 40,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Queues\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#37872D\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 100\n              },\n              {\n                \"color\": \"#C4162A\",\n                \"value\": 500\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 3\n      },\n      \"id\": 65,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"hide\": false,\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Unacknowledged messages\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": -1\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 50\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 3\n      },\n      \"id\": 63,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) +\\nsum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) +\\nsum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) +\\nsum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) +\\nsum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"hide\": false,\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Outgoing messages / s\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 12,\n        \"y\": 3\n      },\n      \"id\": 41,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_consumers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Consumers\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#C4162A\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 16,\n        \"y\": 3\n      },\n      \"id\": 38,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Channels\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [\n            {\n              \"options\": {\n                \"match\": \"null\",\n                \"result\": {\n                  \"text\": \"N/A\"\n                }\n              },\n              \"type\": \"special\"\n            }\n          ],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"#1F60C4\",\n                \"value\": null\n              },\n              {\n                \"color\": \"#37872D\",\n                \"value\": 3\n              },\n              {\n                \"color\": \"#C4162A\",\n                \"value\": 8\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 3\n      },\n      \"id\": 67,\n      \"links\": [],\n      \"maxDataPoints\": 100,\n      \"options\": {\n        \"colorMode\": \"background\",\n        \"graphMode\": \"area\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"horizontal\",\n        \"reduceOptions\": {\n          \"calcs\": [\n            \"lastNotNull\"\n          ],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"textMode\": \"auto\"\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Nodes\",\n      \"type\": \"stat\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 6\n      },\n      \"id\": 4,\n      \"panels\": [],\n      \"title\": \"NODES\",\n      \"type\": \"row\"\n    },\n    {\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"displayMode\": \"auto\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"erlang_version\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"Erlang/OTP\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"none\"\n              },\n              {\n                \"id\": \"custom.align\"\n              },\n              {\n                \"id\": \"thresholds\",\n                \"value\": {\n                  \"mode\": \"absolute\",\n                  \"steps\": [\n                    {\n                      \"color\": \"rgba(50, 172, 45, 0.97)\",\n                      \"value\": null\n                    },\n                    {\n                      \"color\": \"rgba(237, 129, 40, 0.89)\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"rabbitmq_version\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"RabbitMQ\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"none\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              },\n              {\n                \"id\": \"thresholds\",\n                \"value\": {\n                  \"mode\": \"absolute\",\n                  \"steps\": [\n                    {\n                      \"color\": \"rgba(245, 54, 54, 0.9)\",\n                      \"value\": null\n                    },\n                    {\n                      \"color\": \"rgba(237, 129, 40, 0.89)\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"instance\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"Host\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"rabbitmq_node\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"Node name\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              },\n              {\n                \"id\": \"thresholds\",\n                \"value\": {\n                  \"mode\": \"absolute\",\n                  \"steps\": [\n                    {\n                      \"color\": \"rgba(245, 54, 54, 0.9)\",\n                      \"value\": null\n                    },\n                    {\n                      \"color\": \"rgba(237, 129, 40, 0.89)\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Time\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Value\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"job\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"rabbitmq_cluster\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"Cluster\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"prometheus_client_version\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"prometheus.erl\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"prometheus_plugin_version\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"displayName\",\n                \"value\": \"rabbitmq_prometheus\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"short\"\n              },\n              {\n                \"id\": \"decimals\",\n                \"value\": 2\n              },\n              {\n                \"id\": \"custom.align\"\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 7\n      },\n      \"id\": 69,\n      \"links\": [],\n      \"options\": {\n        \"footer\": {\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"showHeader\": true\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"exemplar\": false,\n          \"expr\": \"rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\",\n          \"format\": \"table\",\n          \"instant\": true,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"transformations\": [\n        {\n          \"id\": \"merge\",\n          \"options\": {\n            \"reducers\": []\n          }\n        }\n      ],\n      \"type\": \"table\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"If the value is zero or less, the memory alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\\n\\nThis value can temporarily go negative because the memory alarm is triggered with a slight delay.\\n\\nThe kernel's view of the amount of memory used by the node can differ from what the node itself can observe. This means that this value can be negative for a sustained period of time.\\n\\nBy default nodes use resident set size (RSS) to compute how much memory they use. This strategy can be changed (see the guides below).\\n\\n* [Alarms](https://www.rabbitmq.com/alarms.html)\\n* [Memory Alarms](https://www.rabbitmq.com/memory.html)\\n* [Reasoning About Memory Use](https://www.rabbitmq.com/memory-use.html)\\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": true,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"decimals\": 1,\n          \"links\": [],\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"red\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 0\n              },\n              {\n                \"color\": \"transparent\",\n                \"value\": 536870912\n              }\n            ]\n          },\n          \"unit\": \"bytes\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 11\n      },\n      \"id\": 7,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"(rabbitmq_resident_memory_limit_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) -\\n(rabbitmq_process_resident_memory_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Memory available before publishers blocked\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"This metric is reported for the partition where the RabbitMQ data directory is stored.\\n\\nIf the value is zero or less, the disk alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\\n\\nThis value can temporarily go negative because the free disk space alarm is triggered with a slight delay.\\n\\n* [Alarms](https://www.rabbitmq.com/alarms.html)\\n* [Disk Space Alarms](https://www.rabbitmq.com/disk-alarms.html)\\n* [Disk Space](https://www.rabbitmq.com/production-checklist.html#resource-limits-disk-space)\\n* [Persistence Configuration](https://www.rabbitmq.com/persistence-conf.html)\\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": true,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"decimals\": 1,\n          \"links\": [],\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"red\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 1073741824\n              },\n              {\n                \"color\": \"transparent\",\n                \"value\": 5368709120\n              }\n            ]\n          },\n          \"unit\": \"bytes\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 8,\n        \"x\": 12,\n        \"y\": 11\n      },\n      \"id\": 8,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"rabbitmq_disk_space_available_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Disk space available before publishers blocked\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"When this value reaches zero, new connections will not be accepted and disk write operations may fail.\\n\\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\\n\\n* [Open File Handles Limit](https://www.rabbitmq.com/production-checklist.html#resource-limits-file-handle-limit)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": true,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"red\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 500\n              },\n              {\n                \"color\": \"transparent\",\n                \"value\": 1000\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 11\n      },\n      \"id\": 2,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"(rabbitmq_process_max_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) -\\n(rabbitmq_process_open_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"File descriptors available\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"When this value reaches zero, new connections will not be accepted.\\n\\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\\n\\n* [Networking and RabbitMQ](https://www.rabbitmq.com/networking.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": true,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"red\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 500\n              },\n              {\n                \"color\": \"transparent\",\n                \"value\": 1000\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 4,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 15\n      },\n      \"id\": 5,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"(rabbitmq_process_max_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) -\\n(rabbitmq_process_open_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"TCP sockets available\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 19\n      },\n      \"id\": 27,\n      \"panels\": [],\n      \"title\": \"QUEUED MESSAGES\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Total number of ready messages ready to be delivered to consumers.\\n\\nAim to keep this value as low as possible. RabbitMQ behaves best when messages are flowing through it. It's OK for publishers to occasionally outpace consumers, but the expectation is that consumers will eventually process all ready messages.\\n\\nIf this metric keeps increasing, your system will eventually run out of memory and/or disk space. Consider using TTL or Queue Length Limit to prevent unbounded message growth.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\\n* [Queue Length Limit](https://www.rabbitmq.com/maxlength.html)\\n* [Time-To-Live and Expiration](https://www.rabbitmq.com/ttl.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 20\n      },\n      \"id\": 9,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages ready to be delivered to consumers\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The total number of messages that are either in-flight to consumers, currently being processed by consumers or simply waiting for the consumer acknowledgements to be processed by the queue. Until the queue processes the message acknowledgement, the message will remain unacknowledged.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 20\n      },\n      \"id\": 19,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages pending consumer acknowledgement\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 25\n      },\n      \"id\": 11,\n      \"panels\": [],\n      \"title\": \"INCOMING MESSAGES\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The incoming message rate before any routing rules are applied.\\n\\nIf this value is lower than the number of messages published to queues, it may indicate that some messages are delivered to more than one queue.\\n\\nIf this value is higher than the number of messages published to queues, messages cannot be routed and will either be dropped or returned to publishers.\\n\\n* [Publishers](https://www.rabbitmq.com/publishers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 26\n      },\n      \"id\": 13,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages published / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages confirmed by the broker to publishers. Publishers must opt-in to receive message confirmations.\\n\\nIf this metric is consistently at zero it may suggest that publisher confirms are not used by clients. The safety of published messages is likely to be at risk.\\n\\n* [Publisher Confirms](https://www.rabbitmq.com/confirms.html#publisher-confirms)\\n* [Publisher Confirms and Data Safety](https://www.rabbitmq.com/publishers.html#data-safety)\\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 26\n      },\n      \"id\": 18,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages confirmed to publishers / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages received from publishers and successfully routed to the master queue replicas.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\\n* [Publishers](https://www.rabbitmq.com/publishers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 31\n      },\n      \"id\": 61,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_routed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages routed to queues / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages received from publishers that have publisher confirms enabled and the broker has not confirmed yet.\\n\\n* [Publishers](https://www.rabbitmq.com/publishers.html)\\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": true,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 31\n      },\n      \"id\": 12,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_received_confirm_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"} - \\nrate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\\n) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages unconfirmed to publishers / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages that cannot be routed and are dropped. \\n\\nAny value above zero means message loss and likely suggests a routing problem on the publisher end.\\n\\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 0\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/rabbit/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#C4162A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 36\n      },\n      \"id\": 34,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_unroutable_dropped_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Unroutable messages dropped / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages that cannot be routed and are returned back to publishers.\\n\\nSustained values above zero may indicate a routing problem on the publisher end.\\n\\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)\\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 0\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/rabbit/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#C4162A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 36\n      },\n      \"id\": 16,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_unroutable_returned_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Unroutable messages returned to publishers / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 41\n      },\n      \"id\": 29,\n      \"panels\": [],\n      \"title\": \"OUTGOING MESSAGES\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages delivered to consumers. It includes messages that have been redelivered.\\n\\nThis metric does not include messages that have been fetched by consumers using `basic.get` (consumed by polling).\\n\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 42\n      },\n      \"id\": 14,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(\\n  (rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) +\\n  (rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"})\\n) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages delivered / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages that have been redelivered to consumers. It includes messages that have been requeued automatically and redelivered due to channel exceptions or connection closures.\\n\\nHaving some redeliveries is expected, but if this metric is consistently non-zero, it is worth investigating why.\\n\\n* [Negative Acknowledgement and Requeuing of Deliveries](https://www.rabbitmq.com/confirms.html#consumer-nacks-requeue)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 20\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 100\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 42\n      },\n      \"id\": 15,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages redelivered / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of message deliveries to consumers that use manual acknowledgement mode.\\n\\nWhen this mode is used, RabbitMQ waits for consumers to acknowledge messages before more messages can be delivered.\\n\\nThis is the safest way of consuming messages.\\n\\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 47\n      },\n      \"id\": 20,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages delivered with manual ack / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of message deliveries to consumers that use automatic acknowledgement mode.\\n\\nWhen this mode is used, RabbitMQ does not wait for consumers to acknowledge message deliveries.\\n\\nThis mode is fire-and-forget and does not offer any delivery safety guarantees. It tends to provide higher throughput and it may lead to consumer overload  and higher consumer memory usage.\\n\\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 47\n      },\n      \"id\": 21,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages delivered auto ack / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of message acknowledgements coming from consumers that use manual acknowledgement mode.\\n\\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"decimals\": 0,\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 52\n      },\n      \"id\": 22,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_acknowledged_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Messages acknowledged / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages delivered to polling consumers that use automatic acknowledgement mode.\\n\\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\\n\\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 0\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/rabbit/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#C4162A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 52\n      },\n      \"id\": 24,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Polling operations with auto ack / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of polling consumer operations that yield no result.\\n\\nAny value above zero means that RabbitMQ resources are wasted by polling consumers.\\n\\nCompare this metric to the other polling consumer metrics to see the inefficiency rate.\\n\\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\\n\\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 0\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/rabbit/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#C4162A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 57\n      },\n      \"id\": 25,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_get_empty_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Polling operations that yield no result / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of messages delivered to polling consumers that use manual acknowledgement mode.\\n\\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\\n\\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\\n* [Consumers](https://www.rabbitmq.com/consumers.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 0\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/rabbit/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#C4162A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 57\n      },\n      \"id\": 23,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Polling operations with manual ack / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 62\n      },\n      \"id\": 53,\n      \"panels\": [],\n      \"title\": \"QUEUES\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Total number of queue masters  per node. \\n\\nThis metric makes it easy to see sub-optimal queue distribution in a cluster.\\n\\n* [Queue Masters, Data Locality](https://www.rabbitmq.com/ha.html#master-migration-data-locality)\\n* [Queues](https://www.rabbitmq.com/queues.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 63\n      },\n      \"id\": 57,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Total queues\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of queue declarations performed by clients.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 4,\n        \"x\": 12,\n        \"y\": 63\n      },\n      \"id\": 58,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_queues_declared_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Queues declared / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of new queues created (as opposed to redeclarations).\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 4,\n        \"x\": 16,\n        \"y\": 63\n      },\n      \"id\": 60,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_queues_created_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Queues created / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of queues deleted.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\\n\\n* [Queues](https://www.rabbitmq.com/queues.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 4,\n        \"x\": 20,\n        \"y\": 63\n      },\n      \"id\": 59,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_queues_deleted_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Queues deleted / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 68\n      },\n      \"id\": 51,\n      \"panels\": [],\n      \"title\": \"CHANNELS\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Total number of channels on all currently opened connections.\\n\\nIf this metric grows monotonically it is highly likely a channel leak in one of the applications. Confirm channel leaks by using the _Channels opened_ and _Channels closed_ metrics.\\n\\n* [Channel Leak](https://www.rabbitmq.com/channels.html#channel-leaks)\\n* [Channels](https://www.rabbitmq.com/channels.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 69\n      },\n      \"id\": 54,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Total channels\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of new channels opened by applications across all connections. Channels are expected to be long-lived.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\\n\\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\\n* [Channels](https://www.rabbitmq.com/channels.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 69\n      },\n      \"id\": 55,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_channels_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Channels opened / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of channels closed by applications across all connections. Channels are expected to be long-lived.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\\n\\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\\n* [Channels](https://www.rabbitmq.com/channels.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 69\n      },\n      \"id\": 56,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_channels_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Channels closed / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 74\n      },\n      \"id\": 46,\n      \"panels\": [],\n      \"title\": \"CONNECTIONS\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Total number of client connections.\\n\\nIf this metric grows monotonically it is highly likely a connection leak in one of the applications. Confirm connection leaks by using the _Connections opened_ and _Connections closed_ metrics.\\n\\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\\n* [Connections](https://www.rabbitmq.com/connections.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 80\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 75\n      },\n      \"id\": 47,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Total connections\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of new connections opened by clients. Connections are expected to be long-lived.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\\n\\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\\n* [Connections](https://www.rabbitmq.com/connections.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 75\n      },\n      \"id\": 48,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_connections_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"interval\": \"\",\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Connections opened / s\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"The rate of connections closed. Connections are expected to be long-lived.\\n\\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\\n\\n* [Connections](https://www.rabbitmq.com/connections.html)\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 100,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"never\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"normal\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"line+area\"\n            }\n          },\n          \"links\": [],\n          \"mappings\": [],\n          \"min\": 0,\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"transparent\",\n                \"value\": null\n              },\n              {\n                \"color\": \"orange\",\n                \"value\": 2\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 10\n              }\n            ]\n          },\n          \"unit\": \"short\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?0(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#56A64B\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?1(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#F2CC0C\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?2(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#3274D9\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?3(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#A352CC\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?4(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FF780A\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?5(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#96D98D\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?6(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFEE52\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?7(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#8AB8FF\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?8(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#CA95E5\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"/^rabbit@[a-zA-Z\\\\.\\\\-]*?9(\\\\b|\\\\.)/\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"#FFB357\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 75\n      },\n      \"id\": 49,\n      \"links\": [],\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [\n            \"lastNotNull\",\n            \"max\",\n            \"min\"\n          ],\n          \"displayMode\": \"hidden\",\n          \"placement\": \"bottom\"\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\"\n        }\n      },\n      \"pluginVersion\": \"8.3.4\",\n      \"targets\": [\n        {\n          \"expr\": \"sum(rate(rabbitmq_connections_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\\\"$rabbitmq_cluster\\\", namespace=\\\"$namespace\\\"}) by(rabbitmq_node)\",\n          \"format\": \"time_series\",\n          \"instant\": false,\n          \"intervalFactor\": 1,\n          \"legendFormat\": \"{{rabbitmq_node}}\",\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Connections closed / s\",\n      \"type\": \"timeseries\"\n    }\n  ],\n  \"refresh\": \"15s\",\n  \"schemaVersion\": 34,\n  \"style\": \"dark\",\n  \"tags\": [\n    \"rabbitmq-prometheus\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"default\",\n          \"value\": \"default\"\n        },\n        \"datasource\": \"PBFA97CFB590B2093\",\n        \"hide\": 2,\n        \"includeAll\": false,\n        \"label\": \"datasource\",\n        \"multi\": false,\n        \"name\": \"DS_PROMETHEUS\",\n        \"options\": [],\n        \"query\": \"prometheus\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"type\": \"datasource\"\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_PROMETHEUS}\"\n        },\n        \"definition\": \"label_values(rabbitmq_identity_info, namespace)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Namespace\",\n        \"multi\": false,\n        \"name\": \"namespace\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(rabbitmq_identity_info, namespace)\",\n          \"refId\": \"Prometheus-namespace-Variable-Query\"\n        },\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"tagValuesQuery\": \"\",\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      },\n      {\n        \"current\": {},\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_PROMETHEUS}\"\n        },\n        \"definition\": \"label_values(rabbitmq_identity_info{namespace=\\\"$namespace\\\"}, rabbitmq_cluster)\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"RabbitMQ Cluster\",\n        \"multi\": false,\n        \"name\": \"rabbitmq_cluster\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(rabbitmq_identity_info{namespace=\\\"$namespace\\\"}, rabbitmq_cluster)\",\n          \"refId\": \"Prometheus-rabbitmq_cluster-Variable-Query\"\n        },\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 1,\n        \"tagValuesQuery\": \"\",\n        \"tagsQuery\": \"\",\n        \"type\": \"query\",\n        \"useTags\": false\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-15m\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"15s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"10m\"\n    ],\n    \"time_options\": [\n      \"5m\",\n      \"15m\",\n      \"1h\",\n      \"6h\",\n      \"12h\",\n      \"24h\",\n      \"2d\",\n      \"7d\",\n      \"30d\"\n    ]\n  },\n  \"timezone\": \"\",\n  \"title\": \"RabbitMQ-Overview\",\n  \"uid\": \"Kn5xm-gZk\",\n  \"version\": 20220805,\n  \"weekStart\": \"\",\n  \"gnetId\": 10991\n}\n"
  },
  {
    "path": "deployments/configs/grafana/provisioning/dashboards/dashboard.yml",
    "content": "# https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards\napiVersion: 1\n\nproviders:\n  - name: \"default\"\n    orgId: 1\n    folder: \"\"\n    type: file\n    disableDeletion: false\n    editable: true\n    allowUiUpdates: true\n    updateIntervalSeconds: 5 # how often Grafana will scan for changed dashboards\n    options:\n      path: /var/lib/grafana/dashboards # path to dashboards on disk\n"
  },
  {
    "path": "deployments/configs/grafana/provisioning/datasources/datasource.yml",
    "content": "# https://grafana.com/docs/grafana/latest/administration/provisioning/\n# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml\n# https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml\n\napiVersion: 1\n\ndatasources:\n  # https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml\n  - name: Prometheus\n    type: prometheus\n    typeName: Prometheus\n    uid: prometheus-uid\n    access: proxy\n    orgId: 1\n    url: http://prometheus:9090\n    basicAuth: false\n    isDefault: true\n    readOnly: false\n    user: ''\n    database: ''\n    version: 1\n    editable: false\n    jsonData:\n      httpMethod: GET\n\n  - name: Jaeger\n    type: jaeger\n    access: proxy\n    url: http://jaeger-all-in-one:16686\n    editable: false\n    uid: jaeger-uid\n\n  - name: Zipkin\n    type: zipkin\n    access: proxy\n    url: http://zipkin-all-in-one:9411\n    editable: false\n    uid: zipkin-uid\n\n  # https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/grafana-datasources.yaml\n  - name: Tempo\n    type: tempo\n    access: proxy\n    orgId: 1\n    url: http://tempo:3200\n    basicAuth: false\n    isDefault: false\n    version: 1\n    editable: false\n    apiVersion: 1\n    uid: tempo-uid\n    jsonData:\n      httpMethod: GET\n      serviceMap:\n        datasourceUid: prometheus-uid\n      streamingEnabled:\n        search: true\n\n  #https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml\n  - name: Loki\n    type: loki\n    access: proxy\n    uid: loki-uid\n    url: http://loki:3100\n    user: ''\n    database: ''\n    readOnly: false\n    jsonData:\n      derivedFields:\n        - datasourceUid: tempo-uid\n          matcherRegex: \"^.*?traceI[d|D]=(\\\\w+).*$\"\n          name: traceId\n          url: '$${__value.raw}'\n\n  - name: Kibana\n    type: elasticsearch\n    url: http://elasticsearch:9200\n    access: proxy\n    isDefault: false\n    uid: kibana-uid\n    jsonData:\n      esVersion: 7\n      timeField: \"@timestamp\"\n      maxConcurrentShardRequests: 256\n      interval: Daily\n      logMessageField: \"message\" # Optional: Field for log messages\n      logLevelField: \"level\" # Optional: Field for log levels\n    editable: true\n"
  },
  {
    "path": "deployments/configs/loki-config.yaml",
    "content": "# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/\n# https://github.com/grafana/loki/issues/2018#issuecomment-970789233\n# https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/\n# https://github.com/grafana/loki/blob/main/examples/getting-started/loki-config.yaml\n# https://github.com/grafana/loki/blob/main/cmd/loki/loki-local-config.yaml\n# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/#1-local-configuration-exampleyaml\n\n---\n# https://grafana.com/docs/loki/latest/configure/examples/configuration-examples/#1-local-configuration-exampleyaml\nauth_enabled: false\n\n# This is a complete configuration to deploy Loki backed by the filesystem.\n# The index will be shipped to the storage via tsdb-shipper.\nserver:\n  http_listen_port: 3100\n\ncommon:\n  ring:\n    instance_addr: 127.0.0.1\n    kvstore:\n      store: inmemory\n  replication_factor: 1\n  path_prefix: /tmp/loki\n\nschema_config:\n  configs:\n    - from: 2020-05-15\n      store: tsdb\n      object_store: filesystem\n      schema: v13\n      index:\n        prefix: index_\n        period: 24h\n\nstorage_config:\n  filesystem:\n    directory: /tmp/loki/chunks\n\n# https://grafana.com/docs/loki/latest/send-data/otel/\n# https://grafana.com/docs/loki/latest/send-data/otel/#changing-the-default-mapping-of-otlp-to-loki-format\nlimits_config:\n  # this attribute should be `true` when we use `otlphttp/loki`, but if we want to use `loki component` from `opentelemetry-collector-contrib` it should be false.\n  allow_structured_metadata: true\n\n"
  },
  {
    "path": "deployments/configs/otel-collector-config.yaml",
    "content": "# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/otel-collector-config.yaml\n# https://opentelemetry.io/docs/collector/configuration/\n# https://opentelemetry.io/docs/collector/architecture/\n# https://betterstack.com/community/guides/observability/opentelemetry-collector/\n# https://signoz.io/blog/opentelemetry-collector-complete-guide/\n\n# This configuration sets up an OpenTelemetry Collector that receives trace data via the OTLP protocol over HTTP on port 4318, applies batch processing, and then exports the processed traces\n# to exporter components like `Jaeger` endpoint located at `jaeger-all-in-one:4317`. It also includes a health_check extension for monitoring the collector's status.\n\n# Receivers in the OpenTelemetry Collector are components that collect telemetry data (traces, metrics, and logs) from various sources, such as instrumented applications or agents.\n# They act as entry points, converting incoming data into OpenTelemetry's internal format for processing and export.\n# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components\n# https://opentelemetry.io/docs/collector/architecture/#receivers\n# https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md\n# https://opentelemetry.io/docs/collector/configuration/#receivers\nreceivers:\n  # supported receivers\n  # https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver\n  # instead of specifying details explicitly we can just use `otlp` and it uses both grpc and http\n  otlp:\n    protocols:\n      grpc:\n        endpoint: 0.0.0.0:4317\n      http:\n        endpoint: 0.0.0.0:4318\n#  prometheus:\n#    config:\n#      scrape_configs:\n#        - job_name: 'node-exporter'\n#          scrape_interval: 10s\n#          static_configs:\n#            - targets: [ 'node-exporter:9100' ]\n\n\n# Processors in the OpenTelemetry Collector modify and enhance telemetry data by filtering, transforming, enriching, or batching it to prepare it for export.\n# https://github.com/open-telemetry/opentelemetry-collector/tree/main/processor\nprocessors:\n  batch: # Batches logs for better performance\n\n# - Exporters in the OpenTelemetry Collector send processed telemetry data to backend systems like observability platforms, databases, or cloud services for storage, visualization, and analysis.\n# - The `key` follows the `type/name` format, where `type` specifies the exporter `type` (e.g., otlp, kafka, prometheus), and `name` (optional) can be appended to provide a unique name for multiple instance of the same type\n# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components\n# https://opentelemetry.io/docs/collector/architecture/#exporters\n# https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter\n# https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter\n# https://opentelemetry.io/docs/collector/configuration/#exporters\nexporters:\n\n  # valid values: [prometheusremotewrite zipkin otlphttp file kafka prometheus debug nop otlp opencensus]\n\n  # Prometheus exporter metrics\n  prometheus:\n    endpoint: \"0.0.0.0:8889\"\n\n  prometheusremotewrite:\n    endpoint: \"http://prometheus:9090/api/v1/write\"\n\n  # https://grafana.com/docs/loki/latest/send-data/otel/\n  # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/lokiexporter/README.md\n  otlphttp/loki:\n    endpoint: \"http://loki:3100/otlp\"\n    tls:\n      insecure: true\n\n      #  # we can also use `loki component` from `opentelemetry-collector-contrib` if we don't want to use builtin `otlphttp` exporter type and `http://loki:3100/otlp` loki endpoint\n      #  loki:\n      #    endpoint: \"http://loki:3100/loki/api/v1/push\"\n      #    tls:\n      #      insecure: true\n\n  debug:\n\n  # https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/elasticsearchexporter\n  # using `elasticsearch` from `opentelemetry-collector-contrib` components because it doesn't exist in `opentelemetry-collector`\n  elasticsearch:\n    endpoint: \"http://elasticsearch:9200\"\n\n  zipkin:\n    endpoint: \"http://zipkin-all-in-one:9411/api/v2/spans\"\n    format: proto\n\n  # export collected telemetry traces to jaeger OTLP grpc port, we can send data to other available endpoints and ports on jaeger as well\n  otlp/jaeger:\n    endpoint: \"http://jaeger-all-in-one:4317\"\n    tls:\n      insecure: true\n\n  otlp/tempo:\n    endpoint: \"http://tempo:4317\"\n    tls:\n      insecure: true\n\n      #  seq-otlp:\n      #    endpoint: \"http://seq:5341/ingest/otlp\"\n\n# https://opentelemetry.io/docs/collector/configuration/#extensions\n# https://github.com/open-telemetry/opentelemetry-collector/blob/main/extension/README.md\nextensions:\n  pprof:\n    endpoint: 0.0.0.0:1888\n  zpages:\n    endpoint: 0.0.0.0:55679\n  health_check:\n    endpoint: 0.0.0.0:13133\n\n# - The service section is used to configure what components are enabled in the Collector based on the configuration found in the receivers, processors, exporters, and extensions sections.\n# - If a component is configured, but not defined within the service section, then it’s not enabled.\n# https://betterstack.com/community/guides/observability/opentelemetry-collector/#exploring-the-opentelemetry-collector-components\n# https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md\n# https://opentelemetry.io/docs/collector/architecture/\n# https://opentelemetry.io/docs/collector/configuration/#service\nservice:\n  # The `service.extensions` subsection determines which of the configured extensions will be enabled\n  extensions: [pprof, zpages, health_check]\n  # The `service.pipeline` Each pipeline starts with one or more receivers collecting data, which is then processed sequentially by processors (applying transformations, filtering, or sampling).\n  # The processed data is finally sent to all configured exporters, ensuring each receives a copy. Components must be pre-configured in their respective sections before being used in a pipeline.\n  # pipeline activate predefined components, defined components are disabled by default\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: [batch]\n      # https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-selection\n      exporters: [debug, zipkin, otlp/jaeger, otlp/tempo]\n    metrics:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [debug, prometheusremotewrite, prometheus]\n    logs:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [otlphttp/loki, elasticsearch]\n"
  },
  {
    "path": "deployments/configs/prometheus.yaml",
    "content": "# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/prometheus.yaml\n# https://prometheus.io/docs/introduction/first_steps/\n# https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n\nglobal:\n  scrape_interval: 5s\n\nscrape_configs:\n    # when we use otel-collector we should comment other jobs in prometheus config, and we read configs from `otel-collector-config`\n  - job_name: \"otel-collector\"\n    scrape_interval: 10s\n    static_configs:\n      # otel-collector Prometheus exporter metrics\n      - targets: [ 'otel-collector:8889' ]\n      - targets: [ 'otel-collector:8888' ]\n\n  - job_name: \"prometheus\"\n    static_configs:\n      - targets: [\"prometheus:9090\"]\n\n#  # https://prometheus.io/docs/guides/node-exporter/\n#  # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n#  - job_name: \"node-exporter\"\n#    static_configs:\n#      - targets: [ 'node-exporter:9100' ]\n\n#  # if we don't use otel collector we should uncomment this\n#  # scrap application metrics\n#  # http://localhost:4000/metrics by AddPrometheusExporter()\n#  - job_name: vertical-slice-template-api\n#    scrape_interval: 10s\n#    metrics_path: /metrics\n#    static_configs:\n#      - targets: ['host.docker.internal:4000']\n#\n#  # if we don't use otel collector we should uncomment this\n#  # scrap application health metrics\n#  # http://localhost:4000/health/metrics  by AddPrometheusExporter()\n#  - job_name: vertical-slice-template-api-healthchecks\n#    scrape_interval: 10s\n#    metrics_path: /health/metrics\n#    static_configs:\n#      - targets: ['host.docker.internal:4000']\n\n## https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/prometheus.yaml\n#  - job_name: 'tempo'\n#    static_configs:\n#      - targets: [ 'tempo:3200' ]\n"
  },
  {
    "path": "deployments/configs/tempo.yaml",
    "content": "# https://grafana.com/docs/tempo/latest/configuration/\n# https://github.com/grafana/tempo/blob/main/example/docker-compose/local/tempo.yaml\n\n# https://github.com/grafana/tempo/blob/main/example/docker-compose/shared/tempo.yaml\nstream_over_http_enabled: true\nserver:\n  http_listen_port: 3200\n  log_level: info\n\ndistributor:\n  receivers:\n    otlp:\n      protocols:\n        grpc:\n          endpoint: \"tempo:4317\"\n\ningester:\n  max_block_duration: 5m               # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally\n\ncompactor:\n  compaction:\n    block_retention: 1h                # overall Tempo trace retention. set for demo purposes\n\nmetrics_generator:\n  registry:\n    external_labels:\n      source: tempo\n      cluster: docker-compose\n  storage:\n    path: /var/tempo/generator/wal\n    remote_write:\n      - url: http://prometheus:9090/api/v1/write\n        send_exemplars: true\n  traces_storage:\n    path: /var/tempo/generator/traces\n\nstorage:\n  trace:\n    backend: local                     # backend configuration to use\n    wal:\n      path: /var/tempo/wal             # where to store the wal locally\n    local:\n      path: /var/tempo/blocks\n\noverrides:\n  defaults:\n    metrics_generator:\n      processors: [service-graphs, span-metrics, local-blocks] # enables metrics generator\n      generate_native_histograms: both\n"
  },
  {
    "path": "deployments/docker-compose/docker-compose.infrastructure.yaml",
    "content": "# ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/examples/demo/docker-compose.yaml\n# ref: https://github.com/joaofbantunes/DotNetMicroservicesObservabilitySample/blob/main/docker-compose.yml\n# ref: https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/docker-compose.yml\n# https://github.com/grafana/intro-to-mltp\n# https://stackoverflow.com/questions/65272764/ports-are-not-available-listen-tcp-0-0-0-0-50070-bind-an-attempt-was-made-to\n\n\nname: booking-microservices-infrastructure\n\nservices:\n  #######################################################\n  #  rabbitmq\n  #######################################################\n  rabbitmq:\n    image: rabbitmq:management\n    container_name: rabbitmq\n    restart: unless-stopped\n    ports:\n      - \"5672:5672\"\n      - \"15672:15672\"\n      # volumes:\n      #   - rabbitmq:/var/lib/rabbitmq\n    networks:\n      - infrastructure\n\n  #######################################################\n  #  postgres\n  #######################################################\n  postgres:\n    image: postgres:latest\n    container_name: postgres\n    restart: unless-stopped\n    ports:\n      - '5432:5432'\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=postgres\n    command:\n      - \"postgres\"\n      - \"-c\"\n      - \"wal_level=logical\"\n      - \"-c\"\n      - \"max_prepared_transactions=10\"\n    volumes:\n      - postgres-data:/var/lib/postgresql/data\n    networks:\n      - infrastructure\n\n\n  #######################################################\n  #  EventStoreDB\n  #######################################################\n  eventstore:\n      container_name: eventstore\n      image: eventstore/eventstore:latest\n      restart: unless-stopped\n      environment:\n         - EVENTSTORE_CLUSTER_SIZE=1\n         - EVENTSTORE_RUN_PROJECTIONS=All\n         - EVENTSTORE_START_STANDARD_PROJECTIONS=True\n         - EVENTSTORE_HTTP_PORT=2113\n         - EVENTSTORE_INSECURE=True\n         - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=True\n      ports:\n          - \"2113:2113\"\n      networks:\n          - infrastructure\n\n\n  # #######################################################\n  # #  Mongo\n  # #######################################################\n  mongo:\n    image: mongo:latest\n    container_name: mongo\n    restart: unless-stopped\n    # environment:\n    #   - MONGO_INITDB_ROOT_USERNAME=root\n    #   - MONGO_INITDB_ROOT_PASSWORD=secret\n    ports:\n      - 27017:27017\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  Redis\n  # #######################################################\n  redis:\n    image: redis\n    container_name: redis\n    restart: unless-stopped\n    ports:\n      - 6379:6379\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  jaeger\n  # # https://www.jaegertracing.io/docs/1.64/deployment/\n  # # https://www.jaegertracing.io/docs/1.6/deployment/\n  # #######################################################\n  jaeger-all-in-one:\n    image: jaegertracing/all-in-one:latest\n    container_name: jaeger-all-in-one\n    restart: unless-stopped\n    ports:\n      - \"6831:6831/udp\" # UDP port for Jaeger agent\n      - \"16686:16686\" # endpoints and Jaeger UI\n      - \"14268:14268\" # HTTP port for accept trace spans directly from clients\n      - \"14317:4317\" # OTLP gRPC receiver for jaeger\n      - \"14318:4318\" # OTLP http receiver for jaeger\n      # - \"9411\" # Accepts Zipkin spans - /api/v2/spans\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  zipkin\n  # # https://zipkin.io/pages/quickstart\n  # #######################################################\n  zipkin-all-in-one:\n    image: openzipkin/zipkin:latest\n    container_name: zipkin-all-in-one\n    restart: unless-stopped\n    ports:\n      - \"9411:9411\"\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  otel-collector\n  # # https://opentelemetry.io/docs/collector/installation/\n  # # https://github.com/open-telemetry/opentelemetry-collector\n  # # https://github.com/open-telemetry/opentelemetry-collector-contrib\n  # # we can use none contrib docker `otel/opentelemetry-collector` version from `https://github.com/open-telemetry/opentelemetry-collector` repository but,\n  # # if we need more components like `elasticsearch` we should use `otel/opentelemetry-collector-contrib` image of `https://github.com/open-telemetry/opentelemetry-collector-contrib` repository.\n  # #######################################################\n  otel-collector:\n    image: otel/opentelemetry-collector-contrib:latest\n    container_name: otel-collector\n    restart: unless-stopped\n    command: [\"--config=/etc/otelcol-contrib/config.yaml\"]\n    volumes:\n      - ./../configs/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml\n    ports:\n      - \"11888:1888\" # pprof extension\n      - \"8888:8888\" # Prometheus metrics exposed by the Collector\n      - \"8889:8889\" # Prometheus exporter metrics\n      - \"13133:13133\" # health_check extension\n      - \"4317:4317\" # OTLP gRPC receiver\n      - \"4318:4318\" # OTLP http receiver\n      - \"55679:55679\" # zpages extension\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  prometheus\n  # # https://prometheus.io/docs/introduction/first_steps/\n  # # https://prometheus.io/docs/prometheus/3.1/installation/\n  # # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n  # #######################################################\n  prometheus:\n    image: prom/prometheus:latest\n    restart: unless-stopped\n    ports:\n      - \"9090:9090\"\n    volumes:\n      - ./../configs/prometheus.yaml:/etc/prometheus/prometheus.yml\n    # to passe one flag, such as \"--log.level=debug\" or \"--web.enable-remote-write-receiver\", we need to override the whole command, as we can't just pass one extra argument\n    command:\n      - \"--config.file=/etc/prometheus/prometheus.yml\"\n      - \"--storage.tsdb.path=/prometheus\"\n      - \"--web.console.libraries=/usr/share/prometheus/console_libraries\"\n      - \"--web.console.templates=/usr/share/prometheus/consoles\"\n      # need this for the OpenTelemetry collector to be able to put metrics into Prometheus\n      - \"--web.enable-remote-write-receiver\"\n    #   - \"--log.level=debug\"\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # # node-exporter\n  # # https://prometheus.io/docs/guides/node-exporter/\n  # # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n  # #######################################################\n  node-exporter:\n    image: prom/node-exporter:latest\n    container_name: node-exporter\n    restart: unless-stopped\n    volumes:\n      - /proc:/host/proc:ro\n      - /sys:/host/sys:ro\n      - /:/rootfs:ro\n    command:\n      - '--path.procfs=/host/proc'\n      - '--path.rootfs=/rootfs'\n      - '--path.sysfs=/host/sys'\n    ports:\n       - \"9101:9100\"\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # #  grafana\n  # # https://grafana.com/docs/grafana/latest/administration/provisioning/\n  # # https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/\n  # # https://grafana.com/docs/grafana/latest/setup-grafana/configure-docker/\n  # # https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml\n  # #######################################################\n  grafana:\n    image: grafana/grafana:latest\n    container_name: grafana\n    restart: unless-stopped\n    environment:\n      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource\n      - GF_SECURITY_ADMIN_USER=admin\n      - GF_SECURITY_ADMIN_PASSWORD=admin\n      - GF_FEATURE_TOGGLES_ENABLE=traceqlEditor\n      #      - GF_AUTH_ANONYMOUS_ENABLED=true\n      #      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin\n      #      - GF_AUTH_DISABLE_LOGIN_FORM=true\n    depends_on:\n      - prometheus\n    ports:\n      - \"3000:3000\"\n    volumes:\n      - ./../configs/grafana/provisioning:/etc/grafana/provisioning\n      - ./../configs/grafana/dashboards:/var/lib/grafana/dashboards\n      ## https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/\n      # - ./../configs/grafana/grafana.ini:/etc/grafana/grafana.ini\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # # tempo\n  # # https://github.com/grafana/tempo/blob/main/example/docker-compose/otel-collector/docker-compose.yaml\n  # # https://github.com/grafana/tempo/blob/main/example/docker-compose/shared\n  # # https://github.com/grafana/tempo/blob/main/example/docker-compose/local\n  # # https://github.com/grafana/tempo/tree/main/example/docker-compose\n  # #######################################################\n  tempo:\n    image: grafana/tempo:latest\n    container_name: tempo\n    restart: unless-stopped\n    command: [ \"-config.file=/etc/tempo.yaml\" ]\n    volumes:\n      - ./../configs/tempo.yaml:/etc/tempo.yaml\n    ports:\n      - \"3200\" # tempo\n      - \"24317:4317\" # otlp grpc\n      - \"24318:4318\" # otlp http\n    networks:\n      - infrastructure\n\n\n  # #######################################################\n  # # loki\n  # # https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/\n  # # https://github.com/grafana/loki/blob/main/production/docker-compose.yaml\n  # # https://github.com/grafana/loki/blob/main/examples/getting-started/docker-compose.yaml\n  # #######################################################\n  loki:\n    image: grafana/loki:latest\n    hostname: loki\n    container_name: loki\n    ports:\n      - \"3100:3100\"\n    command: -config.file=/etc/loki/local-config.yaml\n    volumes:\n      - ./../configs/loki-config.yaml:/etc/loki/local-config.yaml\n    networks:\n      - infrastructure\n\n\n  #  #######################################################\n  #  # elasticsearch\n  #  # https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docker.html#docker-compose-file\n  #  #######################################################\n  elasticsearch:\n     container_name: elasticsearch\n     restart: unless-stopped\n     image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0\n     environment:\n       - discovery.type=single-node\n       - cluster.name=docker-cluster\n       - node.name=docker-node\n       - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n       - xpack.security.enabled=false\n       - xpack.security.http.ssl.enabled=false\n       - xpack.security.transport.ssl.enabled=false\n       - network.host=0.0.0.0\n       - http.port=9200\n       - transport.host=localhost\n       - bootstrap.memory_lock=true\n       - cluster.routing.allocation.disk.threshold_enabled=false\n     ulimits:\n       memlock:\n         soft: -1\n         hard: -1\n     volumes:\n       - elastic-data:/usr/share/elasticsearch/data\n     ports:\n       - ${ELASTIC_HOST_PORT:-9200}:${ELASTIC_PORT:-9200}\n       - 9300:9300\n     networks:\n       - infrastructure\n\n\n  #  #######################################################\n  #  # kibana\n  #  # https://www.elastic.co/guide/en/kibana/current/docker.html\n  #  #######################################################\n  kibana:\n     image: docker.elastic.co/kibana/kibana:8.17.0\n     container_name: kibana\n     restart: unless-stopped\n     environment:\n       - ELASTICSEARCH_HOSTS=http://elasticsearch:9200\n     ports:\n       - ${KIBANA_HOST_PORT:-5601}:${KIBANA_PORT:-5601}\n     depends_on:\n       - elasticsearch\n     networks:\n       - infrastructure\n\n\n  #   #######################################################\n  #   # cadvisor\n  #   #######################################################\n  cadvisor:\n    image: gcr.io/cadvisor/cadvisor:latest\n    container_name: cadvisor\n    restart: unless-stopped\n    ports:\n      - \"8080:8080\"\n    volumes:\n      - /:/rootfs:ro\n      - /var/run:/var/run:ro\n      - /sys:/sys:ro\n      - /var/lib/docker/:/var/lib/docker:ro\n      - /dev/disk/:/dev/disk:ro\n    devices:\n      - /dev/kmsg\n    networks:\n      - infrastructure\n\n\nnetworks:\n  infrastructure:\n    name: infrastructure\n    driver: bridge\n\nvolumes:\n  elastic-data:\n  postgres-data:"
  },
  {
    "path": "deployments/docker-compose/docker-compose.yaml",
    "content": "name: booking-microservices\n\nservices:\n\n  #######################################################\n  #  rabbitmq\n  #######################################################\n  rabbitmq:\n    image: rabbitmq:management\n    container_name: rabbitmq\n    restart: unless-stopped\n    ports:\n      - \"5672:5672\"\n      - \"15672:15672\"\n      # volumes:\n      #   - rabbitmq:/var/lib/rabbitmq\n    networks:\n      - booking\n\n  #######################################################\n  #  postgres\n  #######################################################\n  postgres:\n    image: postgres:latest\n    container_name: postgres\n    restart: unless-stopped\n    ports:\n      - '5432:5432'\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=postgres\n    command:\n      - \"postgres\"\n      - \"-c\"\n      - \"wal_level=logical\"\n      - \"-c\"\n      - \"max_prepared_transactions=10\"\n    volumes:\n      - postgres-data:/var/lib/postgresql/data\n    networks:\n      - booking\n\n\n  #######################################################\n  #  EventStoreDB\n  #######################################################\n  eventstore:\n      container_name: eventstore\n      image: eventstore/eventstore:latest\n      restart: unless-stopped\n      environment:\n         - EVENTSTORE_CLUSTER_SIZE=1\n         - EVENTSTORE_RUN_PROJECTIONS=All\n         - EVENTSTORE_START_STANDARD_PROJECTIONS=True\n         - EVENTSTORE_HTTP_PORT=2113\n         - EVENTSTORE_INSECURE=True\n         - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=True\n      ports:\n          - \"2113:2113\"\n      networks:\n          - booking\n\n\n  #######################################################\n  #  Mongo\n  #######################################################\n  mongo:\n    image: mongo:latest\n    container_name: mongo\n    restart: unless-stopped\n    # environment:\n    #   - MONGO_INITDB_ROOT_USERNAME=root\n    #   - MONGO_INITDB_ROOT_PASSWORD=secret\n    ports:\n      - 27017:27017\n    networks:\n      - booking\n\n\n  #######################################################\n  #  Redis\n  #######################################################\n  redis:\n    image: redis\n    container_name: redis\n    restart: unless-stopped\n    ports:\n      - 6379:6379\n    networks:\n      - booking\n\n\n  #######################################################\n  #  jaeger\n  # https://www.jaegertracing.io/docs/1.64/deployment/\n  # https://www.jaegertracing.io/docs/1.6/deployment/\n  #######################################################\n  jaeger-all-in-one:\n    image: jaegertracing/all-in-one:latest\n    container_name: jaeger-all-in-one\n    restart: unless-stopped\n    ports:\n      - \"6831:6831/udp\" # UDP port for Jaeger agent\n      - \"16686:16686\" # endpoints and Jaeger UI\n      - \"14268:14268\" # HTTP port for accept trace spans directly from clients\n      - \"14317:4317\" # OTLP gRPC receiver for jaeger\n      - \"14318:4318\" # OTLP http receiver for jaeger\n      # - \"9411\" # Accepts Zipkin spans - /api/v2/spans\n    networks:\n      - booking\n\n\n  #######################################################\n  #  zipkin\n  # https://zipkin.io/pages/quickstart\n  #######################################################\n  zipkin-all-in-one:\n    image: openzipkin/zipkin:latest\n    container_name: zipkin-all-in-one\n    restart: unless-stopped\n    ports:\n      - \"9411:9411\"\n    networks:\n      - booking\n\n\n  #######################################################\n  #  otel-collector\n  # https://opentelemetry.io/docs/collector/installation/\n  # https://github.com/open-telemetry/opentelemetry-collector\n  # https://github.com/open-telemetry/opentelemetry-collector-contrib\n  # we can use none contrib docker `otel/opentelemetry-collector` version from `https://github.com/open-telemetry/opentelemetry-collector` repository but,\n  # if we need more components like `elasticsearch` we should use `otel/opentelemetry-collector-contrib` image of `https://github.com/open-telemetry/opentelemetry-collector-contrib` repository.\n  #######################################################\n  otel-collector:\n    image: otel/opentelemetry-collector-contrib:latest\n    container_name: otel-collector\n    restart: unless-stopped\n    command: [\"--config=/etc/otelcol-contrib/config.yaml\"]\n    volumes:\n      - ./../configs/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml\n    ports:\n      - \"11888:1888\" # pprof extension\n      - \"8888:8888\" # Prometheus metrics exposed by the Collector\n      - \"8889:8889\" # Prometheus exporter metrics\n      - \"13133:13133\" # health_check extension\n      - \"4317:4317\" # OTLP gRPC receiver\n      - \"4318:4318\" # OTLP http receiver\n      - \"55679:55679\" # zpages extension\n    networks:\n      - booking\n\n\n  #######################################################\n  #  prometheus\n  # https://prometheus.io/docs/introduction/first_steps/\n  # https://prometheus.io/docs/prometheus/3.1/installation/\n  # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n  #######################################################\n  prometheus:\n    image: prom/prometheus:latest\n    restart: unless-stopped\n    ports:\n      - \"9090:9090\"\n    volumes:\n      - ./../configs/prometheus.yaml:/etc/prometheus/prometheus.yml\n    # to passe one flag, such as \"--log.level=debug\" or \"--web.enable-remote-write-receiver\", we need to override the whole command, as we can't just pass one extra argument\n    command:\n      - \"--config.file=/etc/prometheus/prometheus.yml\"\n      - \"--storage.tsdb.path=/prometheus\"\n      - \"--web.console.libraries=/usr/share/prometheus/console_libraries\"\n      - \"--web.console.templates=/usr/share/prometheus/consoles\"\n      # need this for the OpenTelemetry collector to be able to put metrics into Prometheus\n      - \"--web.enable-remote-write-receiver\"\n    #   - \"--log.level=debug\"\n    networks:\n      - booking\n\n\n  #######################################################\n  # node-exporter\n  # https://prometheus.io/docs/guides/node-exporter/\n  # https://grafana.com/docs/grafana-cloud/send-data/metrics/metrics-prometheus/prometheus-config-examples/docker-compose-linux/\n  #######################################################\n  node-exporter:\n    image: prom/node-exporter:latest\n    container_name: node-exporter\n    restart: unless-stopped\n    volumes:\n      - /proc:/host/proc:ro\n      - /sys:/host/sys:ro\n      - /:/rootfs:ro\n    command:\n      - '--path.procfs=/host/proc'\n      - '--path.rootfs=/rootfs'\n      - '--path.sysfs=/host/sys'\n    ports:\n       - \"9101:9100\"\n    networks:\n      - booking\n\n\n  #######################################################\n  #  grafana\n  # https://grafana.com/docs/grafana/latest/administration/provisioning/\n  # https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/\n  # https://grafana.com/docs/grafana/latest/setup-grafana/configure-docker/\n  # https://github.com/grafana/intro-to-mltp/blob/main/grafana/provisioning/datasources/datasources.yaml\n  #######################################################\n  grafana:\n    image: grafana/grafana:latest\n    container_name: grafana\n    restart: unless-stopped\n    environment:\n      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource\n      - GF_SECURITY_ADMIN_USER=admin\n      - GF_SECURITY_ADMIN_PASSWORD=admin\n      - GF_FEATURE_TOGGLES_ENABLE=traceqlEditor\n      #      - GF_AUTH_ANONYMOUS_ENABLED=true\n      #      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin\n      #      - GF_AUTH_DISABLE_LOGIN_FORM=true\n    depends_on:\n      - prometheus\n    ports:\n      - \"3000:3000\"\n    volumes:\n      - ./../configs/grafana/provisioning:/etc/grafana/provisioning\n      - ./../configs/grafana/dashboards:/var/lib/grafana/dashboards\n      ## https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/\n      # - ./../configs/grafana/grafana.ini:/etc/grafana/grafana.ini\n    networks:\n      - booking\n\n\n  #######################################################\n  # tempo\n  # https://github.com/grafana/tempo/blob/main/example/docker-compose/otel-collector/docker-compose.yaml\n  # https://github.com/grafana/tempo/blob/main/example/docker-compose/shared\n  # https://github.com/grafana/tempo/blob/main/example/docker-compose/local\n  # https://github.com/grafana/tempo/tree/main/example/docker-compose\n  #######################################################\n  tempo:\n    image: grafana/tempo:latest\n    container_name: tempo\n    restart: unless-stopped\n    command: [ \"-config.file=/etc/tempo.yaml\" ]\n    volumes:\n      - ./../configs/tempo.yaml:/etc/tempo.yaml\n    ports:\n      - \"3200\" # tempo\n      - \"24317:4317\" # otlp grpc\n      - \"24318:4318\" # otlp http\n    networks:\n      - booking\n\n\n  #######################################################\n  # loki\n  # https://grafana.com/docs/opentelemetry/collector/send-logs-to-loki/\n  # https://github.com/grafana/loki/blob/main/production/docker-compose.yaml\n  # https://github.com/grafana/loki/blob/main/examples/getting-started/docker-compose.yaml\n  #######################################################\n  loki:\n    image: grafana/loki:latest\n    hostname: loki\n    container_name: loki\n    ports:\n      - \"3100:3100\"\n    command: -config.file=/etc/loki/local-config.yaml\n    volumes:\n      - ./../configs/loki-config.yaml:/etc/loki/local-config.yaml\n    networks:\n      - booking\n\n\n   #######################################################\n   # elasticsearch\n   # https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docker.html#docker-compose-file\n   #######################################################\n  elasticsearch:\n     container_name: elasticsearch\n     restart: unless-stopped\n     image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0\n     environment:\n       - discovery.type=single-node\n       - cluster.name=docker-cluster\n       - node.name=docker-node\n       - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n       - xpack.security.enabled=false\n       - xpack.security.http.ssl.enabled=false\n       - xpack.security.transport.ssl.enabled=false\n       - network.host=0.0.0.0\n       - http.port=9200\n       - transport.host=localhost\n       - bootstrap.memory_lock=true\n       - cluster.routing.allocation.disk.threshold_enabled=false\n     ulimits:\n       memlock:\n         soft: -1\n         hard: -1\n     volumes:\n       - elastic-data:/usr/share/elasticsearch/data\n     ports:\n       - ${ELASTIC_HOST_PORT:-9200}:${ELASTIC_PORT:-9200}\n       - 9300:9300\n     networks:\n       - booking\n\n\n   #######################################################\n   # kibana\n   # https://www.elastic.co/guide/en/kibana/current/docker.html\n   #######################################################\n  kibana:\n     image: docker.elastic.co/kibana/kibana:8.17.0\n     container_name: kibana\n     restart: unless-stopped\n     environment:\n       - ELASTICSEARCH_HOSTS=http://elasticsearch:9200\n     ports:\n       - ${KIBANA_HOST_PORT:-5601}:${KIBANA_PORT:-5601}\n     depends_on:\n       - elasticsearch\n     networks:\n       - booking\n\n\n    #######################################################\n    # cadvisor\n    #######################################################\n  cadvisor:\n    image: gcr.io/cadvisor/cadvisor:latest\n    container_name: cadvisor\n    restart: unless-stopped\n    ports:\n      - \"8080:8080\"\n    volumes:\n      - /:/rootfs:ro\n      - /var/run:/var/run:ro\n      - /sys:/sys:ro\n      - /var/lib/docker/:/var/lib/docker:ro\n      - /dev/disk/:/dev/disk:ro\n    devices:\n      - /dev/kmsg\n    networks:\n      - booking\n\n\n  ######################################################\n  #  Api-Gateway\n  ######################################################\n  api-gateway:\n    image: api-gateway\n    build:\n      args:\n        Version: \"1\"\n      context: ../../\n      dockerfile: src/ApiGateway/Dockerfile\n    container_name: api-gateway\n    ports:\n      - \"5001:80\"\n      - \"5000:443\"\n    volumes:\n      - ~/.aspnet/https:/https:ro\n    environment:\n      - ASPNETCORE_ENVIRONMENT=docker\n      - ASPNETCORE_URLS=https://+;http://+\n      - ASPNETCORE_HTTPS_PORT=5000\n      - ASPNETCORE_HTTP_PORT=5001\n      - ASPNETCORE_Kestrel__Certificates__Default__Password=password\n      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\n    networks:\n      - booking\n\n\n    #######################################################\n    #  Flight\n    #######################################################\n  flight:\n    image: flight\n    build:\n      args:\n        Version: \"1\"\n      context: ../../\n      dockerfile: src/Services/Flight/Dockerfile\n    container_name: flight\n    ports:\n      - 5004:80\n      - 5003:443\n    volumes:\n      - ~/.aspnet/https:/https:ro\n    environment:\n      - ASPNETCORE_ENVIRONMENT=docker\n      - ASPNETCORE_URLS=https://+;http://+\n      - ASPNETCORE_HTTPS_PORT=5003\n      - ASPNETCORE_HTTP_PORT=5004\n      - ASPNETCORE_Kestrel__Certificates__Default__Password=password\n      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\n    networks:\n      - booking\n\n    #######################################################\n    #  Identity\n    #######################################################\n  identity:\n    image: identity\n    build:\n      args:\n        Version: \"1\"\n      context: ../../\n      dockerfile: src/Services/Identity/Dockerfile\n    container_name: identity\n    ports:\n      - 6005:80\n      - 5005:443\n    volumes:\n      - ~/.aspnet/https:/https:ro\n    environment:\n      - ASPNETCORE_ENVIRONMENT=docker\n      - ASPNETCORE_URLS=https://+;http://+\n      - ASPNETCORE_HTTPS_PORT=5005\n      - ASPNETCORE_HTTP_PORT=6005\n      - ASPNETCORE_Kestrel__Certificates__Default__Password=password\n      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\n    networks:\n      - booking\n\n\n    #######################################################\n    #  Passenger\n    #######################################################\n  passenger:\n    image: passenger\n    build:\n      args:\n        Version: \"1\"\n      context: ../../\n      dockerfile: src/Services/Passenger/Dockerfile\n    container_name: passenger\n    ports:\n      - 6012:80\n      - 5012:443\n    volumes:\n      - ~/.aspnet/https:/https:ro\n    environment:\n      - ASPNETCORE_ENVIRONMENT=docker\n      - ASPNETCORE_URLS=https://+;http://+\n      - ASPNETCORE_HTTPS_PORT=5012\n      - ASPNETCORE_HTTP_PORT=6012\n      - ASPNETCORE_Kestrel__Certificates__Default__Password=password\n      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\n    networks:\n      - booking\n\n\n    #######################################################\n    #  Booking\n    #######################################################\n  booking:\n    image: booking\n    build:\n      args:\n        Version: \"1\"\n      context: ../../\n      dockerfile: src/Services/Booking/Dockerfile\n    container_name: booking\n    ports:\n      - 6010:80\n      - 5010:443\n    volumes:\n      - ~/.aspnet/https:/https:ro\n    environment:\n      - ASPNETCORE_ENVIRONMENT=docker\n      - ASPNETCORE_URLS=https://+;http://+\n      - ASPNETCORE_HTTPS_PORT=5010\n      - ASPNETCORE_HTTP_PORT=6010\n      - ASPNETCORE_Kestrel__Certificates__Default__Password=password\n      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\n    networks:\n      - booking\n\n\nnetworks:\n  booking:\n    name: booking\n    driver: bridge\n\nvolumes:\n  elastic-data:\n  postgres-data:\n\n\n"
  },
  {
    "path": "deployments/kubernetes/booking-cert-manager.yml",
    "content": "apiVersion: cert-manager.io/v1\nkind: ClusterIssuer\nmetadata:\n  name: letsencrypt-staging\nspec:\n  acme:\n    # Staging API\n    server: https://acme-staging-v02.api.letsencrypt.org/directory\n    # server: https://acme-v02.api.letsencrypt.org/directory\n    email: test@email.com\n    privateKeySecretRef:\n      name: letsencrypt-staging\n    solvers:\n    - http01:\n       ingress:\n         class: nginx\n"
  },
  {
    "path": "deployments/kubernetes/booking-microservices.yml",
    "content": "## ref: https://kompose.io\n#######################################################\n#  Network\n#######################################################\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  creationTimestamp: null\n  name: booking\nspec:\n  ingress:\n    - from:\n        - podSelector:\n            matchLabels:\n              io.kompose.network/booking: \"true\"\n  podSelector:\n    matchLabels:\n      io.kompose.network/booking: \"true\"\n\n---\n#######################################################\n#  ElasticSearch\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: elasticsearch\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: elasticsearch\n  template:\n    metadata:\n      labels:\n        app: elasticsearch\n    spec:\n      containers:\n      - name: elasticsearch\n        image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0\n        env:\n        - name: discovery.type\n          value: \"single-node\"\n        - name: cluster.name\n          value: \"docker-cluster\"\n        - name: node.name\n          value: \"docker-node\"\n        - name: ES_JAVA_OPTS\n          value: \"-Xms512m -Xmx512m\"\n        - name: xpack.security.enabled\n          value: \"false\"\n        - name: xpack.security.http.ssl.enabled\n          value: \"false\"\n        - name: xpack.security.transport.ssl.enabled\n          value: \"false\"\n        - name: network.host\n          value: \"0.0.0.0\"\n        - name: http.port\n          value: \"9200\"\n        - name: transport.host\n          value: \"localhost\"\n        - name: bootstrap.memory_lock\n          value: \"true\"\n        - name: cluster.routing.allocation.disk.threshold_enabled\n          value: \"false\"\n        ports:\n        - containerPort: 9200\n        - containerPort: 9300\n        volumeMounts:\n        - mountPath: /usr/share/elasticsearch/data\n          name: elastic-data\n      volumes:\n      - name: elastic-data\n        persistentVolumeClaim:\n          claimName: elasticsearch-pvc\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: elasticsearch-pvc\nspec:\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 10Gi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: elasticsearch\nspec:\n  selector:\n    app: elasticsearch\n  ports:\n  - port: 9200\n    targetPort: 9200\n  - port: 9300\n    targetPort: 9300\n  type: ClusterIP\n---\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: elasticsearch-pv\n  labels:\n    type: local\nspec:\n  storageClassName: manual\n  capacity:\n    storage: 10Gi\n  accessModes:\n    - ReadWriteOnce\n  hostPath:\n    path: \"/mnt/data\"\n---\n#######################################################\n#  Kibana\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: kibana\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: kibana\n  template:\n    metadata:\n      labels:\n        app: kibana\n    spec:\n      containers:\n      - name: kibana\n        image: docker.elastic.co/kibana/kibana:8.17.0\n        env:\n        - name: ELASTICSEARCH_HOSTS\n          value: \"http://elasticsearch:9200\"\n        ports:\n        - containerPort: 5601\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: kibana\nspec:\n  selector:\n    app: kibana\n  ports:\n  - port: 5601\n    targetPort: 5601\n  type: ClusterIP\n---\n#######################################################\n#  Tempo\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: tempo\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: tempo\n  template:\n    metadata:\n      labels:\n        app: tempo\n    spec:\n      containers:\n      - name: tempo\n        image: grafana/tempo:latest\n        args:\n        - \"-config.file=/etc/tempo.yaml\"\n        ports:\n        - containerPort: 3200\n        - containerPort: 4317\n        - containerPort: 4318\n        volumeMounts:\n        - mountPath: /etc/tempo.yaml\n          name: tempo-config\n          subPath: tempo.yaml\n      volumes:\n      - name: tempo-config\n        configMap:\n          name: tempo-config\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: tempo-config\ndata:\n  tempo.yaml: |\n    # Your Tempo configuration here\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: tempo\nspec:\n  selector:\n    app: tempo\n  ports:\n  - port: 3200\n    targetPort: 3200\n  - port: 4317\n    targetPort: 4317\n  - port: 4318\n    targetPort: 4318\n  type: ClusterIP\n---\n#######################################################\n#  Looki\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: loki\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: loki\n  template:\n    metadata:\n      labels:\n        app: loki\n    spec:\n      containers:\n      - name: loki\n        image: grafana/loki:latest\n        args:\n        - \"-config.file=/etc/loki/local-config.yaml\"\n        ports:\n        - containerPort: 3100\n        volumeMounts:\n        - mountPath: /etc/loki/local-config.yaml\n          name: loki-config\n          subPath: local-config.yaml\n      volumes:\n      - name: loki-config\n        configMap:\n          name: loki-config\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: loki-config\ndata:\n  local-config.yaml: |\n    # Your Loki configuration here\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: loki\nspec:\n  selector:\n    app: loki\n  ports:\n  - port: 3100\n    targetPort: 3100\n  type: ClusterIP\n---\n#######################################################\n#  Event Store\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: eventstore\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: eventstore\n  template:\n    metadata:\n      labels:\n        app: eventstore\n    spec:\n      containers:\n      - name: eventstore\n        image: eventstore/eventstore:latest\n        env:\n        - name: EVENTSTORE_CLUSTER_SIZE\n          value: \"1\"\n        - name: EVENTSTORE_RUN_PROJECTIONS\n          value: \"All\"\n        - name: EVENTSTORE_START_STANDARD_PROJECTIONS\n          value: \"True\"\n        - name: EVENTSTORE_HTTP_PORT\n          value: \"2113\"\n        - name: EVENTSTORE_INSECURE\n          value: \"True\"\n        - name: EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP\n          value: \"True\"\n        ports:\n        - containerPort: 2113\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: eventstore\nspec:\n  selector:\n    app: eventstore\n  ports:\n  - port: 2113\n    targetPort: 2113\n  type: ClusterIP\n---\n#######################################################\n#  Jaeger\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: jaeger\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: jaeger\n  template:\n    metadata:\n      labels:\n        app: jaeger\n    spec:\n      containers:\n      - name: jaeger\n        image: jaegertracing/all-in-one:latest\n        ports:\n        - containerPort: 6831\n          protocol: UDP\n        - containerPort: 16686\n        - containerPort: 14268\n        - containerPort: 4317\n        - containerPort: 4318\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: jaeger\nspec:\n  selector:\n    app: jaeger\n  ports:\n  - port: 6831\n    targetPort: 6831\n    protocol: UDP\n  - port: 16686\n    targetPort: 16686\n  - port: 14268\n    targetPort: 14268\n  - port: 4317\n    targetPort: 4317\n  - port: 4318\n    targetPort: 4318\n  type: ClusterIP\n---\n#######################################################\n#  Zipkin\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: zipkin\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: zipkin\n  template:\n    metadata:\n      labels:\n        app: zipkin\n    spec:\n      containers:\n      - name: zipkin\n        image: openzipkin/zipkin:latest\n        ports:\n        - containerPort: 9411\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: zipkin\nspec:\n  selector:\n    app: zipkin\n  ports:\n  - port: 9411\n    targetPort: 9411\n  type: ClusterIP\n\n---\n#######################################################\n#  OpenTelemetry Collector\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: otel-collector\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: otel-collector\n  template:\n    metadata:\n      labels:\n        app: otel-collector\n    spec:\n      containers:\n      - name: otel-collector\n        image: otel/opentelemetry-collector-contrib:latest\n        args: [\"--config=/etc/otelcol-contrib/config.yaml\"]\n        ports:\n        - containerPort: 11888\n        - containerPort: 8888\n        - containerPort: 8889\n        - containerPort: 13133\n        - containerPort: 4317\n        - containerPort: 4318\n        - containerPort: 55679\n        volumeMounts:\n        - mountPath: /etc/otelcol-contrib/config.yaml\n          name: otel-config\n          subPath: config.yaml\n      volumes:\n      - name: otel-config\n        configMap:\n          name: otel-collector-config\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: otel-collector-config\ndata:\n  config.yaml: |\n    # Your OpenTelemetry Collector configuration here\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: otel-collector\nspec:\n  selector:\n    app: otel-collector\n  ports:\n  - port: 11888\n    targetPort: 11888\n  - port: 8888\n    targetPort: 8888\n  - port: 8889\n    targetPort: 8889\n  - port: 13133\n    targetPort: 13133\n  - port: 4317\n    targetPort: 4317\n  - port: 4318\n    targetPort: 4318\n  - port: 55679\n    targetPort: 55679\n  type: ClusterIP\n---\n#######################################################\n#  Prometheus\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: prometheus\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: prometheus\n  template:\n    metadata:\n      labels:\n        app: prometheus\n    spec:\n      containers:\n      - name: prometheus\n        image: prom/prometheus:latest\n        args:\n        - \"--config.file=/etc/prometheus/prometheus.yml\"\n        - \"--storage.tsdb.path=/prometheus\"\n        - \"--web.console.libraries=/usr/share/prometheus/console_libraries\"\n        - \"--web.console.templates=/usr/share/prometheus/consoles\"\n        - \"--web.enable-remote-write-receiver\"\n        ports:\n        - containerPort: 9090\n        volumeMounts:\n        - mountPath: /etc/prometheus/prometheus.yml\n          name: prometheus-config\n          subPath: prometheus.yml\n      volumes:\n      - name: prometheus-config\n        configMap:\n          name: prometheus-config\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: prometheus-config\ndata:\n  prometheus.yml: |\n    # Your Prometheus configuration here\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: prometheus\nspec:\n  selector:\n    app: prometheus\n  ports:\n  - port: 9090\n    targetPort: 9090\n  type: ClusterIP\n---\n#######################################################\n#  Grafana\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: grafana\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: grafana\n  template:\n    metadata:\n      labels:\n        app: grafana\n    spec:\n      containers:\n      - name: grafana\n        image: grafana/grafana:latest\n        env:\n        - name: GF_INSTALL_PLUGINS\n          value: \"grafana-clock-panel,grafana-simple-json-datasource\"\n        - name: GF_SECURITY_ADMIN_USER\n          value: \"admin\"\n        - name: GF_SECURITY_ADMIN_PASSWORD\n          value: \"admin\"\n        - name: GF_FEATURE_TOGGLES_ENABLE\n          value: \"traceqlEditor\"\n        ports:\n        - containerPort: 3000\n        volumeMounts:\n        - mountPath: /etc/grafana/provisioning\n          name: grafana-provisioning\n        - mountPath: /var/lib/grafana/dashboards\n          name: grafana-dashboards\n      volumes:\n      - name: grafana-provisioning\n        configMap:\n          name: grafana-provisioning\n      - name: grafana-dashboards\n        configMap:\n          name: grafana-dashboards\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: grafana-provisioning\ndata:\n  # Your Grafana provisioning configuration here\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: grafana-dashboards\ndata:\n  # Your Grafana dashboards configuration here\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: grafana\nspec:\n  selector:\n    app: grafana\n  ports:\n  - port: 3000\n    targetPort: 3000\n  type: ClusterIP\n---\n#######################################################\n#  Node Exporter\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: node-exporter\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: node-exporter\n  template:\n    metadata:\n      labels:\n        app: node-exporter\n    spec:\n      containers:\n      - name: node-exporter\n        image: prom/node-exporter:latest\n        args:\n        - \"--path.procfs=/host/proc\"\n        - \"--path.rootfs=/rootfs\"\n        - \"--path.sysfs=/host/sys\"\n        ports:\n        - containerPort: 9100\n        volumeMounts:\n        - mountPath: /host/proc\n          name: proc\n          readOnly: true\n        - mountPath: /host/sys\n          name: sys\n          readOnly: true\n        - mountPath: /rootfs\n          name: rootfs\n          readOnly: true\n      volumes:\n      - name: proc\n        hostPath:\n          path: /proc\n      - name: sys\n        hostPath:\n          path: /sys\n      - name: rootfs\n        hostPath:\n          path: /\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: node-exporter\nspec:\n  selector:\n    app: node-exporter\n  ports:\n  - port: 9100\n    targetPort: 9100\n  type: ClusterIP\n---\n#######################################################\n#  Cadvisor\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: cadvisor\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: cadvisor\n  template:\n    metadata:\n      labels:\n        app: cadvisor\n    spec:\n      containers:\n      - name: cadvisor\n        image: gcr.io/cadvisor/cadvisor:latest\n        ports:\n        - containerPort: 8080\n        volumeMounts:\n        - mountPath: /rootfs\n          name: rootfs\n          readOnly: true\n        - mountPath: /var/run\n          name: var-run\n          readOnly: true\n        - mountPath: /sys\n          name: sys\n          readOnly: true\n        - mountPath: /var/lib/docker\n          name: var-lib-docker\n          readOnly: true\n        - mountPath: /dev/disk\n          name: dev-disk\n          readOnly: true\n      volumes:\n      - name: rootfs\n        hostPath:\n          path: /\n      - name: var-run\n        hostPath:\n          path: /var/run\n      - name: sys\n        hostPath:\n          path: /sys\n      - name: var-lib-docker\n        hostPath:\n          path: /var/lib/docker\n      - name: dev-disk\n        hostPath:\n          path: /dev/disk\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: cadvisor\nspec:\n  selector:\n    app: cadvisor\n  ports:\n  - port: 8080\n    targetPort: 8080\n  type: ClusterIP\n---\n#######################################################\n#  Mongo\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: mongo\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: mongo\n  template:\n    metadata:\n      labels:\n        app: mongo\n    spec:\n      containers:\n      - name: mongo\n        image: mongo:latest\n        ports:\n        - containerPort: 27017\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: mongo\nspec:\n  selector:\n    app: mongo\n  ports:\n  - port: 27017\n    targetPort: 27017\n  type: ClusterIP\n---\n#######################################################\n#  Postgres\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: postgres\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: postgres\n  template:\n    metadata:\n      labels:\n        app: postgres\n    spec:\n      containers:\n      - name: postgres\n        image: postgres:latest\n        env:\n        - name: POSTGRES_USER\n          value: postgres\n        - name: POSTGRES_PASSWORD\n          value: postgres\n        ports:\n        - containerPort: 5432\n        volumeMounts:\n        - mountPath: /var/lib/postgresql/data\n          name: postgres-data\n      volumes:\n      - name: postgres-data\n        persistentVolumeClaim:\n          claimName: postgres-pvc\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: postgres-pvc\nspec:\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 10Gi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: postgres\nspec:\n  selector:\n    app: postgres\n  ports:\n  - port: 5432\n    targetPort: 5432\n  type: ClusterIP\n---\n#######################################################\n#  Rabbitmq\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: rabbitmq\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: rabbitmq\n  template:\n    metadata:\n      labels:\n        app: rabbitmq\n    spec:\n      containers:\n      - name: rabbitmq\n        image: rabbitmq:management\n        ports:\n        - containerPort: 5672\n        - containerPort: 15672\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: rabbitmq\nspec:\n  selector:\n    app: rabbitmq\n  ports:\n  - port: 5672\n    targetPort: 5672\n  - port: 15672\n    targetPort: 15672\n  type: ClusterIP\n---\n#######################################################\n#  Redis\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: redis\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: redis\n  template:\n    metadata:\n      labels:\n        app: redis\n    spec:\n      containers:\n      - name: redis\n        image: redis\n        ports:\n        - containerPort: 6379\n        resources:\n          requests:\n            memory: \"512Mi\"\n            cpu: \"500m\"\n          limits:\n            memory: \"1Gi\"\n            cpu: \"1\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: redis\nspec:\n  selector:\n    app: redis\n  ports:\n  - port: 6379\n    targetPort: 6379\n  type: ClusterIP\n---\n#######################################################\n#   ConfigMap AppSettings\n#######################################################\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: appsettings\ndata:\n  appsettings.json: |-\n    {\n      .Files.Get \"settings/appsettings.docker.json\"\n    }\n#ref: https://www.mrjamiebowman.com/software-development/dotnet/kubernetes-configmaps-with-net-core/\n---\n#######################################################\n#   Flight\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: flight-deployment\n  labels:\n    app: flight\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: flight\n  template:\n    metadata:\n      labels:\n        app: flight\n    spec:\n      containers:\n        - image: meysamh66/booking-microservices-flight:v1.6.7\n          name: flight\n          ports:\n            - containerPort: 80\n          env:\n          - name: ASPNETCORE_ENVIRONMENT\n            value: docker\n          - name: ASPNETCORE_URLS\n            value: http://+\n          volumeMounts:\n          - name: appsettings-volume\n            mountPath: /app/Settings\n      volumes:\n      - name: appsettings-volume\n        configMap:\n          name: appsettings\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: flight\nspec:\n  selector:\n    app: flight\n  ports:\n  - name: http\n    protocol: TCP\n    port: 80\n    targetPort: 80\n  type: ClusterIP\n---\n#######################################################\n#   Identity\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: identity-deployment\n  labels:\n    app: identity\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: identity\n  template:\n    metadata:\n      labels:\n        app: identity\n    spec:\n      containers:\n        - image: meysamh66/booking-microservices-identity:v1.6.7\n          name: identity\n          ports:\n            - containerPort: 80\n          env:\n          - name: ASPNETCORE_ENVIRONMENT\n            value: docker\n          - name: ASPNETCORE_URLS\n            value: http://+\n          volumeMounts:\n          - name: appsettings-volume\n            mountPath: /app/Settings\n      volumes:\n      - name: appsettings-volume\n        configMap:\n          name: appsettings\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: identity\nspec:\n  selector:\n    app: identity\n  ports:\n  - name: http\n    protocol: TCP\n    port: 80\n    targetPort: 80\n  type: ClusterIP\n---\n#######################################################\n#   Booking\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: booking-deployment\n  labels:\n    app: booking\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: booking\n  template:\n    metadata:\n      labels:\n        app: booking\n    spec:\n      containers:\n        - image: meysamh66/booking-microservices-booking:v1.6.7\n          name: booking\n          ports:\n            - containerPort: 80\n          env:\n          - name: ASPNETCORE_ENVIRONMENT\n            value: docker\n          - name: ASPNETCORE_URLS\n            value: http://+\n          volumeMounts:\n          - name: appsettings-volume\n            mountPath: /app/Settings\n      volumes:\n      - name: appsettings-volume\n        configMap:\n          name: appsettings\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: booking\nspec:\n  selector:\n    app: booking\n  ports:\n  - name: http\n    protocol: TCP\n    port: 80\n    targetPort: 80\n  type: ClusterIP\n---\n#######################################################\n#   Passenger\n#######################################################\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: passenger-deployment\n  labels:\n    app: passenger\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: passenger\n  template:\n    metadata:\n      labels:\n        app: passenger\n    spec:\n      containers:\n        - image: meysamh66/booking-microservices-passenger:v1.6.7\n          name: passenger\n          ports:\n            - containerPort: 80\n          env:\n          - name: ASPNETCORE_ENVIRONMENT\n            value: docker\n          - name: ASPNETCORE_URLS\n            value: http://+\n          volumeMounts:\n          - name: appsettings-volume\n            mountPath: /app/Settings\n      volumes:\n      - name: appsettings-volume\n        configMap:\n          name: appsettings\n---\n#######################################################\n#   Ingress Controller\n#######################################################\napiVersion: v1\nkind: Service\nmetadata:\n  name: passenger\nspec:\n  selector:\n    app: passenger\n  ports:\n  - name: http\n    protocol: TCP\n    port: 80\n    targetPort: 80\n  type: ClusterIP\n---\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: booking-microservies\n  annotations:\n    nginx.ingress.kubernetes.io/rewrite-target: /$1\n    cert-manager.io/cluster-issuer: \"letsencrypt-staging\"\n    nginx.ingress.kubernetes.io/use-regex: \"true\"\n    nginx.ingress.kubernetes.io/proxy-buffer-size: \"128k\"\n    nginx.ingress.kubernetes.io/proxy-buffers: \"4 256k\"\n    nginx.ingress.kubernetes.io/proxy-busy-buffers-size: \"256k\"\n    nginx.ingress.kubernetes.io/client-header-buffer-size: \"64k\"\n    nginx.ingress.kubernetes.io/http2-max-field-size: \"16k\"\n    nginx.ingress.kubernetes.io/http2-max-header-size: \"128k\"\n    nginx.ingress.kubernetes.io/large-client-header-buffers: \"8 64k\"\nspec:\n  ingressClassName: nginx\n  tls:\n  - hosts:\n      - booking-microservices.com\n    secretName: letsencrypt-staging\n  rules:\n    - host: booking-microservices.com\n      http:\n        paths:\n          - path: /identity\n            pathType: Prefix\n            backend:\n              service:\n                name: flight\n                port:\n                  number: 80\n          - path: /identity/(.*)\n            pathType: Prefix\n            backend:\n              service:\n                name: identity\n                port:\n                  number: 80\n\n\n          - path: /flight\n            pathType: Prefix\n            backend:\n              service:\n                name: flight\n                port:\n                  number: 80\n          - path: /flight/(.*)\n            pathType: Prefix\n            backend:\n              service:\n                name: flight\n                port:\n                  number: 80\n\n\n          - path: /passenger\n            pathType: Prefix\n            backend:\n              service:\n                name: passenger\n                port:\n                  number: 80\n          - path: /passenger/(.*)\n            pathType: Prefix\n            backend:\n              service:\n                name: passenger\n                port:\n                  number: 80\n\n\n          - path: /booking\n            pathType: Prefix\n            backend:\n              service:\n                name: booking\n                port:\n                  number: 80\n          - path: /booking/(.*)\n            pathType: Prefix\n            backend:\n              service:\n                name: booking\n                port:\n                  number: 80\n"
  },
  {
    "path": "global.json",
    "content": "{\n    \"sdk\": {\n      \"version\": \"10.0.103\",\n      \"rollForward\": \"latestFeature\"\n    }\n  }\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"booking-microservices\",\n  \"version\": \"1.0.0\",\n  \"description\": \"booking-microservices\",\n  \"author\": \"Meysam Hadeli\",\n  \"license\": \"MIT\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"prepare\": \"husky && dotnet tool restore\",\n    \"format\": \"dotnet tool run dotnet-csharpier booking-microservices.sln\",\n    \"ci-format\": \"dotnet tool run dotnet-csharpier booking-microservices.sln --check\",\n    \"upgrade-packages\": \"dotnet outdated --upgrade\"\n  },\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"^19.5.0\",\n    \"@commitlint/config-conventional\": \"^19.5.0\",\n    \"husky\": \"^9.1.6\"\n  }\n}\n"
  },
  {
    "path": "scripts/setup_kubectl_gitpod.sh",
    "content": "#!/bin/bash\n\n# Download kubectl binary\ncurl -LO \"https://storage.googleapis.com/kubernetes-release/release/$(curl -L -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl\"\n\n# Make the kubectl binary executable\nchmod +x kubectl\n\n# Move the binary in to PATH\nsudo mv kubectl /usr/local/bin/"
  },
  {
    "path": "src/ApiGateway/Dockerfile",
    "content": "# ---------- Build Stage ----------\nFROM mcr.microsoft.com/dotnet/sdk:10.0 AS build\nWORKDIR /src\n\n# Copy solution-level files\nCOPY .editorconfig .\nCOPY global.json .\nCOPY Directory.Build.props .\n\n# Copy project files first (better Docker caching)\nCOPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/\nCOPY src/ApiGateway/src/ApiGateway.csproj src/ApiGateway/src/\nCOPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/\n\n# Restore dependencies\nRUN dotnet restore src/ApiGateway/src/ApiGateway.csproj\n\n# Copy the rest of the source code\nCOPY src ./src\n\n# Publish (build included)\nRUN dotnet publish src/ApiGateway/src/ApiGateway.csproj \\\n    -c Release \\\n    -o /app/publish \\\n    --no-restore\n\n# ---------- Runtime Stage ----------\nFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime\nWORKDIR /app\n\nCOPY --from=build /app/publish .\n\nENV ASPNETCORE_URLS=http://+:80\nENV ASPNETCORE_ENVIRONMENT=docker\n\nEXPOSE 80\n\nENTRYPOINT [\"dotnet\", \"ApiGateway.dll\"]"
  },
  {
    "path": "src/ApiGateway/src/ApiGateway.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/ApiGateway/src/Program.cs",
    "content": "using BuildingBlocks.Web;\nusing Figgle;\nusing Figgle.Fonts;\n\nvar builder = WebApplication.CreateBuilder(args);\nvar env = builder.Environment;\nvar appOptions = builder.Services.GetOptions<AppOptions>(\"AppOptions\");\nConsole.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));\n\n\nbuilder.Services.AddControllers();\nbuilder.Services.AddHttpContextAccessor();\n\nbuilder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection(\"Yarp\"));\n\nvar app = builder.Build();\n\napp.UseCorrelationId();\napp.UseRouting();\napp.UseHttpsRedirection();\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.UseEndpoints(endpoints =>\n{\n    endpoints.MapControllers();\n    endpoints.MapReverseProxy();\n});\n\napp.MapGet(\"/\", x => x.Response.WriteAsync(appOptions.Name));\n\napp.Run();"
  },
  {
    "path": "src/ApiGateway/src/Properties/launchSettings.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"ApiGateway\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:5000;http://localhost:5001\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/ApiGateway/src/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/ApiGateway/src/appsettings.docker.json",
    "content": "{\n  \"LogOptions\": {\n    \"Level\": \"Information\",\n    \"LogTemplate\": \"{Timestamp:HH:mm:ss} [{Level:u4}] {Message:lj}{NewLine}{Exception}\",\n    \"ElasticUri\": \"elasticsearch:9200\"\n  },\n  \"Yarp\": {\n    \"clusters\": {\n      \"flight\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://flight:80\"\n          }\n        }\n      },\n      \"identity\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://identity:80\"\n          }\n        }\n      },\n      \"passenger\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://passenger:80\"\n          }\n        }\n      },\n      \"booking\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://booking:80\"\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/ApiGateway/src/appsettings.json",
    "content": "{\n  \"AppOptions\": {\n    \"Name\": \"ApiGateway\"\n  },\n  \"LogOptions\": {\n    \"Level\": \"Information\",\n    \"LogTemplate\": \"{Timestamp:HH:mm:ss} [{Level:u4}] {Message:lj}{NewLine}{Exception}\",\n    \"ElasticUri\": \"http://localhost:9200\"\n  },\n  \"HealthOptions\": {\n    \"Enabled\": false\n  },\n  \"Yarp\": {\n    \"routes\": {\n      \"identity\": {\n        \"clusterId\": \"identity\",\n        \"match\": {\n          \"path\": \"identity/{**catch-all}\"\n        },\n        \"Transforms\":  [\n        {\n          \"PathRemovePrefix\": \"identity\"\n        }\n      ]\n      },\n      \"flight\": {\n        \"clusterId\": \"flight\",\n        \"match\": {\n          \"path\": \"flight/{**catch-all}\"\n        },\n        \"Transforms\":  [\n          {\n            \"PathRemovePrefix\": \"flight\"\n          }\n        ]\n      },\n      \"passenger\": {\n        \"clusterId\": \"passenger\",\n        \"match\": {\n          \"path\": \"passenger/{**catch-all}\"\n        },\n        \"Transforms\":  [\n          {\n            \"PathRemovePrefix\": \"passenger\"\n          }\n        ]\n      },\n      \"booking\": {\n        \"clusterId\": \"booking\",\n        \"match\": {\n          \"path\": \"booking/{**catch-all}\"\n        },\n        \"Transforms\":  [\n          {\n            \"PathRemovePrefix\": \"booking\"\n          }\n        ]\n      }\n    },\n    \"clusters\": {\n      \"flight\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://localhost:5004\"\n          }\n        }\n      },\n      \"identity\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://localhost:6005\"\n          }\n        }\n      },\n      \"passenger\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://localhost:6012\"\n          }\n        }\n      },\n      \"booking\": {\n        \"destinations\": {\n          \"destination1\": {\n            \"address\": \"http://localhost:6010\"\n          }\n        }\n      }\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Aspire/src/AppHost/AppHost.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Sdk Name=\"Aspire.AppHost.SDK\" Version=\"13.1.1\"/>\n  \n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsAspireHost>true</IsAspireHost>\n    <UserSecretsId>bde28db3-85ba-4201-b889-0f3faba24169</UserSecretsId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.AppHost\" Version=\"13.1.1\" />\n    <PackageReference Include=\"Aspire.Hosting.Docker\" Version=\"13.1.1-preview.1.26105.8\" />\n    <PackageReference Include=\"Aspire.Hosting.MongoDB\" Version=\"13.1.1\" />\n    <PackageReference Include=\"Aspire.Hosting.PostgreSQL\" Version=\"13.1.1\" />\n    <PackageReference Include=\"Aspire.Hosting.RabbitMQ\" Version=\"13.1.1\" />\n    <PackageReference Include=\"Aspire.Hosting.Redis\" Version=\"13.1.1\" />\n    <PackageReference Include=\"CommunityToolkit.Aspire.Hosting.EventStore\" Version=\"9.9.0\" />\n    <PackageReference Include=\"Elastic.Aspire.Hosting.Elasticsearch\" Version=\"9.3.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\ApiGateway\\src\\ApiGateway.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\Services\\Booking\\src\\Booking.Api\\Booking.Api.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\Services\\Flight\\src\\Flight.Api\\Flight.Api.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\Services\\Identity\\src\\Identity.Api\\Identity.Api.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\Services\\Passenger\\src\\Passenger.Api\\Passenger.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Aspire/src/AppHost/Program.cs",
    "content": "using System.Net.Sockets;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\nbuilder.AddDockerComposeEnvironment(\"docker-compose\");\n\n// 1. Database Services\nvar pgUsername = builder.AddParameter(\"pg-username\", \"postgres\", secret: true);\nvar pgPassword = builder.AddParameter(\"pg-password\", \"postgres\", secret: true);\n\nvar postgres = builder.AddPostgres(\"postgres\", pgUsername, pgPassword)\n    .WithImage(\"postgres:latest\")\n    .WithEndpoint(\n        \"tcp\",\n        e =>\n        {\n            e.Port = 5432;\n            e.TargetPort = 5432;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        })\n    .WithArgs(\n        \"-c\",\n        \"wal_level=logical\",\n        \"-c\",\n        \"max_prepared_transactions=10\");\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    postgres.WithDataVolume(\"postgres-data\")\n        .WithLifetime(ContainerLifetime.Persistent);\n}\n\n\nvar flightDb = postgres.AddDatabase(\"flight\");\nvar passengerDb = postgres.AddDatabase(\"passenger\");\nvar identityDb = postgres.AddDatabase(\"identity\");\nvar persistMessageDb = postgres.AddDatabase(\"persist-message\");\n\nvar mongoUsername = builder.AddParameter(\"mongo-username\", \"root\", secret: true);\nvar mongoPassword = builder.AddParameter(\"mongo-password\", \"secret\", secret: true);\n\nvar mongo = builder.AddMongoDB(\"mongo\", userName: mongoUsername, password: mongoPassword)\n    .WithImage(\"mongo\")\n    .WithImageTag(\"latest\")\n    .WithEndpoint(\n        \"tcp\",\n        e =>\n        {\n            e.Port = 27017;\n            e.TargetPort = 27017;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        });\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    mongo.WithDataVolume(\"mongo-data\")\n        .WithLifetime(ContainerLifetime.Persistent);\n}\n\n\nvar redis = builder.AddRedis(\"redis\")\n    .WithImage(\"redis:latest\")\n    .WithEndpoint(\n        \"tcp\",\n        e =>\n        {\n            e.Port = 6379;\n            e.TargetPort = 6379;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        });\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    redis.WithDataVolume(\"redis-data\")\n        .WithLifetime(ContainerLifetime.Persistent);\n}\n\n\nvar eventstore = builder.AddEventStore(\"eventstore\")\n    .WithImage(\"eventstore/eventstore\")\n    .WithEnvironment(\"EVENTSTORE_CLUSTER_SIZE\", \"1\")\n    .WithEnvironment(\"EVENTSTORE_RUN_PROJECTIONS\", \"All\")\n    .WithEnvironment(\"EVENTSTORE_START_STANDARD_PROJECTIONS\", \"True\")\n    .WithEnvironment(\"EVENTSTORE_INSECURE\", \"True\")\n    .WithEnvironment(\"EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP\", \"True\")\n    .WithEndpoint(\n        \"http\",\n        e =>\n        {\n            e.TargetPort = 2113;\n            e.Port = 2113;\n            e.IsProxied = true;\n            e.IsExternal = true;\n        })\n    .WithEndpoint(\n        port: 1113,\n        targetPort: 1113,\n        name: \"tcp\",\n        isProxied: true,\n        isExternal: false);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    eventstore.WithDataVolume(\"eventstore-data\")\n        .WithLifetime(ContainerLifetime.Persistent);\n}\n\n// 2. Messaging Services\nvar rabbitmqUsername = builder.AddParameter(\"rabbitmq-username\", \"guest\", secret: true);\nvar rabbitmqPassword = builder.AddParameter(\"rabbitmq-password\", \"guest\", secret: true);\n\nvar rabbitmq = builder.AddRabbitMQ(\"rabbitmq\", rabbitmqUsername, rabbitmqPassword)\n    .WithManagementPlugin()\n    .WithEndpoint(\n        \"tcp\",\n        e =>\n        {\n            e.TargetPort = 5672;\n            e.Port = 5672;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        })\n    .WithEndpoint(\n        \"management\",\n        e =>\n        {\n            e.TargetPort = 15672;\n            e.Port = 15672;\n            e.IsProxied = true;\n            e.IsExternal = true;\n        });\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    rabbitmq.WithLifetime(ContainerLifetime.Persistent);\n}\n\n// // 3. Observability Services\nvar jaeger = builder.AddContainer(\"jaeger-all-in-one\", \"jaegertracing/all-in-one\")\n    .WithEndpoint(\n        port: 6831,\n        targetPort: 6831,\n        name: \"agent\",\n        protocol: ProtocolType.Udp,\n        isProxied: true,\n        isExternal: false)\n    .WithEndpoint(port: 16686, targetPort: 16686, name: \"http\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 14268, targetPort: 14268, name: \"collector\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 14317, targetPort: 4317, name: \"otlp-grpc\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 14318, targetPort: 4318, name: \"otlp-http\", isProxied: true, isExternal: false);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    jaeger.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar zipkin = builder.AddContainer(\"zipkin-all-in-one\", \"openzipkin/zipkin\")\n    .WithEndpoint(port: 9411, targetPort: 9411, name: \"http\", isProxied: true, isExternal: true);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    zipkin.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar otelCollector = builder.AddContainer(\"otel-collector\", \"otel/opentelemetry-collector-contrib\")\n    .WithBindMount(\n        \"../../../../deployments/configs/otel-collector-config.yaml\",\n        \"/etc/otelcol-contrib/config.yaml\",\n        isReadOnly: true)\n    .WithArgs(\"--config=/etc/otelcol-contrib/config.yaml\")\n    .WithEndpoint(port: 11888, targetPort: 1888, name: \"otel-pprof\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 8888, targetPort: 8888, name: \"otel-metrics\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 8889, targetPort: 8889, name: \"otel-exporter-metrics\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 13133, targetPort: 13133, name: \"otel-health\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 4317, targetPort: 4317, name: \"otel-grpc\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 4318, targetPort: 4318, name: \"otel-http\", isProxied: true, isExternal: true)\n    .WithEndpoint(port: 55679, targetPort: 55679, name: \"otel-zpages\", isProxied: true, isExternal: true);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    otelCollector.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar prometheus = builder.AddContainer(\"prometheus\", \"prom/prometheus\")\n    .WithBindMount(\"../../../../deployments/configs/prometheus.yaml\", \"/etc/prometheus/prometheus.yml\")\n    .WithArgs(\n        \"--config.file=/etc/prometheus/prometheus.yml\",\n        \"--storage.tsdb.path=/prometheus\",\n        \"--web.console.libraries=/usr/share/prometheus/console_libraries\",\n        \"--web.console.templates=/usr/share/prometheus/consoles\",\n        \"--web.enable-remote-write-receiver\")\n    .WithEndpoint(port: 9090, targetPort: 9090, name: \"http\", isProxied: true, isExternal: true);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    prometheus.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar grafana = builder.AddContainer(\"grafana\", \"grafana/grafana\")\n    .WithEnvironment(\"GF_INSTALL_PLUGINS\", \"grafana-clock-panel,grafana-simple-json-datasource\")\n    .WithEnvironment(\"GF_SECURITY_ADMIN_USER\", \"admin\")\n    .WithEnvironment(\"GF_SECURITY_ADMIN_PASSWORD\", \"admin\")\n    .WithEnvironment(\"GF_FEATURE_TOGGLES_ENABLE\", \"traceqlEditor\")\n    .WithBindMount(\"../../../../deployments/configs/grafana/provisioning\", \"/etc/grafana/provisioning\")\n    .WithBindMount(\"../../../../deployments/configs/grafana/dashboards\", \"/var/lib/grafana/dashboards\")\n    .WithEndpoint(port: 3000, targetPort: 3000, name: \"http\", isProxied: true, isExternal: true);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    grafana.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar nodeExporter = builder.AddContainer(\"node-exporter\", \"prom/node-exporter\")\n    .WithBindMount(\"/proc\", \"/host/proc\", isReadOnly: true)\n    .WithBindMount(\"/sys\", \"/host/sys\", isReadOnly: true)\n    .WithBindMount(\"/\", \"/rootfs\", isReadOnly: true)\n    .WithArgs(\n        \"--path.procfs=/host/proc\",\n        \"--path.rootfs=/rootfs\",\n        \"--path.sysfs=/host/sys\")\n    .WithEndpoint(port: 9101, targetPort: 9100, name: \"http\", isProxied: true, isExternal: true);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    nodeExporter.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar tempo = builder.AddContainer(\"tempo\", \"grafana/tempo\")\n    .WithBindMount(\"../../../../deployments/configs/tempo.yaml\", \"/etc/tempo.yaml\", isReadOnly: true)\n    .WithArgs(\"--config.file=/etc/tempo.yaml\")\n    .WithEndpoint(port: 3200, targetPort: 3200, name: \"http\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 9095, targetPort: 9095, name: \"grpc\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 4317, targetPort: 4317, name: \"otlp-grpc\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 4318, targetPort: 4318, name: \"otlp-http\", isProxied: true, isExternal: false);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    tempo.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar loki = builder.AddContainer(\"loki\", \"grafana/loki\")\n    .WithBindMount(\"../../../../deployments/configs/loki-config.yaml\", \"/etc/loki/local-config.yaml\", isReadOnly: true)\n    .WithArgs(\"-config.file=/etc/loki/local-config.yaml\")\n    .WithEndpoint(port: 3100, targetPort: 3100, name: \"http\", isProxied: true, isExternal: false)\n    .WithEndpoint(port: 9096, targetPort: 9096, name: \"grpc\", isProxied: true, isExternal: false);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    loki.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar elasticsearch = builder.AddElasticsearch(\"elasticsearch\")\n    .WithImage(\"docker.elastic.co/elasticsearch/elasticsearch:8.17.0\")\n    .WithEnvironment(\"discovery.type\", \"single-node\")\n    .WithEnvironment(\"cluster.name\", \"docker-cluster\")\n    .WithEnvironment(\"node.name\", \"docker-node\")\n    .WithEnvironment(\"ES_JAVA_OPTS\", \"-Xms512m -Xmx512m\")\n    .WithEnvironment(\"xpack.security.enabled\", \"false\")\n    .WithEnvironment(\"xpack.security.http.ssl.enabled\", \"false\")\n    .WithEnvironment(\"xpack.security.transport.ssl.enabled\", \"false\")\n    .WithEnvironment(\"network.host\", \"0.0.0.0\")\n    .WithEnvironment(\"http.port\", \"9200\")\n    .WithEnvironment(\"transport.host\", \"localhost\")\n    .WithEnvironment(\"bootstrap.memory_lock\", \"true\")\n    .WithEnvironment(\"cluster.routing.allocation.disk.threshold_enabled\", \"false\")\n    .WithEndpoint(\n        \"http\",\n        e =>\n        {\n            e.TargetPort = 9200;\n            e.Port = 9200;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        })\n    .WithEndpoint(\n        \"internal\",\n        e =>\n        {\n            e.TargetPort = 9300;\n            e.Port = 9300;\n            e.IsProxied = true;\n            e.IsExternal = false;\n        })\n    .WithDataVolume(\"elastic-data\");\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    elasticsearch.WithLifetime(ContainerLifetime.Persistent);\n}\n\nvar kibana = builder.AddContainer(\"kibana\", \"docker.elastic.co/kibana/kibana:8.17.0\")\n    .WithEnvironment(\"ELASTICSEARCH_HOSTS\", \"http://elasticsearch:9200\")\n    .WithEndpoint(port: 5601, targetPort: 5601, name: \"http\", isProxied: true, isExternal: true)\n    .WithReference(elasticsearch)\n    .WaitFor(elasticsearch);\n\nif (builder.ExecutionContext.IsPublishMode)\n{\n    kibana.WithLifetime(ContainerLifetime.Persistent);\n}\n\n// 5. Application Services\nvar identity = builder.AddProject<Projects.Identity_Api>(\"identity-service\")\n    .WithReference(persistMessageDb)\n    .WaitFor(persistMessageDb)\n    .WithReference(identityDb)\n    .WaitFor(identityDb)\n    .WithReference(mongo)\n    .WaitFor(mongo)\n    .WithReference(rabbitmq)\n    .WaitFor(rabbitmq)\n    .WithHttpEndpoint(port: 6005, name: \"identity-http\")\n    .WithHttpsEndpoint(port: 5005, name: \"identity-https\");\n\nvar passenger = builder.AddProject<Projects.Passenger_Api>(\"passenger-service\")\n    .WithReference(persistMessageDb)\n    .WaitFor(persistMessageDb)\n    .WithReference(passengerDb)\n    .WaitFor(passengerDb)\n    .WithReference(mongo)\n    .WaitFor(mongo)\n    .WithReference(rabbitmq)\n    .WaitFor(rabbitmq)\n    .WithHttpEndpoint(port: 6012, name: \"passenger-http\")\n    .WithHttpsEndpoint(port: 5012, name: \"passenger-https\");\n\nvar flight = builder.AddProject<Projects.Flight_Api>(\"flight-service\")\n    .WithReference(persistMessageDb)\n    .WaitFor(persistMessageDb)\n    .WithReference(flightDb)\n    .WaitFor(flightDb)\n    .WithReference(mongo)\n    .WaitFor(mongo)\n    .WithReference(rabbitmq)\n    .WaitFor(rabbitmq)\n    .WithHttpEndpoint(port: 5004, name: \"flight-http\")\n    .WithHttpsEndpoint(port: 5003, name: \"flight-https\");\n\nvar booking = builder.AddProject<Projects.Booking_Api>(\"booking-service\")\n    .WithReference(persistMessageDb)\n    .WaitFor(persistMessageDb)\n    .WithReference(eventstore)\n    .WaitFor(eventstore)\n    .WithReference(mongo)\n    .WaitFor(mongo)\n    .WithReference(rabbitmq)\n    .WaitFor(rabbitmq)\n    .WithHttpEndpoint(port: 6010, name: \"booking-http\")\n    .WithHttpsEndpoint(port: 5010, name: \"booking-https\");\n\nvar gateway = builder.AddProject<Projects.ApiGateway>(\"api-gateway\")\n    .WithReference(flight)\n    .WaitFor(flight)\n    .WithReference(passenger)\n    .WaitFor(passenger)\n    .WithReference(identity)\n    .WaitFor(identity)\n    .WithReference(booking)\n    .WaitFor(booking)\n    .WithHttpEndpoint(port: 5001, name: \"gateway-http\")\n    .WithHttpsEndpoint(port: 5000, name: \"gateway-https\");\n\nbuilder.Build().Run();"
  },
  {
    "path": "src/Aspire/src/AppHost/Properties/launchSettings.json",
    "content": "﻿{\n    \"$schema\": \"http://json.schemastore.org/launchsettings.json\",\n    \"profiles\": {\n        \"AppHost\": {\n            \"commandName\": \"Project\",\n            \"dotnetRunMessages\": true,\n            \"launchBrowser\": true,\n            \"applicationUrl\": \"http://localhost:18888\",\n            \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n                \"DOTNET_ENVIRONMENT\": \"Development\",\n                \"ASPIRE_ALLOW_UNSECURED_TRANSPORT\": \"true\",\n                \"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL\": \"http://otel-collector:4317\",\n                \"ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL\": \"http://otel-collector:4318\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Aspire/src/AppHost/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/Aspire/src/AppHost/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Aspire/src/ServiceDefaults/Extensions.cs",
    "content": "using BuildingBlocks.HealthCheck;\nusing BuildingBlocks.OpenTelemetryCollector;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace ServiceDefaults;\n\npublic static class Extensions\n{\n    public static IHostApplicationBuilder AddServiceDefaults(this WebApplicationBuilder builder)\n    {\n        builder.Services.AddCustomHealthCheck();\n        builder.AddCustomObservability();\n        builder.Services.AddServiceDiscovery();\n\n        builder.Services.ConfigureHttpClientDefaults(http =>\n        {\n            http.AddStandardResilienceHandler(options =>\n            {\n                var timeSpan = TimeSpan.FromMinutes(1);\n                options.CircuitBreaker.SamplingDuration = timeSpan * 2;\n                options.TotalRequestTimeout.Timeout = timeSpan * 3;\n                options.Retry.MaxRetryAttempts = 3;\n            });\n\n            // Turn on service discovery by default\n            http.AddServiceDiscovery();\n        });\n\n        return builder;\n    }\n\n    public static WebApplication UseServiceDefaults(this WebApplication app)\n    {\n        app.UseCustomHealthCheck();\n        app.UseCustomObservability();\n\n        return app;\n    }\n}\n"
  },
  {
    "path": "src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" IsAspireProjectResource=\"false\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/BuildingBlocks/BuildingBlocks.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Ardalis.GuardClauses\" Version=\"5.0.0\" />\n    <PackageReference Include=\"Asp.Versioning.Abstractions\" Version=\"8.1.0\" />\n    <PackageReference Include=\"Asp.Versioning.Http\" Version=\"8.1.1\" />\n    <PackageReference Include=\"Asp.Versioning.Mvc\" Version=\"8.1.1\" />\n    <PackageReference Include=\"Asp.Versioning.Mvc.ApiExplorer\" Version=\"8.1.1\" />\n    <PackageReference Include=\"Figgle.Fonts\" Version=\"0.6.5\" />\n    <PackageReference Include=\"Grpc.Core.Testing\" Version=\"2.46.6\" />\n    <PackageReference Include=\"EasyCaching.Core\" Version=\"1.9.2\" />\n    <PackageReference Include=\"EasyCaching.InMemory\" Version=\"1.9.2\" />\n    <PackageReference Include=\"EasyNetQ.Management.Client\" Version=\"3.0.1\" />\n    <PackageReference Include=\"EFCore.NamingConventions\" Version=\"10.0.1\" />\n    <PackageReference Include=\"Figgle\" Version=\"0.6.5\" />\n    <PackageReference Include=\"FluentValidation\" Version=\"12.1.1\" />\n    <PackageReference Include=\"FluentValidation.AspNetCore\" Version=\"11.3.1\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.OpenApi\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyModel\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Http.Resilience\" Version=\"10.3.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.ServiceDiscovery\" Version=\"10.3.0\" />\n    <PackageReference Include=\"Npgsql\" Version=\"10.0.1\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.3.0\" />\n    <PackageReference Include=\"Polly\" Version=\"8.6.5\" />\n    <PackageReference Include=\"Humanizer.Core\" Version=\"3.0.1\" />\n    <PackageReference Include=\"IdGen\" Version=\"3.0.7\" />\n    <PackageReference Include=\"Mapster\" Version=\"7.4.0\" />\n    <PackageReference Include=\"Mapster.DependencyInjection\" Version=\"1.0.1\" />\n    <PackageReference Include=\"MediatR\" Version=\"14.0.0\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Authentication.JwtBearer\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.InMemory\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.SqlServer\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Abstractions\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Http.Polly\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"10.0.3\" />\n    <PackageReference Include=\"MongoDB.Driver\" Version=\"3.6.0\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.4\" />\n    <PackageReference Include=\"Scalar.AspNetCore\" Version=\"2.12.38\" />\n    <PackageReference Include=\"Scrutor\" Version=\"7.0.0\" />\n    <PackageReference Include=\"Sieve\" Version=\"2.5.5\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"10.1.2\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore.SwaggerGen\" Version=\"10.1.2\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore.SwaggerUI\" Version=\"10.1.2\" />\n    <PackageReference Include=\"MassTransit\" Version=\"8.5.8\" />\n    <PackageReference Include=\"MassTransit.RabbitMQ\" Version=\"8.5.8\" />\n    <PackageReference Include=\"Duende.IdentityServer\" Version=\"7.4.5\" />\n    <PackageReference Include=\"Duende.IdentityServer.AspNetIdentity\" Version=\"7.4.5\" />\n    <PackageReference Include=\"Duende.IdentityServer.EntityFramework\" Version=\"7.4.5\" />\n    <PackageReference Include=\"Duende.IdentityServer.EntityFramework.Storage\" Version=\"7.4.5\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Identity.EntityFrameworkCore\" Version=\"10.0.3\" />\n    <PackageReference Include=\"System.Linq.Async\" Version=\"7.0.0\" />\n    <PackageReference Include=\"System.Linq.Async.Queryable\" Version=\"7.0.0\" />\n    <PackageReference Include=\"Testcontainers\" Version=\"4.9.0\" />\n    <PackageReference Include=\"Testcontainers.EventStoreDb\" Version=\"4.9.0\" />\n    <PackageReference Include=\"Testcontainers.MongoDb\" Version=\"4.9.0\" />\n    <PackageReference Include=\"Testcontainers.PostgreSql\" Version=\"4.9.0\" />\n    <PackageReference Include=\"Testcontainers.RabbitMq\" Version=\"4.9.0\" />\n    <PackageReference Include=\"xunit.abstractions\" Version=\"2.0.3\" />\n    <PackageReference Include=\"xunit.extensibility.core\" Version=\"2.9.3\" />\n    <PackageReference Include=\"Xunit.Extensions.Logging\" Version=\"1.1.0\" />\n    <PackageReference Include=\"Yarp.ReverseProxy\" Version=\"2.3.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Diagnostics.HealthChecks\" Version=\"10.0.3\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.UI\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.UI.Client\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.UI.InMemory.Storage\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.EventStore\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.NpgSql\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.Rabbitmq\" Version=\"9.0.0\" />\n    <PackageReference Include=\"AspNetCore.HealthChecks.MongoDb\" Version=\"9.0.0\" />\n\n    <PackageReference Include=\"Npgsql.OpenTelemetry\" Version=\"10.0.1\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.OpenTelemetryProtocol\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Extensions.Hosting\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.AspNetCore\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.GrpcNetClient\" Version=\"1.15.0-beta.1\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Http\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Process\" Version=\"1.15.0-beta.1\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Runtime\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.Prometheus.AspNetCore\" Version=\"1.15.0-beta.1\" />\n    <PackageReference Include=\"Grafana.OpenTelemetry\" Version=\"1.5.2\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.Console\" Version=\"1.15.0\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.Zipkin\" Version=\"1.15.0\" />\n\n    <PackageReference Include=\"EventStore.Client.Grpc.Streams\" Version=\"23.3.9\" />\n    <PackageReference Include=\"Npgsql.EntityFrameworkCore.PostgreSQL\" Version=\"10.0.0\" />\n\n    <PackageReference Include=\"AutoBogus\" Version=\"2.13.1\" />\n    <PackageReference Include=\"Bogus\" Version=\"35.6.5\" />\n    <PackageReference Include=\"FluentAssertions\" Version=\"8.8.0\" />\n    <PackageReference Include=\"Respawn\" Version=\"7.0.0\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.TestHost\" Version=\"10.0.3\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Testing\" Version=\"10.0.3\" />\n    <PackageReference Include=\"WebMotions.Fake.Authentication.JwtBearer\" Version=\"10.0.0\" />\n\n    <PackageReference Include=\"Google.Protobuf\" Version=\"3.33.5\" />\n    <PackageReference Include=\"Grpc.Net.ClientFactory\" Version=\"2.76.0\" />\n\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"10.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/BuildingBlocks/Caching/CachingBehavior.cs",
    "content": "using EasyCaching.Core;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.Caching;\n\npublic class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>\n    where TRequest : notnull, IRequest<TResponse>\n    where TResponse : notnull\n{\n    private readonly IEasyCachingProvider _cachingProvider;\n    private readonly ILogger<CachingBehavior<TRequest, TResponse>> _logger;\n    private readonly int defaultCacheExpirationInHours = 1;\n\n    public CachingBehavior(IEasyCachingProviderFactory cachingFactory,\n        ILogger<CachingBehavior<TRequest, TResponse>> logger)\n    {\n        _logger = logger;\n        _cachingProvider = cachingFactory.GetCachingProvider(\"mem\");\n    }\n\n    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,\n        CancellationToken cancellationToken)\n    {\n        if (request is not ICacheRequest cacheRequest)\n            // No cache request found, so just continue through the pipeline\n            return await next();\n\n        var cacheKey = cacheRequest.CacheKey;\n        var cachedResponse = await _cachingProvider.GetAsync<TResponse>(cacheKey);\n        if (cachedResponse.Value != null)\n        {\n            _logger.LogDebug(\"Response retrieved {TRequest} from cache. CacheKey: {CacheKey}\",\n                typeof(TRequest).FullName, cacheKey);\n            return cachedResponse.Value;\n        }\n\n        var response = await next();\n\n        var expirationTime = cacheRequest.AbsoluteExpirationRelativeToNow ??\n                             DateTime.Now.AddHours(defaultCacheExpirationInHours);\n\n        await _cachingProvider.SetAsync(cacheKey, response, expirationTime.TimeOfDay);\n\n        _logger.LogDebug(\"Caching response for {TRequest} with cache key: {CacheKey}\", typeof(TRequest).FullName,\n            cacheKey);\n\n        return response;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Caching/ICacheRequest.cs",
    "content": "namespace BuildingBlocks.Caching;\n\npublic interface ICacheRequest\n{\n    string CacheKey { get; }\n    DateTime? AbsoluteExpirationRelativeToNow { get; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Caching/IInvalidateCacheRequest.cs",
    "content": "namespace BuildingBlocks.Caching\n{\n    public interface IInvalidateCacheRequest\n    {\n        string CacheKey { get; }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Caching/InvalidateCachingBehavior.cs",
    "content": "using EasyCaching.Core;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.Caching\n{\n    public class InvalidateCachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>\n        where TRequest : notnull, IRequest<TResponse>\n        where TResponse : notnull\n    {\n        private readonly ILogger<InvalidateCachingBehavior<TRequest, TResponse>> _logger;\n        private readonly IEasyCachingProvider _cachingProvider;\n\n        public InvalidateCachingBehavior(IEasyCachingProviderFactory cachingFactory,\n            ILogger<InvalidateCachingBehavior<TRequest, TResponse>> logger)\n        {\n            _logger = logger;\n            _cachingProvider = cachingFactory.GetCachingProvider(\"mem\");\n        }\n\n        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)\n        {\n            if (request is not IInvalidateCacheRequest invalidateCacheRequest)\n            {\n                // No cache request found, so just continue through the pipeline\n                return await next();\n            }\n\n            var cacheKey = invalidateCacheRequest.CacheKey;\n            var response = await next();\n\n            await _cachingProvider.RemoveAsync(cacheKey);\n\n            _logger.LogDebug(\"Cache data with cache key: {CacheKey} removed.\", cacheKey);\n\n            return response;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Constants/IdentityConstant.cs",
    "content": "namespace BuildingBlocks.Constants;\n\npublic static class IdentityConstant\n{\n    public static class Role\n    {\n        public const string Admin = \"admin\";\n        public const string User = \"user\";\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Contracts/EventBus.Messages/FlighContracts.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Contracts.EventBus.Messages;\n\npublic record FlightCreated(Guid Id) : IIntegrationEvent;\npublic record FlightUpdated(Guid Id) : IIntegrationEvent;\npublic record FlightDeleted(Guid Id) : IIntegrationEvent;\npublic record AircraftCreated(Guid Id) : IIntegrationEvent;\npublic record AirportCreated(Guid Id) : IIntegrationEvent;\npublic record SeatCreated(Guid Id) : IIntegrationEvent;\npublic record SeatReserved(Guid Id) : IIntegrationEvent;"
  },
  {
    "path": "src/BuildingBlocks/Contracts/EventBus.Messages/IdentityContracts.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Contracts.EventBus.Messages;\n\npublic record UserCreated(Guid Id, string Name, string PassportNumber) : IIntegrationEvent;"
  },
  {
    "path": "src/BuildingBlocks/Contracts/EventBus.Messages/PassengerContracts.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Contracts.EventBus.Messages;\n\npublic record PassengerRegistrationCompleted(Guid Id) : IIntegrationEvent;\npublic record PassengerCreated(Guid Id) : IIntegrationEvent;"
  },
  {
    "path": "src/BuildingBlocks/Contracts/EventBus.Messages/ReservationContracts.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Contracts.EventBus.Messages;\n\npublic record BookingCreated(Guid Id) : IIntegrationEvent;"
  },
  {
    "path": "src/BuildingBlocks/Core/CQRS/ICommand.cs",
    "content": "using MediatR;\n\nnamespace BuildingBlocks.Core.CQRS;\n\npublic interface ICommand : ICommand<Unit>\n{\n}\n\npublic interface ICommand<out T> : IRequest<T>\n    where T : notnull\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/CQRS/ICommandHandler.cs",
    "content": "using MediatR;\n\nnamespace BuildingBlocks.Core.CQRS;\n\npublic interface ICommandHandler<in TCommand> : ICommandHandler<TCommand, Unit>\n    where TCommand : ICommand<Unit>\n{\n}\n\npublic interface ICommandHandler<in TCommand, TResponse> : IRequestHandler<TCommand, TResponse>\n    where TCommand : ICommand<TResponse>\n    where TResponse : notnull\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/CQRS/IQuery.cs",
    "content": "using MediatR;\n\nnamespace BuildingBlocks.Core.CQRS;\n\npublic interface IQuery<out T> : IRequest<T>\n    where T : notnull\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/CQRS/IQueryHandler.cs",
    "content": "using MediatR;\n\nnamespace BuildingBlocks.Core.CQRS;\n\npublic interface IQueryHandler<in TQuery, TResponse> : IRequestHandler<TQuery, TResponse>\n    where TQuery : IQuery<TResponse>\n    where TResponse : notnull\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/CompositeEventMapper.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core;\n\npublic class CompositeEventMapper : IEventMapper\n{\n    private readonly IEnumerable<IEventMapper> _mappers;\n\n    public CompositeEventMapper(IEnumerable<IEventMapper> mappers)\n    {\n        _mappers = mappers;\n    }\n\n    public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)\n    {\n        foreach (var mapper in _mappers)\n        {\n            var integrationEvent = mapper.MapToIntegrationEvent(@event);\n            if (integrationEvent is not null)\n                return integrationEvent;\n        }\n\n        return null;\n    }\n\n    public IInternalCommand? MapToInternalCommand(IDomainEvent @event)\n    {\n        foreach (var mapper in _mappers)\n        {\n            var internalCommand = mapper.MapToInternalCommand(@event);\n            if (internalCommand is not null)\n                return internalCommand;\n        }\n\n        return null;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/EventType.cs",
    "content": "namespace BuildingBlocks.Core.Event;\n\n[Flags]\npublic enum EventType\n{\n    DomainEvent = 1,\n    IntegrationEvent = 2,\n    InternalCommand = 4\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/IDomainEvent.cs",
    "content": "namespace BuildingBlocks.Core.Event;\n\npublic interface IDomainEvent : IEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/IEvent.cs",
    "content": "using MediatR;\n\nnamespace BuildingBlocks.Core.Event;\n\nusing global::MassTransit;\n\npublic interface IEvent : INotification\n{\n    Guid EventId => NewId.NextGuid();\n    public DateTime OccurredOn => DateTime.Now;\n    public string EventType => GetType().AssemblyQualifiedName;\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/IHaveIntegrationEvent.cs",
    "content": "namespace BuildingBlocks.Core.Event;\n\npublic interface IHaveIntegrationEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/IIntegrationEvent.cs",
    "content": "using MassTransit;\n\nnamespace BuildingBlocks.Core.Event;\n\n[ExcludeFromTopology]\npublic interface IIntegrationEvent : IEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/IInternalCommand.cs",
    "content": "namespace BuildingBlocks.Core.Event;\n\npublic interface IInternalCommand : IEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/InternalCommand.cs",
    "content": "using BuildingBlocks.Core.CQRS;\n\nnamespace BuildingBlocks.Core.Event;\n\npublic record InternalCommand : IInternalCommand, ICommand;"
  },
  {
    "path": "src/BuildingBlocks/Core/Event/MessageEnvelope.cs",
    "content": "using Google.Protobuf;\n\nnamespace BuildingBlocks.Core.Event;\n\npublic class MessageEnvelope\n{\n    public MessageEnvelope(object? message, IDictionary<string, object?>? headers = null)\n    {\n        Message = message;\n        Headers = headers ?? new Dictionary<string, object?>();\n    }\n\n    public object? Message { get; init; }\n    public IDictionary<string, object?> Headers { get; init; }\n}\n\npublic class MessageEnvelope<TMessage> : MessageEnvelope\n    where TMessage : class, IMessage\n{\n    public MessageEnvelope(TMessage message, IDictionary<string, object?> header) : base(message, header)\n    {\n        Message = message;\n    }\n\n    public new TMessage? Message { get; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/EventDispatcher.cs",
    "content": "using System.Security.Claims;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.Web;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing MessageEnvelope = BuildingBlocks.Core.Event.MessageEnvelope;\n\nnamespace BuildingBlocks.Core;\n\npublic sealed class EventDispatcher(\n    IServiceScopeFactory serviceScopeFactory,\n    IEventMapper eventMapper,\n    ILogger<EventDispatcher> logger,\n    IPersistMessageProcessor persistMessageProcessor,\n    IHttpContextAccessor httpContextAccessor\n)\n    : IEventDispatcher\n{\n    public async Task SendAsync<T>(IReadOnlyList<T> events, Type type = null,\n                                   CancellationToken cancellationToken = default)\n        where T : IEvent\n    {\n        if (events.Count > 0)\n        {\n            var eventType = type != null && type.IsAssignableTo(typeof(IInternalCommand))\n                ? EventType.InternalCommand\n                : EventType.DomainEvent;\n\n            async Task PublishIntegrationEvent(IReadOnlyList<IIntegrationEvent> integrationEvents)\n            {\n                foreach (var integrationEvent in integrationEvents)\n                {\n                    await persistMessageProcessor.PublishMessageAsync(\n                        new MessageEnvelope(integrationEvent, SetHeaders()),\n                        cancellationToken);\n                }\n            }\n\n            switch (events)\n            {\n                case IReadOnlyList<IDomainEvent> domainEvents:\n                    {\n                        var integrationEvents = await MapDomainEventToIntegrationEventAsync(domainEvents)\n                        .ConfigureAwait(false);\n\n                        await PublishIntegrationEvent(integrationEvents);\n                        break;\n                    }\n\n                case IReadOnlyList<IIntegrationEvent> integrationEvents:\n                    await PublishIntegrationEvent(integrationEvents);\n                    break;\n            }\n\n            if (type != null && eventType == EventType.InternalCommand)\n            {\n                var internalMessages = await MapDomainEventToInternalCommandAsync(events as IReadOnlyList<IDomainEvent>)\n                    .ConfigureAwait(false);\n\n                foreach (var internalMessage in internalMessages)\n                {\n                    await persistMessageProcessor.AddInternalMessageAsync(internalMessage, cancellationToken);\n                }\n            }\n        }\n    }\n\n    public async Task SendAsync<T>(T @event, Type type = null,\n        CancellationToken cancellationToken = default)\n        where T : IEvent =>\n        await SendAsync(new[] { @event }, type, cancellationToken);\n\n\n    private Task<IReadOnlyList<IIntegrationEvent>> MapDomainEventToIntegrationEventAsync(\n        IReadOnlyList<IDomainEvent> events)\n    {\n        logger.LogTrace(\"Processing integration events start...\");\n\n        var wrappedIntegrationEvents = GetWrappedIntegrationEvents(events.ToList())?.ToList();\n        if (wrappedIntegrationEvents?.Count > 0)\n            return Task.FromResult<IReadOnlyList<IIntegrationEvent>>(wrappedIntegrationEvents);\n\n        var integrationEvents = new List<IIntegrationEvent>();\n        using var scope = serviceScopeFactory.CreateScope();\n        foreach (var @event in events)\n        {\n            var eventType = @event.GetType();\n            logger.LogTrace($\"Handling domain event: {eventType.Name}\");\n\n            var integrationEvent = eventMapper.MapToIntegrationEvent(@event);\n\n            if (integrationEvent is null)\n                continue;\n\n            integrationEvents.Add(integrationEvent);\n        }\n\n        logger.LogTrace(\"Processing integration events done...\");\n\n        return Task.FromResult<IReadOnlyList<IIntegrationEvent>>(integrationEvents);\n    }\n\n\n    private Task<IReadOnlyList<IInternalCommand>> MapDomainEventToInternalCommandAsync(\n        IReadOnlyList<IDomainEvent> events)\n    {\n        logger.LogTrace(\"Processing internal message start...\");\n\n        var internalCommands = new List<IInternalCommand>();\n        using var scope = serviceScopeFactory.CreateScope();\n        foreach (var @event in events)\n        {\n            var eventType = @event.GetType();\n            logger.LogTrace($\"Handling domain event: {eventType.Name}\");\n\n            var integrationEvent = eventMapper.MapToInternalCommand(@event);\n\n            if (integrationEvent is null)\n                continue;\n\n            internalCommands.Add(integrationEvent);\n        }\n\n        logger.LogTrace(\"Processing internal message done...\");\n\n        return Task.FromResult<IReadOnlyList<IInternalCommand>>(internalCommands);\n    }\n\n    private IEnumerable<IIntegrationEvent> GetWrappedIntegrationEvents(IReadOnlyList<IDomainEvent> domainEvents)\n    {\n        foreach (var domainEvent in domainEvents.Where(x =>\n                     x is IHaveIntegrationEvent))\n        {\n            var genericType = typeof(IntegrationEventWrapper<>)\n                .MakeGenericType(domainEvent.GetType());\n\n            var domainNotificationEvent = (IIntegrationEvent)Activator\n                .CreateInstance(genericType, domainEvent);\n\n            yield return domainNotificationEvent;\n        }\n    }\n\n    private IDictionary<string, object> SetHeaders()\n    {\n        var headers = new Dictionary<string, object>();\n        headers.Add(\"CorrelationId\", httpContextAccessor?.HttpContext?.GetCorrelationId());\n        headers.Add(\"UserId\", httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier));\n        headers.Add(\"UserName\", httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.Name));\n\n        return headers;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/IEventDispatcher.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core;\n\npublic interface IEventDispatcher\n{\n    public Task SendAsync<T>(IReadOnlyList<T> events, Type type = null, CancellationToken cancellationToken = default)\n        where T : IEvent;\n    public Task SendAsync<T>(T @event, Type type = null, CancellationToken cancellationToken = default)\n        where T : IEvent;\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/IEventMapper.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core;\n\npublic interface IEventMapper\n{\n    IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event);\n    IInternalCommand? MapToInternalCommand(IDomainEvent @event);\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/IntegrationEventWrapper.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core;\n\npublic record IntegrationEventWrapper<TDomainEventType>(TDomainEventType DomainEvent) : IIntegrationEvent\n    where TDomainEventType : IDomainEvent;"
  },
  {
    "path": "src/BuildingBlocks/Core/Model/Aggregate.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core.Model;\n\npublic abstract record Aggregate<TId> : Entity<TId>, IAggregate<TId>\n{\n    private readonly List<IDomainEvent> _domainEvents = new();\n    public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();\n\n    public void AddDomainEvent(IDomainEvent domainEvent)\n    {\n        _domainEvents.Add(domainEvent);\n    }\n\n    public IEvent[] ClearDomainEvents()\n    {\n        IEvent[] dequeuedEvents = _domainEvents.ToArray();\n\n        _domainEvents.Clear();\n\n        return dequeuedEvents;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Model/Entity.cs",
    "content": "namespace BuildingBlocks.Core.Model;\n\npublic abstract record Entity<T> : IEntity<T>\n{\n    public T Id { get; set; }\n    public DateTime? CreatedAt { get; set; }\n    public long? CreatedBy { get; set; }\n    public DateTime? LastModified { get; set; }\n    public long? LastModifiedBy { get; set; }\n    public bool IsDeleted { get; set; }\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Model/IAggregate.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.Core.Model;\n\npublic interface IAggregate<T> : IAggregate, IEntity<T>\n{\n}\n\npublic interface IAggregate : IEntity\n{\n    IReadOnlyList<IDomainEvent> DomainEvents { get; }\n    IEvent[] ClearDomainEvents();\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Model/IEntity.cs",
    "content": "namespace BuildingBlocks.Core.Model;\n\npublic interface IEntity<T> : IEntity\n{\n    public T Id { get; set; }\n}\n\npublic interface IEntity : IVersion\n{\n    public DateTime? CreatedAt { get; set; }\n    public long? CreatedBy { get; set; }\n    public DateTime? LastModified { get; set; }\n    public long? LastModifiedBy { get; set; }\n    public bool IsDeleted { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Model/IVersion.cs",
    "content": "namespace BuildingBlocks.Core.Model;\n\n// For handling optimistic concurrency\npublic interface IVersion\n{\n    long Version { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Pagination/Extensions.cs",
    "content": "namespace BuildingBlocks.Core.Pagination;\n\nusing Sieve.Models;\nusing Sieve.Services;\n\npublic static class Extensions\n{\n    public static async Task<IPageList<TEntity>> ApplyPagingAsync<TEntity>(\n        this IQueryable<TEntity> queryable,\n        IPageRequest pageRequest,\n        ISieveProcessor sieveProcessor,\n        CancellationToken cancellationToken = default\n    )\n        where TEntity : class\n    {\n        var sieveModel = new SieveModel\n        {\n            PageSize = pageRequest.PageSize,\n            Page = pageRequest.PageNumber,\n            Sorts = pageRequest.SortOrder,\n            Filters = pageRequest.Filters\n        };\n\n        // https://github.com/Biarity/Sieve/issues/34#issuecomment-403817573\n        var result = sieveProcessor.Apply(sieveModel, queryable, applyPagination: false);\n        var total = result.Count();\n        result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false,\n            applySorting: false); // Only applies pagination\n\n        var items = await result\n            .ToAsyncEnumerable()\n            .ToListAsync(cancellationToken: cancellationToken);\n\n        return PageList<TEntity>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Pagination/IPageList.cs",
    "content": "namespace BuildingBlocks.Core.Pagination;\n\npublic interface IPageList<T>\n    where T : class\n{\n    int CurrentPageSize { get; }\n    int CurrentStartIndex { get; }\n    int CurrentEndIndex { get; }\n    int TotalPages { get; }\n    bool HasPrevious { get; }\n    bool HasNext { get; }\n    IReadOnlyList<T> Items { get; init; }\n    int TotalCount { get; init; }\n    int PageNumber { get; init; }\n    int PageSize { get; init; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Pagination/IPageQuery.cs",
    "content": "namespace BuildingBlocks.Core.Pagination;\n\nusing MediatR;\n\npublic interface IPageQuery<out TResponse> : IPageRequest, IRequest<TResponse>\n    where TResponse : class\n{ }"
  },
  {
    "path": "src/BuildingBlocks/Core/Pagination/IPageRequest.cs",
    "content": "namespace BuildingBlocks.Core.Pagination;\n\npublic interface IPageRequest\n{\n    int PageNumber { get; init; }\n    int PageSize { get; init; }\n    string? Filters { get; init; }\n    string? SortOrder { get; init; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Core/Pagination/PageList.cs",
    "content": "namespace BuildingBlocks.Core.Pagination;\n\npublic record PageList<T>(IReadOnlyList<T> Items, int PageNumber, int PageSize, int TotalCount) : IPageList<T>\n    where T : class\n{\n    public int CurrentPageSize => Items.Count;\n    public int CurrentStartIndex => TotalCount == 0 ? 0 : ((PageNumber - 1) * PageSize) + 1;\n    public int CurrentEndIndex => TotalCount == 0 ? 0 : CurrentStartIndex + CurrentPageSize - 1;\n    public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);\n    public bool HasPrevious => PageNumber > 1;\n    public bool HasNext => PageNumber < TotalPages;\n\n    public static PageList<T> Empty => new(Enumerable.Empty<T>().ToList(), 0, 0, 0);\n\n    public static PageList<T> Create(IReadOnlyList<T> items, int pageNumber, int pageSize, int totalItems)\n    {\n        return new PageList<T>(items, pageNumber, pageSize, totalItems);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/AppDbContextBase.cs",
    "content": "using System.Collections.Immutable;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\nusing BuildingBlocks.Web;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.Logging;\nusing IsolationLevel = System.Data.IsolationLevel;\n\nnamespace BuildingBlocks.EFCore;\n\npublic abstract class AppDbContextBase : DbContext, IDbContext\n{\n    private readonly ICurrentUserProvider? _currentUserProvider;\n    private readonly ILogger<AppDbContextBase>? _logger;\n    private IDbContextTransaction _currentTransaction;\n\n    protected AppDbContextBase(DbContextOptions options, ICurrentUserProvider? currentUserProvider = null, ILogger<AppDbContextBase>? logger = null) :\n        base(options)\n    {\n        _currentUserProvider = currentUserProvider;\n        _logger = logger;\n    }\n\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n    }\n\n    public IExecutionStrategy CreateExecutionStrategy() => Database.CreateExecutionStrategy();\n\n    public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        if (_currentTransaction != null)\n            return;\n\n        _currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken);\n    }\n\n    public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            await SaveChangesAsync(cancellationToken);\n            await _currentTransaction?.CommitAsync(cancellationToken)!;\n        }\n        catch\n        {\n            await RollbackTransactionAsync(cancellationToken);\n            throw;\n        }\n        finally\n        {\n            _currentTransaction?.Dispose();\n            _currentTransaction = null;\n        }\n    }\n\n    public async Task RollbackTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            await _currentTransaction?.RollbackAsync(cancellationToken)!;\n        }\n        finally\n        {\n            _currentTransaction?.Dispose();\n            _currentTransaction = null;\n        }\n    }\n\n\n    //ref: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency#execution-strategies-and-transactions\n    public Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default)\n    {\n        var strategy = CreateExecutionStrategy();\n        return strategy.ExecuteAsync(async () =>\n        {\n            await using var transaction =\n                await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken);\n            try\n            {\n                await SaveChangesAsync(cancellationToken);\n                await transaction.CommitAsync(cancellationToken);\n            }\n            catch\n            {\n                await transaction.RollbackAsync(cancellationToken);\n                throw;\n            }\n        });\n    }\n\n    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)\n    {\n        OnBeforeSaving();\n        try\n        {\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n        //ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=data-annotations#resolving-concurrency-conflicts\n        catch (DbUpdateConcurrencyException ex)\n        {\n            foreach (var entry in ex.Entries)\n            {\n                var databaseValues = await entry.GetDatabaseValuesAsync(cancellationToken);\n\n                if (databaseValues == null)\n                {\n                    _logger.LogError(\"The record no longer exists in the database, The record has been deleted by another user.\");\n                    throw;\n                }\n\n                // Refresh the original values to bypass next concurrency check\n                entry.OriginalValues.SetValues(databaseValues);\n            }\n\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n    }\n\n    public IReadOnlyList<IDomainEvent> GetDomainEvents()\n    {\n        var domainEntities = ChangeTracker\n            .Entries<IAggregate>()\n            .Where(x => x.Entity.DomainEvents.Any())\n            .Select(x => x.Entity)\n            .ToList();\n\n        var domainEvents = domainEntities\n            .SelectMany(x => x.DomainEvents)\n            .ToImmutableList();\n\n        domainEntities.ForEach(entity => entity.ClearDomainEvents());\n\n        return domainEvents.ToImmutableList();\n    }\n\n    // ref: https://www.meziantou.net/entity-framework-core-generate-tracking-columns.htm\n    // ref: https://www.meziantou.net/entity-framework-core-soft-delete-using-query-filters.htm\n    private void OnBeforeSaving()\n    {\n        try\n        {\n            foreach (var entry in ChangeTracker.Entries<IAggregate>())\n            {\n                var isAuditable = entry.Entity.GetType().IsAssignableTo(typeof(IAggregate));\n                var userId = _currentUserProvider?.GetCurrentUserId() ?? 0;\n\n                if (isAuditable)\n                {\n                    switch (entry.State)\n                    {\n                        case EntityState.Added:\n                            entry.Entity.CreatedBy = userId;\n                            entry.Entity.CreatedAt = DateTime.Now;\n                            break;\n\n                        case EntityState.Modified:\n                            entry.Entity.LastModifiedBy = userId;\n                            entry.Entity.LastModified = DateTime.Now;\n                            entry.Entity.Version++;\n                            break;\n\n                        case EntityState.Deleted:\n                            entry.State = EntityState.Modified;\n                            entry.Entity.LastModifiedBy = userId;\n                            entry.Entity.LastModified = DateTime.Now;\n                            entry.Entity.IsDeleted = true;\n                            entry.Entity.Version++;\n                            break;\n                    }\n                }\n            }\n        }\n        catch (System.Exception ex)\n        {\n            throw new System.Exception(\"try for find IAggregate\", ex);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/DesignTimeDbContextFactoryBase.cs",
    "content": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Design;\nusing Microsoft.Extensions.Configuration;\n\nnamespace BuildingBlocks.EFCore\n{\n    public abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDbContextFactory<TContext> where TContext : DbContext\n    {\n        public TContext CreateDbContext(string[] args)\n        {\n            return Create(Directory.GetCurrentDirectory(), Environment.GetEnvironmentVariable(\"ASPNETCORE_ENVIRONMENT\"));\n        }\n\n        protected abstract TContext CreateNewInstance(DbContextOptions<TContext> options);\n\n        public TContext Create()\n        {\n            var environmentName = Environment.GetEnvironmentVariable(\"ASPNETCORE_ENVIRONMENT\");\n            var basePath = AppContext.BaseDirectory;\n            return Create(basePath, environmentName);\n        }\n\n        private TContext Create(string basePath, string environmentName)\n        {\n            var builder = new ConfigurationBuilder()\n                .SetBasePath(basePath)\n                .AddJsonFile(\"appsettings.json\")\n                .AddJsonFile($\"appsettings.{environmentName}.json\", true)\n                .AddEnvironmentVariables();\n\n            var config = builder.Build();\n\n            var connstr = config.GetConnectionString(\"DefaultConnection\");\n\n            if (string.IsNullOrWhiteSpace(connstr))\n            {\n                throw new InvalidOperationException(\n                    \"Could not find a connection string named 'Default'.\");\n            }\n            return Create(connstr);\n        }\n\n        private TContext Create(string connectionString)\n        {\n            if (string.IsNullOrEmpty(connectionString))\n                throw new ArgumentException(\n             $\"{nameof(connectionString)} is null or empty.\",\n             nameof(connectionString));\n\n            var optionsBuilder = new DbContextOptionsBuilder<TContext>();\n\n            Console.WriteLine(\"DesignTimeDbContextFactory.Create(string): Connection string: {0}\", connectionString);\n\n            optionsBuilder.UseSqlServer(connectionString);\n\n            var options = optionsBuilder.Options;\n            return CreateNewInstance(options);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/EfTxBehavior.cs",
    "content": "using System.Text.Json;\nusing System.Transactions;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.Polly;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EFCore;\n\n\npublic class EfTxBehavior<TRequest, TResponse>(\n    ILogger<EfTxBehavior<TRequest, TResponse>> logger,\n    IDbContext dbContextBase,\n    IPersistMessageDbContext persistMessageDbContext,\n    IEventDispatcher eventDispatcher\n)\n    : IPipelineBehavior<TRequest, TResponse>\nwhere TRequest : notnull, IRequest<TResponse>\nwhere TResponse : notnull\n{\n    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,\n                                        CancellationToken cancellationToken)\n    {\n        logger.LogInformation(\n            \"{Prefix} Handled command {MediatrRequest}\",\n            nameof(EfTxBehavior<TRequest, TResponse>),\n            typeof(TRequest).FullName);\n\n        logger.LogDebug(\n            \"{Prefix} Handled command {MediatrRequest} with content {RequestContent}\",\n            nameof(EfTxBehavior<TRequest, TResponse>),\n            typeof(TRequest).FullName,\n            JsonSerializer.Serialize(request));\n\n        logger.LogInformation(\n            \"{Prefix} Open the transaction for {MediatrRequest}\",\n            nameof(EfTxBehavior<TRequest, TResponse>),\n            typeof(TRequest).FullName);\n\n        //ref: https://learn.microsoft.com/en-us/ef/core/saving/transactions#using-systemtransactions\n        using var scope = new TransactionScope(TransactionScopeOption.Required,\n            new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },\n            TransactionScopeAsyncFlowOption.Enabled);\n\n        var response = await next();\n\n        logger.LogInformation(\n            \"{Prefix} Executed the {MediatrRequest} request\",\n            nameof(EfTxBehavior<TRequest, TResponse>),\n            typeof(TRequest).FullName);\n\n        while (true)\n        {\n            var domainEvents = dbContextBase.GetDomainEvents();\n\n            if (domainEvents is null || !domainEvents.Any())\n            {\n                return response;\n            }\n\n            await eventDispatcher.SendAsync(domainEvents.ToArray(), typeof(TRequest), cancellationToken);\n\n            // Save data to database with some retry policy in distributed transaction\n            await dbContextBase.RetryOnFailure(async () =>\n            {\n                await dbContextBase.SaveChangesAsync(cancellationToken);\n            });\n\n            // Save data to database with some retry policy in distributed transaction\n            await persistMessageDbContext.RetryOnFailure(async () =>\n            {\n                await persistMessageDbContext.SaveChangesAsync(cancellationToken);\n            });\n\n            scope.Complete();\n\n            return response;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/Extensions.cs",
    "content": "using System.Linq.Expressions;\nusing BuildingBlocks.Core.Model;\nusing BuildingBlocks.Web;\nusing Humanizer;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EFCore;\n\npublic static class Extensions\n{\n    public static IServiceCollection AddCustomDbContext<TContext>(this WebApplicationBuilder builder, string? connectionName = \"\")\n    where TContext : DbContext, IDbContext\n    {\n        AppContext.SetSwitch(\"Npgsql.EnableLegacyTimestampBehavior\", true);\n\n        builder.Services.AddValidateOptions<PostgresOptions>();\n\n        builder.Services.AddDbContext<TContext>(\n            (sp, options) =>\n            {\n                var aspireConnectionString = builder.Configuration.GetConnectionString(connectionName.Kebaberize());\n                var connectionString = aspireConnectionString ?? sp.GetRequiredService<PostgresOptions>().ConnectionString;\n\n                ArgumentException.ThrowIfNullOrEmpty(connectionString);\n\n                options.UseNpgsql(\n                        connectionString,\n                        dbOptions =>\n                        {\n                            dbOptions.MigrationsAssembly(typeof(TContext).Assembly.GetName().Name);\n                        })\n                    .UseSnakeCaseNamingConvention();\n\n                // Suppress warnings for pending model changes\n                options.ConfigureWarnings(\n                    w => w.Ignore(RelationalEventId.PendingModelChangesWarning));\n            });\n\n        builder.Services.AddScoped<ISeedManager, SeedManager>();\n        builder.Services.AddScoped<IDbContext>(sp => sp.GetRequiredService<TContext>());\n\n        return builder.Services;\n    }\n\n\n    public static IApplicationBuilder UseMigration<TContext>(this IApplicationBuilder app)\n    where TContext : DbContext, IDbContext\n    {\n        MigrateAsync<TContext>(app.ApplicationServices).GetAwaiter().GetResult();\n\n        SeedAsync(app.ApplicationServices).GetAwaiter().GetResult();\n\n        return app;\n    }\n\n    // ref: https://github.com/pdevito3/MessageBusTestingInMemHarness/blob/main/RecipeManagement/src/RecipeManagement/Databases/RecipesDbContext.cs\n    public static void FilterSoftDeletedProperties(this ModelBuilder modelBuilder)\n    {\n        Expression<Func<IAggregate, bool>> filterExpr = e => !e.IsDeleted;\n\n        foreach (var mutableEntityType in modelBuilder.Model.GetEntityTypes()\n                     .Where(m => m.ClrType.IsAssignableTo(typeof(IEntity))))\n        {\n            // modify expression to handle correct child type\n            var parameter = Expression.Parameter(mutableEntityType.ClrType);\n\n            var body = ReplacingExpressionVisitor\n                .Replace(filterExpr.Parameters.First(), parameter, filterExpr.Body);\n\n            var lambdaExpression = Expression.Lambda(body, parameter);\n\n            // set filter\n            mutableEntityType.SetQueryFilter(lambdaExpression);\n        }\n    }\n\n    // ref: https://andrewlock.net/customising-asp-net-core-identity-ef-core-naming-conventions-for-postgresql/\n    public static void ToSnakeCaseTables(this ModelBuilder modelBuilder)\n    {\n        foreach (var entity in modelBuilder.Model.GetEntityTypes())\n        {\n            // Replace table names\n            entity.SetTableName(entity.GetTableName()?.Underscore());\n\n            var tableObjectIdentifier =\n                StoreObjectIdentifier.Table(\n                    entity.GetTableName()?.Underscore()!,\n                    entity.GetSchema());\n\n            // Replace column names\n            foreach (var property in entity.GetProperties())\n            {\n                property.SetColumnName(property.GetColumnName(tableObjectIdentifier)?.Underscore());\n            }\n\n            foreach (var key in entity.GetKeys())\n            {\n                key.SetName(key.GetName()?.Underscore());\n            }\n\n            foreach (var key in entity.GetForeignKeys())\n            {\n                key.SetConstraintName(key.GetConstraintName()?.Underscore());\n            }\n        }\n    }\n\n    private static async Task MigrateAsync<TContext>(IServiceProvider serviceProvider)\n    where TContext : DbContext, IDbContext\n    {\n        await using var scope = serviceProvider.CreateAsyncScope();\n        var context = scope.ServiceProvider.GetRequiredService<TContext>();\n        var logger = scope.ServiceProvider.GetRequiredService<ILogger<TContext>>();\n\n        var pendingMigrations = await context.Database.GetPendingMigrationsAsync();\n\n        if (pendingMigrations.Any())\n        {\n            logger.LogInformation(\"Applying {Count} pending migrations...\", pendingMigrations.Count());\n\n            await context.Database.MigrateAsync();\n            logger.LogInformation(\"Migrations applied successfully.\");\n        }\n    }\n\n    private static async Task SeedAsync(IServiceProvider serviceProvider)\n    {\n        await using var scope = serviceProvider.CreateAsyncScope();\n\n        var seedersManager = scope.ServiceProvider.GetRequiredService<ISeedManager>();\n\n        await seedersManager.ExecuteSeedAsync();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/IDataSeeder.cs",
    "content": "namespace BuildingBlocks.EFCore\n{\n    public interface IDataSeeder\n    {\n        Task SeedAllAsync();\n    }\n\n    public interface ITestDataSeeder\n    {\n        Task SeedAllAsync();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/IDbContext.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace BuildingBlocks.EFCore;\n\nusing Microsoft.EntityFrameworkCore.Storage;\n\npublic interface IDbContext\n{\n    DbSet<TEntity> Set<TEntity>() where TEntity : class;\n    IReadOnlyList<IDomainEvent> GetDomainEvents();\n    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);\n    Task BeginTransactionAsync(CancellationToken cancellationToken = default);\n    Task CommitTransactionAsync(CancellationToken cancellationToken = default);\n    Task RollbackTransactionAsync(CancellationToken cancellationToken = default);\n    IExecutionStrategy CreateExecutionStrategy();\n    Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/ISeedManager.cs",
    "content": "namespace BuildingBlocks.EFCore;\n\npublic interface ISeedManager\n{\n    Task ExecuteSeedAsync();\n    Task ExecuteTestSeedAsync();\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/PostgresOptions.cs",
    "content": "namespace BuildingBlocks.EFCore;\n\npublic class PostgresOptions\n{\n    public string ConnectionString { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/EFCore/SeedManagers.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EFCore;\n\npublic class SeedManager(\n    ILogger<SeedManager> logger,\n    IWebHostEnvironment env,\n    IServiceProvider serviceProvider\n) : ISeedManager\n{\n    public async Task ExecuteSeedAsync()\n    {\n        if (!env.IsEnvironment(\"test\"))\n        {\n            await using var scope = serviceProvider.CreateAsyncScope();\n            var dataSeeders = scope.ServiceProvider.GetServices<IDataSeeder>();\n\n            foreach (var seeder in dataSeeders)\n            {\n                logger.LogInformation(\"Seed {SeederName} is started.\", seeder.GetType().Name);\n                await seeder.SeedAllAsync();\n                logger.LogInformation(\"Seed {SeederName} is completed.\", seeder.GetType().Name);\n            }\n        }\n    }\n\n    public async Task ExecuteTestSeedAsync()\n    {\n        await using var scope = serviceProvider.CreateAsyncScope();\n        var testDataSeeders = scope.ServiceProvider.GetServices<ITestDataSeeder>();\n\n        foreach (var testSeeder in testDataSeeders)\n        {\n            logger.LogInformation(\"Seed {SeederName} is started.\", testSeeder.GetType().Name);\n            await testSeeder.SeedAllAsync();\n            logger.LogInformation(\"Seed {SeederName} is completed.\", testSeeder.GetType().Name);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/BackgroundWorkers/BackgroundWorker.cs",
    "content": "using Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EventStoreDB.BackgroundWorkers;\n\npublic class BackgroundWorker : BackgroundService\n{\n    private readonly ILogger<BackgroundWorker> logger;\n    private readonly Func<CancellationToken, Task> perform;\n\n    public BackgroundWorker(\n        ILogger<BackgroundWorker> logger,\n        Func<CancellationToken, Task> perform\n    )\n    {\n        this.logger = logger;\n        this.perform = perform;\n    }\n\n    protected override Task ExecuteAsync(CancellationToken stoppingToken) =>\n        Task.Run(async () =>\n        {\n            await Task.Yield();\n            logger.LogInformation(\"Background worker stopped\");\n            await perform(stoppingToken);\n            logger.LogInformation(\"Background worker stopped\");\n        }, stoppingToken);\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Config.cs",
    "content": "using System.Reflection;\nusing BuildingBlocks.EventStoreDB.BackgroundWorkers;\nusing BuildingBlocks.EventStoreDB.Projections;\nusing BuildingBlocks.EventStoreDB.Repository;\nusing BuildingBlocks.EventStoreDB.Subscriptions;\nusing EventStore.Client;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EventStoreDB;\n\nusing Web;\n\npublic class EventStoreOptions\n{\n    public string ConnectionString { get; set; } = default!;\n}\n\n\npublic record EventStoreDBOptions(\n    bool UseInternalCheckpointing = true\n);\n\npublic static class EventStoreDBConfigExtensions\n{\n    public static IServiceCollection AddEventStoreDB(this IServiceCollection services, IConfiguration configuration,\n        EventStoreDBOptions? options = null)\n    {\n\n        services\n            .AddSingleton(x =>\n            {\n                var aspireConnectionString = configuration.GetConnectionString(\"eventstore\");\n                var eventStoreOptions = services.GetOptions<EventStoreOptions>(nameof(EventStoreOptions));\n                return new EventStoreClient(EventStoreClientSettings.Create(aspireConnectionString ?? eventStoreOptions.ConnectionString));\n            })\n            .AddScoped(typeof(IEventStoreDBRepository<>), typeof(EventStoreDBRepository<>))\n            .AddTransient<EventStoreDBSubscriptionToAll, EventStoreDBSubscriptionToAll>();\n\n        if (options?.UseInternalCheckpointing != false)\n            services.AddTransient<ISubscriptionCheckpointRepository, EventStoreDBSubscriptionCheckpointRepository>();\n\n        return services;\n    }\n\n    public static IServiceCollection AddEventStoreDBSubscriptionToAll(\n        this IServiceCollection services,\n        EventStoreDBSubscriptionToAllOptions? subscriptionOptions = null,\n        bool checkpointToEventStoreDB = true)\n    {\n        if (checkpointToEventStoreDB)\n            services.AddTransient<ISubscriptionCheckpointRepository, EventStoreDBSubscriptionCheckpointRepository>();\n\n        return services.AddHostedService(serviceProvider =>\n            {\n                var logger =\n                    serviceProvider.GetRequiredService<ILogger<BackgroundWorker>>();\n\n                var eventStoreDBSubscriptionToAll =\n                    serviceProvider.GetRequiredService<EventStoreDBSubscriptionToAll>();\n\n                return new BackgroundWorker(\n                    logger,\n                    ct =>\n                        eventStoreDBSubscriptionToAll.SubscribeToAll(\n                            subscriptionOptions ?? new EventStoreDBSubscriptionToAllOptions(),\n                            ct\n                        )\n                );\n            }\n        );\n    }\n\n    public static IServiceCollection AddProjections(this IServiceCollection services,\n        params Assembly[] assembliesToScan)\n    {\n        services.AddSingleton<IProjectionPublisher, ProjectionPublisher>();\n\n        RegisterProjections(services, assembliesToScan!);\n\n        return services;\n    }\n\n    private static void RegisterProjections(IServiceCollection services, Assembly[] assembliesToScan)\n    {\n        services.Scan(scan => scan\n            .FromAssemblies(assembliesToScan)\n            .AddClasses(classes => classes.AssignableTo<IProjectionProcessor>()) // Filter classes\n            .AsImplementedInterfaces()\n            .WithTransientLifetime());\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/AggregateEventSourcing.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\n\nnamespace BuildingBlocks.EventStoreDB.Events\n{\n    public abstract record AggregateEventSourcing<TId> : Entity<TId>, IAggregateEventSourcing<TId>\n    {\n        private readonly List<IDomainEvent> _domainEvents = new();\n        public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();\n\n        public void AddDomainEvent(IDomainEvent domainEvent)\n        {\n            _domainEvents.Add(domainEvent);\n        }\n\n        public IDomainEvent[] ClearDomainEvents()\n        {\n            var dequeuedEvents = _domainEvents.ToArray();\n\n            _domainEvents.Clear();\n\n            return dequeuedEvents;\n        }\n\n        public virtual void When(object @event) { }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/AggregateStreamExtensions.cs",
    "content": "using BuildingBlocks.EventStoreDB.Serialization;\nusing EventStore.Client;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic static class AggregateStreamExtensions\n{\n    public static async Task<T?> AggregateStream<T>(\n        this EventStoreClient eventStore,\n        Guid id,\n        CancellationToken cancellationToken,\n        ulong? fromVersion = null\n    ) where T : class, IProjection\n    {\n        var readResult = eventStore.ReadStreamAsync(\n            Direction.Forwards,\n            StreamNameMapper.ToStreamId<T>(id),\n            fromVersion ?? StreamPosition.Start,\n            cancellationToken: cancellationToken\n        );\n\n        // TODO: consider adding extension method for the aggregation and deserialization\n        var aggregate = (T)Activator.CreateInstance(typeof(T), true)!;\n\n        if (await readResult.ReadState == ReadState.StreamNotFound)\n        {\n            return null;\n        }\n\n        await foreach (var @event in readResult)\n        {\n            var eventData = @event.Deserialize();\n\n            aggregate.When(eventData!);\n        }\n\n        return aggregate;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/EventTypeMapper.cs",
    "content": "using System.Collections.Concurrent;\nusing BuildingBlocks.Utils;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic class EventTypeMapper\n{\n    private static readonly EventTypeMapper Instance = new();\n\n    private readonly ConcurrentDictionary<string, Type?> typeMap = new();\n    private readonly ConcurrentDictionary<Type, string> typeNameMap = new();\n\n    public static void AddCustomMap<T>(string mappedEventTypeName) => AddCustomMap(typeof(T), mappedEventTypeName);\n\n    public static void AddCustomMap(Type eventType, string mappedEventTypeName)\n    {\n        Instance.typeNameMap.AddOrUpdate(eventType, mappedEventTypeName, (_, _) => mappedEventTypeName);\n        Instance.typeMap.AddOrUpdate(mappedEventTypeName, eventType, (_, _) => eventType);\n    }\n\n    public static string ToName<TEventType>() => ToName(typeof(TEventType));\n\n    public static string ToName(Type eventType) => Instance.typeNameMap.GetOrAdd(eventType, _ =>\n    {\n        var eventTypeName = eventType.FullName!.Replace(\".\", \"_\", StringComparison.CurrentCulture);\n\n        Instance.typeMap.AddOrUpdate(eventTypeName, eventType, (_, _) => eventType);\n\n        return eventTypeName;\n    });\n\n    public static Type? ToType(string eventTypeName) => Instance.typeMap.GetOrAdd(eventTypeName, _ =>\n    {\n        var type = TypeProvider.GetFirstMatchingTypeFromCurrentDomainAssembly(eventTypeName.Replace(\"_\", \".\", StringComparison.CurrentCulture));\n\n        if (type == null)\n            return null;\n\n        Instance.typeNameMap.AddOrUpdate(type, eventTypeName, (_, _) => eventTypeName);\n\n        return type;\n    });\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/IAggregateEventSourcing.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\n\nnamespace BuildingBlocks.EventStoreDB.Events\n{\n    public interface IAggregateEventSourcing : IProjection, IEntity\n    {\n        IReadOnlyList<IDomainEvent> DomainEvents { get; }\n        IDomainEvent[] ClearDomainEvents();\n    }\n\n    public interface IAggregateEventSourcing<T> : IAggregateEventSourcing, IEntity<T>\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/IEventHandler.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing MediatR;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic interface IEventHandler<in TEvent> : INotificationHandler<TEvent>\n    where TEvent : IEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/IExternalEvent.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic interface IExternalEvent : IEvent\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/IProjection.cs",
    "content": "namespace BuildingBlocks.EventStoreDB.Events;\n\npublic interface IProjection\n{\n    void When(object @event);\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/StreamEvent.cs",
    "content": "using BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic record EventMetadata(\n    ulong StreamRevision,\n    ulong LogPosition\n);\n\npublic class StreamEvent : IEvent\n{\n    public object Data { get; }\n    public EventMetadata Metadata { get; }\n\n    public StreamEvent(object data, EventMetadata metadata)\n    {\n        Data = data;\n        Metadata = metadata;\n    }\n}\n\npublic class StreamEvent<T> : StreamEvent where T : notnull\n{\n    public new T Data => (T)base.Data;\n\n    public StreamEvent(T data, EventMetadata metadata) : base(data, metadata)\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/StreamEventExtensions.cs",
    "content": "using System.Diagnostics.Eventing.Reader;\nusing BuildingBlocks.EventStoreDB.Serialization;\nusing EventStore.Client;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic static class StreamEventExtensions\n{\n    public static StreamEvent? ToStreamEvent(this ResolvedEvent resolvedEvent)\n    {\n        var eventData = resolvedEvent.Deserialize();\n        if (eventData == null)\n            return null;\n\n        var metaData = new EventMetadata(resolvedEvent.Event.EventNumber.ToUInt64(), resolvedEvent.Event.Position.CommitPosition);\n        var type = typeof(StreamEvent<>).MakeGenericType(eventData.GetType());\n        return (StreamEvent)Activator.CreateInstance(type, eventData, metaData)!;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Events/StreamNameMapper.cs",
    "content": "using System.Collections.Concurrent;\n\nnamespace BuildingBlocks.EventStoreDB.Events;\n\npublic class StreamNameMapper\n{\n    private static readonly StreamNameMapper Instance = new();\n\n    private readonly ConcurrentDictionary<Type, string> TypeNameMap = new();\n\n    public static void AddCustomMap<TStream>(string mappedStreamName) =>\n        AddCustomMap(typeof(TStream), mappedStreamName);\n\n    public static void AddCustomMap(Type streamType, string mappedStreamName)\n    {\n        Instance.TypeNameMap.AddOrUpdate(streamType, mappedStreamName, (_, _) => mappedStreamName);\n    }\n    public static string ToStreamId<TStream>(object aggregateId, object? tenantId = null) =>\n        ToStreamId(typeof(TStream), aggregateId);\n\n    public static string ToStreamId(Type streamType, object aggregateId, object? tenantId = null)\n    {\n        var tenantPrefix = tenantId != null ? $\"{tenantId}_\" : \"\";\n\n        return $\"{tenantPrefix}{streamType.Name}-{aggregateId}\";\n    }\n\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Extensions.cs",
    "content": "using System.Reflection;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.EventStoreDB;\n\nusing Web;\n\npublic static class Extensions\n{\n    // ref: https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventStoreDB/ECommerce\n    public static IServiceCollection AddEventStore(\n        this IServiceCollection services,\n        IConfiguration configuration,\n        params Assembly[] assemblies\n    )\n    {\n        services.AddValidateOptions<EventStoreOptions>();\n\n        var assembliesToScan = assemblies.Length > 0 ? assemblies : new[] { Assembly.GetEntryAssembly()! };\n\n        return services\n            .AddEventStoreDB(configuration)\n            .AddProjections(assembliesToScan);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Projections/IProjectionProcessor.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing MediatR;\n\nnamespace BuildingBlocks.EventStoreDB.Projections;\n\npublic interface IProjectionProcessor\n{\n    Task ProcessEventAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default)\n        where T : INotification;\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Projections/IProjectionPublisher.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing MediatR;\n\nnamespace BuildingBlocks.EventStoreDB.Projections;\n\npublic interface IProjectionPublisher\n{\n    Task PublishAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default)\n        where T : INotification;\n\n    Task PublishAsync(StreamEvent streamEvent, CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Projections/ProjectionPublisher.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.EventStoreDB.Projections;\n\npublic class ProjectionPublisher : IProjectionPublisher\n{\n    private readonly IServiceProvider _serviceProvider;\n\n    public ProjectionPublisher(IServiceProvider serviceProvider)\n    {\n        _serviceProvider = serviceProvider;\n    }\n\n    public async Task PublishAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default)\n        where T : INotification\n    {\n        using var scope = _serviceProvider.CreateScope();\n        var projectionsProcessors = scope.ServiceProvider.GetRequiredService<IEnumerable<IProjectionProcessor>>();\n        foreach (var projectionProcessor in projectionsProcessors)\n        {\n            await projectionProcessor.ProcessEventAsync(streamEvent, cancellationToken);\n        }\n    }\n\n    public Task PublishAsync(StreamEvent streamEvent, CancellationToken cancellationToken = default)\n    {\n        var streamData = streamEvent.Data.GetType();\n\n        var method = typeof(IProjectionPublisher)\n            .GetMethods()\n            .Single(m => m.Name == nameof(PublishAsync) && m.GetGenericArguments().Any())\n            .MakeGenericMethod(streamData);\n\n        return (Task)method\n            .Invoke(this, new object[] { streamEvent, cancellationToken })!;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Repository/EventStoreDBRepository.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing BuildingBlocks.EventStoreDB.Serialization;\nusing EventStore.Client;\n\nnamespace BuildingBlocks.EventStoreDB.Repository;\n\npublic interface IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<Guid>\n{\n    Task<T?> Find(Guid id, CancellationToken cancellationToken);\n    Task<ulong> Add(T aggregate, CancellationToken cancellationToken);\n\n    Task<ulong> Update(T aggregate, long? expectedRevision = null,\n        CancellationToken cancellationToken = default);\n\n    Task<ulong> Delete(T aggregate, long? expectedRevision = null, CancellationToken cancellationToken = default);\n}\n\npublic class EventStoreDBRepository<T> : IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<Guid>\n{\n    private static readonly long _currentUserId;\n    private readonly EventStoreClient eventStore;\n\n    public EventStoreDBRepository(EventStoreClient eventStore)\n    {\n        this.eventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));\n    }\n\n    public Task<T?> Find(Guid id, CancellationToken cancellationToken)\n    {\n        return eventStore.AggregateStream<T>(\n            id,\n            cancellationToken\n        );\n    }\n\n    public async Task<ulong> Add(T aggregate, CancellationToken cancellationToken = default)\n    {\n        var result = await eventStore.AppendToStreamAsync(\n            StreamNameMapper.ToStreamId<T>(aggregate.Id),\n            StreamState.NoStream,\n            GetEventsToStore(aggregate),\n            cancellationToken: cancellationToken\n        );\n        return result.NextExpectedStreamRevision;\n    }\n\n    public async Task<ulong> Update(T aggregate, long? expectedRevision = null,\n        CancellationToken cancellationToken = default)\n    {\n        var nextVersion = expectedRevision ?? aggregate.Version;\n\n        var result = await eventStore.AppendToStreamAsync(\n            StreamNameMapper.ToStreamId<T>(aggregate.Id),\n            (ulong)nextVersion,\n            GetEventsToStore(aggregate),\n            cancellationToken: cancellationToken\n        );\n        return result.NextExpectedStreamRevision;\n    }\n\n    public Task<ulong> Delete(T aggregate, long? expectedRevision = null,\n        CancellationToken cancellationToken = default)\n    {\n        return Update(aggregate, expectedRevision, cancellationToken);\n    }\n\n    private static IEnumerable<EventData> GetEventsToStore(T aggregate)\n    {\n        var events = aggregate.ClearDomainEvents();\n\n        return events\n            .Select(EventStoreDBSerializer.ToJsonEventData);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Repository/RepositoryExtensions.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing BuildingBlocks.Exception;\n\nnamespace BuildingBlocks.EventStoreDB.Repository;\n\npublic static class RepositoryExtensions\n{\n    public static async Task<T> Get<T>(\n        this IEventStoreDBRepository<T> repository,\n        Guid id,\n        CancellationToken cancellationToken\n    ) where T : class, IAggregateEventSourcing<Guid>\n    {\n        var entity = await repository.Find(id, cancellationToken);\n\n        return entity ?? throw AggregateNotFoundException.For<T>(id);\n    }\n\n    public static async Task<ulong> GetAndUpdate<T>(\n        this IEventStoreDBRepository<T> repository,\n        Guid id,\n        Action<T> action,\n        long? expectedVersion = null,\n        CancellationToken cancellationToken = default\n    ) where T : class, IAggregateEventSourcing<Guid>\n    {\n        var entity = await repository.Get(id, cancellationToken);\n\n        action(entity);\n\n        return await repository.Update(entity, expectedVersion, cancellationToken);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Serialization/EventStoreDBSerializer.cs",
    "content": "using System.Text;\nusing BuildingBlocks.EventStoreDB.Events;\nusing EventStore.Client;\nusing Newtonsoft.Json;\n\nnamespace BuildingBlocks.EventStoreDB.Serialization;\n\npublic static class EventStoreDBSerializer\n{\n    private static readonly JsonSerializerSettings SerializerSettings =\n        new JsonSerializerSettings().WithNonDefaultConstructorContractResolver();\n\n    public static T? Deserialize<T>(this ResolvedEvent resolvedEvent) where T : class =>\n        Deserialize(resolvedEvent) as T;\n\n    public static object? Deserialize(this ResolvedEvent resolvedEvent)\n    {\n        // get type\n        var eventType = EventTypeMapper.ToType(resolvedEvent.Event.EventType);\n\n        if (eventType == null)\n            return null;\n\n        // deserialize event\n        return JsonConvert.DeserializeObject(\n            Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span),\n            eventType,\n            SerializerSettings\n        )!;\n    }\n\n    public static EventData ToJsonEventData(this object @event) =>\n        new(\n            Uuid.NewUuid(),\n            EventTypeMapper.ToName(@event.GetType()),\n            Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(@event)),\n            Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { }))\n        );\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Serialization/JsonObjectContractProvider.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Reflection;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Serialization;\n\nnamespace BuildingBlocks.EventStoreDB.Serialization;\n\npublic static class JsonObjectContractProvider\n{\n    private static readonly Type ConstructorAttributeType = typeof(JsonConstructorAttribute);\n    private static readonly ConcurrentDictionary<string, JsonObjectContract> Constructors = new();\n\n    public static JsonObjectContract UsingNonDefaultConstructor(\n        JsonObjectContract contract,\n        Type objectType,\n        Func<ConstructorInfo, JsonPropertyCollection, IList<JsonProperty>> createConstructorParameters) =>\n        Constructors.GetOrAdd(objectType.AssemblyQualifiedName!, _ =>\n        {\n            var nonDefaultConstructor = GetNonDefaultConstructor(objectType);\n\n            if (nonDefaultConstructor == null)\n                return contract;\n\n            contract.OverrideCreator = GetObjectConstructor(nonDefaultConstructor);\n            contract.CreatorParameters.Clear();\n            foreach (var constructorParameter in\n                     createConstructorParameters(nonDefaultConstructor, contract.Properties))\n            {\n                contract.CreatorParameters.Add(constructorParameter);\n            }\n\n            return contract;\n        });\n\n    private static ObjectConstructor<object> GetObjectConstructor(MethodBase method)\n    {\n        var c = method as ConstructorInfo;\n\n        if (c == null)\n            return a => method.Invoke(null, a)!;\n\n        if (!c.GetParameters().Any())\n            return _ => c.Invoke(Array.Empty<object?>());\n\n        return a => c.Invoke(a);\n    }\n\n    private static ConstructorInfo? GetNonDefaultConstructor(Type objectType)\n    {\n        // Use default contract for non-object types.\n        if (objectType.IsPrimitive || objectType.IsEnum)\n            return null;\n\n        return GetAttributeConstructor(objectType)\n               ?? GetTheMostSpecificConstructor(objectType);\n    }\n\n    private static ConstructorInfo? GetAttributeConstructor(Type objectType)\n    {\n        // Use default contract for non-object types.\n        if (objectType.IsPrimitive || objectType.IsEnum)\n            return null;\n\n        var constructors = objectType\n            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)\n            .Where(c => c.GetCustomAttributes().Any(a => a.GetType() == ConstructorAttributeType)).ToList();\n\n        return constructors.Count switch\n        {\n            1 => constructors[0],\n            > 1 => throw new JsonException($\"Multiple constructors with a {ConstructorAttributeType.Name}.\"),\n            _ => null\n        };\n    }\n\n    private static ConstructorInfo? GetTheMostSpecificConstructor(Type objectType) =>\n        objectType\n            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)\n            .OrderByDescending(e => e.GetParameters().Length)\n            .FirstOrDefault();\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Serialization/NonDefaultConstructorContractResolver.cs",
    "content": "using Newtonsoft.Json.Serialization;\n\nnamespace BuildingBlocks.EventStoreDB.Serialization;\n\npublic class NonDefaultConstructorContractResolver : DefaultContractResolver\n{\n    protected override JsonObjectContract CreateObjectContract(Type objectType)\n    {\n        return JsonObjectContractProvider.UsingNonDefaultConstructor(\n            base.CreateObjectContract(objectType),\n            objectType,\n            base.CreateConstructorParameters\n        );\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Serialization/SerializationExtensions.cs",
    "content": "using System.Text;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Converters;\n\nnamespace BuildingBlocks.EventStoreDB.Serialization;\n\npublic static class SerializationExtensions\n{\n    public static JsonSerializerSettings WithDefaults(this JsonSerializerSettings settings)\n    {\n        settings.WithNonDefaultConstructorContractResolver()\n            .Converters.Add(new StringEnumConverter());\n\n        return settings;\n    }\n\n    public static JsonSerializerSettings WithNonDefaultConstructorContractResolver(this JsonSerializerSettings settings)\n    {\n        settings.ContractResolver = new NonDefaultConstructorContractResolver();\n        return settings;\n    }\n\n    /// <summary>\n    /// Deserialize object from json with JsonNet\n    /// </summary>\n    /// <typeparam name=\"T\">Type of the deserialized object</typeparam>\n    /// <param name=\"json\">json string</param>\n    /// <returns>deserialized object</returns>\n    public static T FromJson<T>(this string json)\n    {\n        return JsonConvert.DeserializeObject<T>(json,\n            new JsonSerializerSettings().WithNonDefaultConstructorContractResolver())!;\n    }\n\n\n    /// <summary>\n    /// Deserialize object from json with JsonNet\n    /// </summary>\n    /// <typeparam name=\"T\">Type of the deserialized object</typeparam>\n    /// <param name=\"json\">json string</param>\n    /// <param name=\"type\">object type</param>\n    /// <returns>deserialized object</returns>\n    public static object FromJson(this string json, Type type)\n    {\n        return JsonConvert.DeserializeObject(json, type,\n            new JsonSerializerSettings().WithNonDefaultConstructorContractResolver())!;\n    }\n\n    /// <summary>\n    /// Serialize object to json with JsonNet\n    /// </summary>\n    /// <param name=\"obj\">object to serialize</param>\n    /// <returns>json string</returns>\n    public static string ToJson(this object obj)\n    {\n        return JsonConvert.SerializeObject(obj);\n    }\n\n    /// <summary>\n    /// Serialize object to json with JsonNet\n    /// </summary>\n    /// <param name=\"obj\">object to serialize</param>\n    /// <returns>json string</returns>\n    public static StringContent ToJsonStringContent(this object obj)\n    {\n        return new StringContent(obj.ToJson(), Encoding.UTF8, \"application/json\");\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing BuildingBlocks.EventStoreDB.Events;\nusing BuildingBlocks.EventStoreDB.Serialization;\nusing EventStore.Client;\n\nnamespace BuildingBlocks.EventStoreDB.Subscriptions;\n\npublic record CheckpointStored(string SubscriptionId, ulong? Position, DateTime CheckpointedAt) : IEvent;\n\npublic class EventStoreDBSubscriptionCheckpointRepository : ISubscriptionCheckpointRepository\n{\n    private readonly EventStoreClient eventStoreClient;\n\n    public EventStoreDBSubscriptionCheckpointRepository(\n        EventStoreClient eventStoreClient)\n    {\n        this.eventStoreClient = eventStoreClient ?? throw new ArgumentNullException(nameof(eventStoreClient));\n    }\n\n    public async ValueTask<ulong?> Load(string subscriptionId, CancellationToken ct)\n    {\n        var streamName = GetCheckpointStreamName(subscriptionId);\n\n        var result = eventStoreClient.ReadStreamAsync(Direction.Backwards, streamName, StreamPosition.End, 1,\n            cancellationToken: ct);\n\n        if (await result.ReadState == ReadState.StreamNotFound)\n        {\n            return null;\n        }\n\n        ResolvedEvent? @event = await result.FirstOrDefaultAsync(ct);\n\n        return @event?.Deserialize<CheckpointStored>()?.Position;\n    }\n\n    public async ValueTask Store(string subscriptionId, ulong position, CancellationToken ct)\n    {\n        var @event = new CheckpointStored(subscriptionId, position, DateTime.UtcNow);\n        var eventToAppend = new[] { @event.ToJsonEventData() };\n        var streamName = GetCheckpointStreamName(subscriptionId);\n\n        try\n        {\n            // store new checkpoint expecting stream to exist\n            await eventStoreClient.AppendToStreamAsync(\n                streamName,\n                StreamState.StreamExists,\n                eventToAppend,\n                cancellationToken: ct\n            );\n        }\n        catch (WrongExpectedVersionException)\n        {\n            // WrongExpectedVersionException means that stream did not exist\n            // Set the checkpoint stream to have at most 1 event\n            // using stream metadata $maxCount property\n            await eventStoreClient.SetStreamMetadataAsync(\n                streamName,\n                StreamState.NoStream,\n                new StreamMetadata(1),\n                cancellationToken: ct\n            );\n\n            // append event again expecting stream to not exist\n            await eventStoreClient.AppendToStreamAsync(\n                streamName,\n                StreamState.NoStream,\n                eventToAppend,\n                cancellationToken: ct\n            );\n        }\n    }\n\n    private static string GetCheckpointStreamName(string subscriptionId) => $\"checkpoint_{subscriptionId}\";\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\nusing BuildingBlocks.EventStoreDB.Projections;\nusing BuildingBlocks.Utils;\nusing EventStore.Client;\nusing Grpc.Core;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.EventStoreDB.Subscriptions;\n\npublic class EventStoreDBSubscriptionToAllOptions\n{\n    public string SubscriptionId { get; set; } = \"default\";\n\n    public SubscriptionFilterOptions FilterOptions { get; set; } =\n        new(EventTypeFilter.ExcludeSystemEvents());\n\n    public Action<EventStoreClientOperationOptions>? ConfigureOperation { get; set; }\n    public UserCredentials? Credentials { get; set; }\n    public bool ResolveLinkTos { get; set; }\n    public bool IgnoreDeserializationErrors { get; set; } = true;\n}\n\npublic class EventStoreDBSubscriptionToAll\n{\n    private readonly IProjectionPublisher projectionPublisher;\n    private readonly EventStoreClient eventStoreClient;\n    private readonly IMediator _mediator;\n    private readonly ISubscriptionCheckpointRepository checkpointRepository;\n    private readonly ILogger<EventStoreDBSubscriptionToAll> logger;\n    private EventStoreDBSubscriptionToAllOptions subscriptionOptions = default!;\n    private string SubscriptionId => subscriptionOptions.SubscriptionId;\n    private readonly object resubscribeLock = new();\n    private CancellationToken cancellationToken;\n\n    public EventStoreDBSubscriptionToAll(\n        EventStoreClient eventStoreClient,\n        IMediator mediator,\n        IProjectionPublisher projectionPublisher,\n        ISubscriptionCheckpointRepository checkpointRepository,\n        ILogger<EventStoreDBSubscriptionToAll> logger\n    )\n    {\n        this.projectionPublisher = projectionPublisher;\n        this.eventStoreClient = eventStoreClient ?? throw new ArgumentNullException(nameof(eventStoreClient));\n        _mediator = mediator;\n        this.checkpointRepository =\n            checkpointRepository ?? throw new ArgumentNullException(nameof(checkpointRepository));\n        this.logger = logger ?? throw new ArgumentNullException(nameof(logger));\n    }\n\n    public async Task SubscribeToAll(EventStoreDBSubscriptionToAllOptions subscriptionOptions, CancellationToken ct)\n    {\n        // see: https://github.com/dotnet/runtime/issues/36063\n        await Task.Yield();\n\n        this.subscriptionOptions = subscriptionOptions;\n        cancellationToken = ct;\n\n        logger.LogInformation(\"Subscription to all '{SubscriptionId}'\", subscriptionOptions.SubscriptionId);\n\n        var checkpoint = await checkpointRepository.Load(SubscriptionId, ct);\n\n        await eventStoreClient.SubscribeToAllAsync(\n            checkpoint == null ? FromAll.Start : FromAll.After(new Position(checkpoint.Value, checkpoint.Value)),\n            HandleEvent,\n            subscriptionOptions.ResolveLinkTos,\n            HandleDrop,\n            subscriptionOptions.FilterOptions,\n            subscriptionOptions.Credentials,\n            ct\n        );\n\n        logger.LogInformation(\"Subscription to all '{SubscriptionId}' started\", SubscriptionId);\n    }\n\n    private async Task HandleEvent(StreamSubscription subscription, ResolvedEvent resolvedEvent,\n        CancellationToken ct)\n    {\n        try\n        {\n            if (IsEventWithEmptyData(resolvedEvent) || IsCheckpointEvent(resolvedEvent))\n                return;\n\n            var streamEvent = resolvedEvent.ToStreamEvent();\n\n            if (streamEvent == null)\n            {\n                // That can happen if we're sharing database between modules.\n                // If we're subscribing to all and not filtering out events from other modules,\n                // then we might get events that are from other module and we might not be able to deserialize them.\n                // In that case it's safe to ignore deserialization error.\n                // You may add more sophisticated logic checking if it should be ignored or not.\n                logger.LogWarning(\"Couldn't deserialize event with id: {EventId}\", resolvedEvent.Event.EventId);\n\n                if (!subscriptionOptions.IgnoreDeserializationErrors)\n                    throw new InvalidOperationException($\"Unable to deserialize event {resolvedEvent.Event.EventType} with id: {resolvedEvent.Event.EventId}\");\n                return;\n            }\n\n            // publish event to internal event bus\n            await _mediator.Publish(streamEvent, ct);\n\n            await projectionPublisher.PublishAsync(streamEvent, ct);\n\n            await checkpointRepository.Store(SubscriptionId, resolvedEvent.Event.Position.CommitPosition, ct);\n        }\n        catch (System.Exception e)\n        {\n            logger.LogError(\"Error consuming message: {ExceptionMessage}{ExceptionStackTrace}\", e.Message,\n                e.StackTrace);\n            // if you're fine with dropping some events instead of stopping subscription\n            // then you can add some logic if error should be ignored\n            throw;\n        }\n    }\n\n    private void HandleDrop(StreamSubscription _, SubscriptionDroppedReason reason, System.Exception? exception)\n    {\n        logger.LogError(\n            exception,\n            \"Subscription to all '{SubscriptionId}' dropped with '{Reason}'\",\n            SubscriptionId,\n            reason\n        );\n\n        if (exception is RpcException { StatusCode: StatusCode.Cancelled })\n            return;\n\n        Resubscribe();\n    }\n\n    private void Resubscribe()\n    {\n        // You may consider adding a max resubscribe count if you want to fail process\n        // instead of retrying until database is up\n        while (true)\n        {\n            var resubscribed = false;\n            try\n            {\n                Monitor.Enter(resubscribeLock);\n\n                // No synchronization context is needed to disable synchronization context.\n                // That enables running asynchronous method not causing deadlocks.\n                // As this is a background process then we don't need to have async context here.\n                using (NoSynchronizationContextScope.Enter())\n                {\n                    SubscribeToAll(subscriptionOptions, cancellationToken).Wait(cancellationToken);\n                }\n\n                resubscribed = true;\n            }\n            catch (System.Exception exception)\n            {\n                logger.LogWarning(exception,\n                    \"Failed to resubscribe to all '{SubscriptionId}' dropped with '{ExceptionMessage}{ExceptionStackTrace}'\",\n                    SubscriptionId, exception.Message, exception.StackTrace);\n            }\n            finally\n            {\n                Monitor.Exit(resubscribeLock);\n            }\n\n            if (resubscribed)\n                break;\n\n            // Sleep between reconnections to not flood the database or not kill the CPU with infinite loop\n            // Randomness added to reduce the chance of multiple subscriptions trying to reconnect at the same time\n            Thread.Sleep(1000 + new Random((int)DateTime.UtcNow.Ticks).Next(1000));\n        }\n    }\n\n    private bool IsEventWithEmptyData(ResolvedEvent resolvedEvent)\n    {\n        if (resolvedEvent.Event.Data.Length != 0)\n            return false;\n\n        logger.LogInformation(\"Event without data received\");\n        return true;\n    }\n\n    private bool IsCheckpointEvent(ResolvedEvent resolvedEvent)\n    {\n        if (resolvedEvent.Event.EventType != EventTypeMapper.ToName<CheckpointStored>())\n            return false;\n\n        logger.LogInformation(\"Checkpoint event - ignoring\");\n        return true;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Subscriptions/ISubscriptionCheckpointRepository.cs",
    "content": "namespace BuildingBlocks.EventStoreDB.Subscriptions;\n\npublic interface ISubscriptionCheckpointRepository\n{\n    ValueTask<ulong?> Load(string subscriptionId, CancellationToken ct);\n\n    ValueTask Store(string subscriptionId, ulong position, CancellationToken ct);\n}"
  },
  {
    "path": "src/BuildingBlocks/EventStoreDB/Subscriptions/InMemorySubscriptionCheckpointRepository.cs",
    "content": "using System.Collections.Concurrent;\n\nnamespace BuildingBlocks.EventStoreDB.Subscriptions;\n\npublic class InMemorySubscriptionCheckpointRepository : ISubscriptionCheckpointRepository\n{\n    private readonly ConcurrentDictionary<string, ulong> checkpoints = new();\n\n    public ValueTask<ulong?> Load(string subscriptionId, CancellationToken ct)\n    {\n        return new(checkpoints.TryGetValue(subscriptionId, out var checkpoint) ? checkpoint : null);\n    }\n\n    public ValueTask Store(string subscriptionId, ulong position, CancellationToken ct)\n    {\n        checkpoints.AddOrUpdate(subscriptionId, position, (_, _) => position);\n\n        return ValueTask.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/AggregateNotFoundException.cs",
    "content": "namespace BuildingBlocks.Exception;\n\npublic class AggregateNotFoundException : System.Exception\n{\n    public AggregateNotFoundException(string typeName, Guid id) : base($\"{typeName} with id '{id}' was not found\")\n    {\n    }\n\n    public static AggregateNotFoundException For<T>(Guid id)\n    {\n        return new AggregateNotFoundException(typeof(T).Name, id);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/AppException.cs",
    "content": "using System.Net;\n\nnamespace BuildingBlocks.Exception;\n\npublic class AppException : CustomException\n{\n    public AppException(string message, HttpStatusCode statusCode = HttpStatusCode.BadRequest, int? code = null) : base(message, statusCode, code: code)\n    {\n    }\n\n    public AppException(string message, System.Exception innerException, HttpStatusCode statusCode = HttpStatusCode.BadRequest, int? code = null) : base(message, innerException, statusCode, code)\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/BadRequestException.cs",
    "content": "using System;\nusing System.Net;\n\nnamespace BuildingBlocks.Exception\n{\n    public class BadRequestException : CustomException\n    {\n        public BadRequestException(string message, int? code = null) : base(message, HttpStatusCode.BadRequest, code: code)\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/ConflictException.cs",
    "content": "using System.Net;\n\nnamespace BuildingBlocks.Exception\n{\n    public class ConflictException : CustomException\n    {\n        public ConflictException(string message, int? code = null) : base(message, HttpStatusCode.Conflict, code: code)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/CustomException.cs",
    "content": "using System.Net;\n\nnamespace BuildingBlocks.Exception;\n\npublic class CustomException : System.Exception\n{\n    public CustomException(\n        string message,\n        HttpStatusCode statusCode = HttpStatusCode.InternalServerError,\n        int? code = null) : base(message)\n    {\n        StatusCode = statusCode;\n        Code = code;\n    }\n\n    public CustomException(\n        string message,\n        System.Exception innerException,\n        HttpStatusCode statusCode = HttpStatusCode.InternalServerError,\n        int? code = null) : base(message, innerException)\n    {\n        StatusCode = statusCode;\n        Code = code;\n    }\n\n    public CustomException(\n        HttpStatusCode statusCode = HttpStatusCode.InternalServerError,\n        int? code = null) : base()\n    {\n        StatusCode = statusCode;\n        Code = code;\n    }\n\n    public HttpStatusCode StatusCode { get; }\n\n    public int? Code { get; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/DomainException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace SmartCharging.Infrastructure.Exceptions\n{\n    public class DomainException : CustomException\n    {\n        public DomainException(string message, HttpStatusCode statusCode = HttpStatusCode.BadRequest) : base(message, statusCode)\n        {\n        }\n\n        public DomainException(string message, Exception innerException, HttpStatusCode statusCode = HttpStatusCode.BadRequest, int? code = null) : base(message, innerException, statusCode, code)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/GrpcExceptionInterceptor.cs",
    "content": "using Grpc.Core;\nusing Grpc.Core.Interceptors;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.Exception;\n\npublic class GrpcExceptionInterceptor : Interceptor\n{\n    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(\n        TRequest request,\n        ServerCallContext context,\n        UnaryServerMethod<TRequest, TResponse> continuation)\n    {\n        try\n        {\n            return await continuation(request, context);\n        }\n        catch (System.Exception exception)\n        {\n            throw new RpcException(new Status(StatusCode.Internal, exception.Message));\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/InternalServerException.cs",
    "content": "using System.Globalization;\nusing System.Net;\n\nnamespace BuildingBlocks.Exception\n{\n    public class InternalServerException : CustomException\n    {\n        public InternalServerException() : base() { }\n\n        public InternalServerException(string message, int? code) : base(message, code: code) { }\n\n        public InternalServerException(string message, int? code = null, params object[] args)\n            : base(message: String.Format(CultureInfo.CurrentCulture, message, args, HttpStatusCode.InternalServerError, code))\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/NotFoundException.cs",
    "content": "using System.Net;\n\nnamespace BuildingBlocks.Exception\n{\n    public class NotFoundException : CustomException\n    {\n        public NotFoundException(string message, int? code = null) : base(message, HttpStatusCode.NotFound, code: code)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/ProblemDetailsWithCode.cs",
    "content": "using System.Text.Json.Serialization;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace BuildingBlocks.Exception;\n\nusing ProblemDetails = Microsoft.AspNetCore.Mvc.ProblemDetails;\n\npublic class ProblemDetailsWithCode : ProblemDetails\n{\n    [JsonPropertyName(\"code\")]\n    public int? Code { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Exception/ValidationException.cs",
    "content": "using System.Net;\n\nnamespace BuildingBlocks.Exception\n{\n    public class ValidationException : CustomException\n    {\n        public ValidationException(string message, int? code = null) : base(message, HttpStatusCode.BadRequest, code: code)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/HealthCheck/Extensions.cs",
    "content": "using BuildingBlocks.EFCore;\nusing BuildingBlocks.EventStoreDB;\nusing BuildingBlocks.MassTransit;\nusing BuildingBlocks.Mongo;\nusing BuildingBlocks.Web;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.Hosting;\nusing MongoDB.Driver;\nusing RabbitMQ.Client;\n\nnamespace BuildingBlocks.HealthCheck;\n\npublic static class Extensions\n{\n    private const string HealthEndpointPath = \"/health\";\n    private const string AlivenessEndpointPath = \"/alive\";\n\n    public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services)\n    {\n        var healthOptions = services.GetOptions<HealthOptions>(nameof(HealthOptions));\n\n        if (healthOptions.Enabled)\n        {\n            var appOptions = services.GetOptions<AppOptions>(nameof(AppOptions));\n            var postgresOptions = services.GetOptions<PostgresOptions>(nameof(PostgresOptions));\n            var rabbitMqOptions = services.GetOptions<RabbitMqOptions>(nameof(RabbitMqOptions));\n            var eventStoreOptions = services.GetOptions<EventStoreOptions>(nameof(EventStoreOptions));\n            var mongoOptions = services.GetOptions<MongoOptions>(nameof(MongoOptions));\n\n            var healthChecksBuilder = services.AddHealthChecks()\n                // Add a default liveness check to ensure app is responsive\n                .AddCheck(\"self\", () => HealthCheckResult.Healthy(), [\"live\"])\n                .AddRabbitMQ(\n                    serviceProvider =>\n                    {\n                        var factory = new ConnectionFactory\n                        {\n                            Uri = new Uri($\"amqp://{rabbitMqOptions.UserName}:{rabbitMqOptions.Password}@{rabbitMqOptions.HostName}\"),\n                        };\n                        return factory.CreateConnectionAsync();\n                    });\n\n            if (!string.IsNullOrEmpty(mongoOptions.ConnectionString))\n            {\n                healthChecksBuilder.AddMongoDb(\n                    clientFactory: _ => new MongoClient(mongoOptions.ConnectionString),\n                    name: \"MongoDB-Health\",\n                    failureStatus: HealthStatus.Unhealthy,\n                    timeout: TimeSpan.FromSeconds(10));\n            }\n\n            if (!string.IsNullOrEmpty(postgresOptions.ConnectionString))\n                healthChecksBuilder.AddNpgSql(postgresOptions.ConnectionString);\n\n            if (!string.IsNullOrEmpty(eventStoreOptions.ConnectionString))\n                healthChecksBuilder.AddEventStore(eventStoreOptions.ConnectionString);\n\n            services.AddHealthChecksUI(setup =>\n                                       {\n                                           setup.SetEvaluationTimeInSeconds(60); // time in seconds between check\n                                           setup.AddHealthCheckEndpoint($\"Self Check - {appOptions.Name}\", HealthEndpointPath);\n                                       }).AddInMemoryStorage();\n        }\n\n        services.AddHealthChecks().AddCheck(\"self\", () => HealthCheckResult.Healthy(), [\"live\"]);\n        return services;\n    }\n\n    public static WebApplication UseCustomHealthCheck(this WebApplication app)\n    {\n        var healthOptions = app.Configuration.GetOptions<HealthOptions>(nameof(HealthOptions));\n\n        if (app.Environment.IsDevelopment())\n        {\n            app.MapHealthChecks(HealthEndpointPath);\n            app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions\n            {\n                Predicate = r => r.Tags.Contains(\"live\"),\n            });\n        }\n\n        if (healthOptions.Enabled)\n            app.MapHealthChecksUI(options => options.UIPath = \"/health-ui\");\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/HealthCheck/HealthOptions.cs",
    "content": "namespace BuildingBlocks.HealthCheck;\n\npublic class HealthOptions\n{\n    public bool Enabled { get; set; } = true;\n}"
  },
  {
    "path": "src/BuildingBlocks/Jwt/AuthHeaderHandler.cs",
    "content": "using System.Net.Http.Headers;\nusing Microsoft.AspNetCore.Http;\n\nnamespace BuildingBlocks.Jwt;\n\npublic class AuthHeaderHandler : DelegatingHandler\n{\n    private readonly IHttpContextAccessor _httpContext;\n\n    public AuthHeaderHandler(IHttpContextAccessor httpContext)\n    {\n        _httpContext = httpContext;\n    }\n\n    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,\n        CancellationToken cancellationToken)\n    {\n        var token = (_httpContext?.HttpContext?.Request.Headers[\"Authorization\"])?.ToString();\n\n        request.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", token?.Replace(\"Bearer \", \"\", StringComparison.CurrentCulture));\n\n        return base.SendAsync(request, cancellationToken);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Jwt/JwtExtensions.cs",
    "content": "using BuildingBlocks.Constants;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Microsoft.AspNetCore.Authentication.JwtBearer;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.IdentityModel.Tokens;\n\nnamespace BuildingBlocks.Jwt\n{\n    public static class JwtExtensions\n    {\n        public static IServiceCollection AddJwt(this IServiceCollection services)\n        {\n            // Bind Jwt settings from configuration\n            var jwtOptions = services.GetOptions<JwtBearerOptions>(\"Jwt\");\n\n            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n            .AddJwtBearer(options =>\n            {\n                options.Authority = jwtOptions.Authority;\n                options.Audience = jwtOptions.Audience;\n                options.RequireHttpsMetadata = false;\n\n                options.TokenValidationParameters = new TokenValidationParameters\n                {\n                    ValidateIssuer = true,\n                    ValidIssuers = [jwtOptions.Authority],\n                    ValidateAudience = true,\n                    ValidAudiences = [jwtOptions.Audience],\n                    ValidateLifetime = true,\n                    ClockSkew = TimeSpan.FromSeconds(2), // Reduce default clock skew\n                    // For IdentityServer4/Duende, we should also validate the signing key\n                    ValidateIssuerSigningKey = true,\n                    NameClaimType = \"name\", // Map \"name\" claim to User.Identity.Name\n                    RoleClaimType = \"role\", // Map \"role\" claim to User.IsInRole()\n                };\n\n                // Preserve ALL claims from the token (including \"sub\")\n                options.MapInboundClaims = false;\n            });\n\n\n            services.AddAuthorization(\n                options =>\n                {\n                    options.AddPolicy(\n                        nameof(ApiScope),\n                        policy =>\n                        {\n                            policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);\n                            policy.RequireAuthenticatedUser();\n                            policy.RequireClaim(\"scope\", jwtOptions.Audience);\n                        });\n\n                    // Role-based policies\n                    options.AddPolicy(\n                        IdentityConstant.Role.Admin,\n                        x =>\n                        {\n                            x.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);\n                            x.RequireRole(IdentityConstant.Role.Admin);\n                        }\n                    );\n                    options.AddPolicy(\n                        IdentityConstant.Role.User,\n                        x =>\n                        {\n                            x.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);\n                            x.RequireRole(IdentityConstant.Role.User);\n                        }\n                    );\n                });\n\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Logging/LoggingBehavior.cs",
    "content": "using System.Diagnostics;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.Logging;\n\npublic class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>\n    where TRequest : notnull, IRequest<TResponse>\n    where TResponse : notnull\n{\n    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;\n\n    public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)\n    {\n        _logger = logger;\n    }\n\n    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,\n        CancellationToken cancellationToken)\n    {\n        const string prefix = nameof(LoggingBehavior<TRequest, TResponse>);\n\n        _logger.LogInformation(\"[{Prefix}] Handle request={X-RequestData} and response={X-ResponseData}\",\n            prefix, typeof(TRequest).Name, typeof(TResponse).Name);\n\n        var timer = new Stopwatch();\n        timer.Start();\n\n        var response = await next();\n\n        timer.Stop();\n        var timeTaken = timer.Elapsed;\n        if (timeTaken.Seconds > 3) // if the request is greater than 3 seconds, then log the warnings\n            _logger.LogWarning(\"[{Perf-Possible}] The request {X-RequestData} took {TimeTaken} seconds.\",\n                prefix, typeof(TRequest).Name, timeTaken.Seconds);\n\n        _logger.LogInformation(\"[{Prefix}] Handled {X-RequestData}\", prefix, typeof(TRequest).Name);\n        return response;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mapster/Extensions.cs",
    "content": "using System.Reflection;\nusing Mapster;\nusing MapsterMapper;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Mapster;\n\npublic static class Extensions\n{\n    public static IServiceCollection AddCustomMapster(this IServiceCollection services, params Assembly[] assemblies)\n    {\n        var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;\n        typeAdapterConfig.Scan(assemblies);\n        var mapperConfig = new Mapper(typeAdapterConfig);\n        services.AddSingleton<IMapper>(mapperConfig);\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/MassTransit/ConsumeFilter.cs",
    "content": "using BuildingBlocks.Core.Event;\nusing BuildingBlocks.PersistMessageProcessor;\nusing MassTransit;\n\nnamespace BuildingBlocks.MassTransit;\n\n// Handle inbox messages with masstransit pipeline\npublic class ConsumeFilter<T> : IFilter<ConsumeContext<T>>\n    where T : class\n{\n    private readonly IPersistMessageProcessor _persistMessageProcessor;\n\n    public ConsumeFilter(IPersistMessageProcessor persistMessageProcessor)\n    {\n        _persistMessageProcessor = persistMessageProcessor;\n    }\n\n    public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next)\n    {\n        var id = await _persistMessageProcessor.AddReceivedMessageAsync(\n            new MessageEnvelope(\n                context.Message,\n                context.Headers.ToDictionary(x => x.Key, x => x.Value))\n        );\n\n        var message = await _persistMessageProcessor.ExistMessageAsync(id);\n\n        if (message is null)\n        {\n            await next.Send(context);\n            await _persistMessageProcessor.ProcessInboxAsync(id);\n        }\n    }\n\n    public void Probe(ProbeContext context)\n    {\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/MassTransit/Extensions.cs",
    "content": "using System.Reflection;\nusing BuildingBlocks.Web;\nusing MassTransit;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace BuildingBlocks.MassTransit;\n\nusing Exception;\n\npublic static class Extensions\n{\n    public static IServiceCollection AddCustomMassTransit(\n        this IServiceCollection services,\n        IWebHostEnvironment env,\n        TransportType transportType,\n        params Assembly[] assembly\n    )\n    {\n        services.AddValidateOptions<RabbitMqOptions>();\n\n        if (env.IsEnvironment(\"test\"))\n        {\n            services.AddMassTransitTestHarness(\n                configure =>\n                {\n                    SetupMasstransitConfigurations(services, configure, transportType, assembly);\n                });\n        }\n        else\n        {\n            services.AddMassTransit(\n                configure =>\n                {\n                    SetupMasstransitConfigurations(services, configure, transportType, assembly);\n                });\n        }\n\n        return services;\n    }\n\n    private static void SetupMasstransitConfigurations(\n        IServiceCollection services,\n        IBusRegistrationConfigurator configure,\n        TransportType transportType,\n        params Assembly[] assembly\n    )\n    {\n        configure.AddConsumers(assembly);\n        configure.AddSagaStateMachines(assembly);\n        configure.AddSagas(assembly);\n        configure.AddActivities(assembly);\n\n        switch (transportType)\n        {\n            case TransportType.RabbitMq:\n                configure.UsingRabbitMq(\n                    (context, configurator) =>\n                    {\n                        var configuration = context.GetRequiredService<IConfiguration>();\n\n                        var aspireConnectionString = configuration.GetConnectionString(\"rabbitmq\");\n\n                        if (!string.IsNullOrEmpty(aspireConnectionString))\n                        {\n                            configurator.Host(new Uri(aspireConnectionString));\n                        }\n                        else\n                        {\n                            var rabbitMqOptions = services.GetOptions<RabbitMqOptions>(nameof(RabbitMqOptions));\n\n                            ArgumentNullException.ThrowIfNull(rabbitMqOptions);\n\n                            configurator.Host(\n                                rabbitMqOptions?.HostName,\n                                rabbitMqOptions?.Port ?? 5672,\n                                \"/\",\n                                h =>\n                                {\n                                    h.Username(rabbitMqOptions.UserName);\n                                    h.Password(rabbitMqOptions.Password);\n                                });\n                        }\n\n                        configurator.ConfigureEndpoints(context);\n\n                        configurator.UseMessageRetry(AddRetryConfiguration);\n                    });\n\n                break;\n            case TransportType.InMemory:\n                configure.UsingInMemory(\n                    (context, configurator) =>\n                    {\n                        configurator.ConfigureEndpoints(context);\n                        configurator.UseMessageRetry(AddRetryConfiguration);\n                    });\n\n                break;\n            default:\n                throw new ArgumentOutOfRangeException(\n                    nameof(transportType),\n                    transportType,\n                    message: null);\n        }\n    }\n\n    private static void AddRetryConfiguration(IRetryConfigurator retryConfigurator)\n    {\n        retryConfigurator.Exponential(\n                3,\n                TimeSpan.FromMilliseconds(200),\n                TimeSpan.FromMinutes(120),\n                TimeSpan.FromMilliseconds(200))\n            .Ignore<\n                ValidationException>(); // don't retry if we have invalid data and message goes to _error queue masstransit\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/MassTransit/RabbitMqOptions.cs",
    "content": "namespace BuildingBlocks.MassTransit;\n\npublic class RabbitMqOptions\n{\n    public string HostName { get; set; }\n    public string ExchangeName { get; set; }\n    public string UserName { get; set; }\n    public string Password { get; set; }\n    public ushort? Port { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/MassTransit/TransportType.cs",
    "content": "namespace BuildingBlocks.MassTransit;\n\npublic enum TransportType\n{\n    RabbitMq,\n    InMemory\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/Extensions.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Mongo\n{\n    using Web;\n\n    public static class Extensions\n    {\n        public static IServiceCollection AddMongoDbContext<TContext>(\n            this WebApplicationBuilder builder, Action<MongoOptions>? configurator = null)\n        where TContext : MongoDbContext\n        {\n            return builder.Services.AddMongoDbContext<TContext, TContext>(builder.Configuration, configurator);\n        }\n\n        public static IServiceCollection AddMongoDbContext<TContextService, TContextImplementation>(\n            this IServiceCollection services, IConfiguration configuration, Action<MongoOptions>? configurator = null)\n        where TContextService : IMongoDbContext\n        where TContextImplementation : MongoDbContext, TContextService\n        {\n            // Configure MongoOptions with Aspire-aware defaults\n            services.AddOptions<MongoOptions>()\n                .Bind(configuration.GetSection(nameof(MongoOptions)))\n                .PostConfigure(options =>\n                               {\n                                   var aspireConnectionString = configuration.GetConnectionString(\"mongo\");\n                                   options.ConnectionString = aspireConnectionString ?? options.ConnectionString;\n                               });\n\n            if (configurator is { })\n            {\n                services.Configure(nameof(MongoOptions), configurator);\n            }\n            else\n            {\n                services.AddValidateOptions<MongoOptions>();\n            }\n\n            services.AddScoped(typeof(TContextService), typeof(TContextImplementation));\n            services.AddScoped(typeof(TContextImplementation));\n\n            services.AddScoped<IMongoDbContext>(sp => sp.GetRequiredService<TContextService>());\n\n            services.AddTransient(typeof(IMongoRepository<,>), typeof(MongoRepository<,>));\n            services.AddTransient(typeof(IMongoUnitOfWork<>), typeof(MongoUnitOfWork<>));\n\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/IMongoDbContext.cs",
    "content": "using MongoDB.Driver;\n\nnamespace BuildingBlocks.Mongo;\n\npublic interface IMongoDbContext : IDisposable\n{\n    IMongoCollection<T> GetCollection<T>(string? name = null);\n    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);\n    Task BeginTransactionAsync(CancellationToken cancellationToken = default);\n    Task CommitTransactionAsync(CancellationToken cancellationToken = default);\n    Task RollbackTransaction(CancellationToken cancellationToken = default);\n    void AddCommand(Func<Task> func);\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/IMongoRepository.cs",
    "content": "using BuildingBlocks.Core.Model;\n\nnamespace BuildingBlocks.Mongo;\n\npublic interface IMongoRepository<TEntity, in TId> : IRepository<TEntity, TId>\n    where TEntity : class, IAggregate<TId>\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/IMongoUnitOfWork.cs",
    "content": "namespace BuildingBlocks.Mongo;\n\npublic interface IMongoUnitOfWork<out TContext> : IUnitOfWork<TContext> where TContext : class, IMongoDbContext\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/IRepository.cs",
    "content": "using System.Linq.Expressions;\nusing BuildingBlocks.Core.Model;\n\nnamespace BuildingBlocks.Mongo;\n\npublic interface IReadRepository<TEntity, in TId>\n    where TEntity : class, IAggregate<TId>\n{\n    Task<TEntity?> FindByIdAsync(TId id, CancellationToken cancellationToken = default);\n\n    Task<TEntity?> FindOneAsync(\n        Expression<Func<TEntity, bool>> predicate,\n        CancellationToken cancellationToken = default);\n\n    Task<IReadOnlyList<TEntity>> FindAsync(\n        Expression<Func<TEntity, bool>> predicate,\n        CancellationToken cancellationToken = default);\n\n    Task<IReadOnlyList<TEntity>> GetAllAsync(CancellationToken cancellationToken = default);\n\n    public Task<IReadOnlyList<TEntity>> RawQuery(\n        string query,\n        CancellationToken cancellationToken = default,\n        params object[] queryParams);\n}\n\npublic interface IWriteRepository<TEntity, in TId>\n    where TEntity : class, IAggregate<TId>\n{\n    Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default);\n    Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);\n    Task DeleteRangeAsync(IReadOnlyList<TEntity> entities, CancellationToken cancellationToken = default);\n    Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);\n    Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default);\n    Task DeleteByIdAsync(TId id, CancellationToken cancellationToken = default);\n}\n\npublic interface IRepository<TEntity, in TId> :\n    IReadRepository<TEntity, TId>,\n    IWriteRepository<TEntity, TId>,\n    IDisposable\n    where TEntity : class, IAggregate<TId>\n{\n}\n\npublic interface IRepository<TEntity> : IRepository<TEntity, long>\n    where TEntity : class, IAggregate<long>\n{\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/ITransactionAble.cs",
    "content": "namespace BuildingBlocks.Mongo;\n\npublic interface ITransactionAble\n{\n    Task BeginTransactionAsync(CancellationToken cancellationToken = default);\n    Task RollbackTransactionAsync(CancellationToken cancellationToken = default);\n    Task CommitTransactionAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/IUnitOfWork.cs",
    "content": "namespace BuildingBlocks.Mongo;\n\npublic interface IUnitOfWork : IDisposable\n{\n    Task BeginTransactionAsync(CancellationToken cancellationToken = default);\n    Task CommitAsync(CancellationToken cancellationToken = default);\n}\n\npublic interface IUnitOfWork<out TContext> : IUnitOfWork\n    where TContext : class\n{\n    TContext Context { get; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/ImmutablePocoConvention.cs",
    "content": "using System.Reflection;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace BuildingBlocks.Mongo\n{\n    /// <summary>\n    /// A convention that map all read only properties for which a matching constructor is found.\n    /// Also matching constructors are mapped.\n    /// </summary>\n    public class ImmutablePocoConvention : ConventionBase, IClassMapConvention\n    {\n        private readonly BindingFlags _bindingFlags;\n\n        public ImmutablePocoConvention()\n            : this(BindingFlags.Instance | BindingFlags.Public)\n        {\n        }\n\n        public ImmutablePocoConvention(BindingFlags bindingFlags)\n        {\n            _bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;\n        }\n\n        public void Apply(BsonClassMap classMap)\n        {\n            var readOnlyProperties = classMap.ClassType.GetTypeInfo()\n                .GetProperties(_bindingFlags)\n                .Where(p => IsReadOnlyProperty(classMap, p))\n                .ToList();\n\n            foreach (var constructor in classMap.ClassType.GetConstructors())\n            {\n                // If we found a matching constructor then we map it and all the readonly properties\n                var matchProperties = GetMatchingProperties(constructor, readOnlyProperties);\n                if (matchProperties.Any())\n                {\n                    // Map constructor\n                    classMap.MapConstructor(constructor);\n\n                    // Map properties\n                    foreach (var p in matchProperties)\n                        classMap.MapMember(p);\n                }\n            }\n        }\n\n        private static List<PropertyInfo> GetMatchingProperties(\n            ConstructorInfo constructor,\n            List<PropertyInfo> properties)\n        {\n            var matchProperties = new List<PropertyInfo>();\n\n            var ctorParameters = constructor.GetParameters();\n            foreach (var ctorParameter in ctorParameters)\n            {\n                var matchProperty = properties.FirstOrDefault(p => ParameterMatchProperty(ctorParameter, p));\n                if (matchProperty == null)\n                    return new List<PropertyInfo>();\n\n                matchProperties.Add(matchProperty);\n            }\n\n            return matchProperties;\n        }\n\n\n        private static bool ParameterMatchProperty(ParameterInfo parameter, PropertyInfo property)\n        {\n            return string.Equals(property.Name, parameter.Name, StringComparison.OrdinalIgnoreCase)\n                   && parameter.ParameterType == property.PropertyType;\n        }\n\n        private static bool IsReadOnlyProperty(BsonClassMap classMap, PropertyInfo propertyInfo)\n        {\n            // we can't read\n            if (!propertyInfo.CanRead)\n                return false;\n\n            // we can write (already handled by the default convention...)\n            if (propertyInfo.CanWrite)\n                return false;\n\n            // skip indexers\n            if (propertyInfo.GetIndexParameters().Length != 0)\n                return false;\n\n            // skip overridden properties (they are already included by the base class)\n            var getMethodInfo = propertyInfo.GetMethod;\n            if (getMethodInfo.IsVirtual && getMethodInfo.GetBaseDefinition().DeclaringType != classMap.ClassType)\n                return false;\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/MicroBootstrap.Persistence.Mongo.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\MicroBootstrap.Abstractions\\MicroBootstrap.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\MicroBootstrap.Core\\MicroBootstrap.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/BuildingBlocks/Mongo/MongoDbContext.cs",
    "content": "using System.Globalization;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\nusing MongoDB.Bson.Serialization.Serializers;\nusing MongoDB.Driver;\n\nnamespace BuildingBlocks.Mongo;\n\n// https://www.thecodebuzz.com/mongodb-repository-implementation-unit-testing-net-core-example/\n\npublic class MongoDbContext : IMongoDbContext\n{\n    public IClientSessionHandle? Session { get; set; }\n    public IMongoDatabase Database { get; }\n    public IMongoClient MongoClient { get; }\n    protected readonly IList<Func<Task>> _commands;\n    private static readonly bool _isSerializerRegisterd;\n\n    static MongoDbContext()\n    {\n        BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));\n    }\n\n    public MongoDbContext(IOptions<MongoOptions> options)\n    {\n        RegisterConventions();\n\n        MongoClient = new MongoClient(options.Value.ConnectionString);\n        var databaseName = options.Value.DatabaseName;\n        Database = MongoClient.GetDatabase(databaseName);\n\n        // Every command will be stored and it'll be processed at SaveChanges\n        _commands = new List<Func<Task>>();\n    }\n\n    private static void RegisterConventions()\n    {\n        ConventionRegistry.Register(\n            \"conventions\",\n            new ConventionPack\n            {\n                new CamelCaseElementNameConvention(),\n                new IgnoreExtraElementsConvention(true),\n                new EnumRepresentationConvention(BsonType.String),\n                new IgnoreIfDefaultConvention(false),\n                new ImmutablePocoConvention()\n            }, _ => true);\n    }\n\n    public IMongoCollection<T> GetCollection<T>(string? name = null)\n    {\n        return Database.GetCollection<T>(name ?? typeof(T).Name.ToLower(CultureInfo.CurrentCulture));\n    }\n\n    public void Dispose()\n    {\n        while (Session is { IsInTransaction: true })\n            Thread.Sleep(TimeSpan.FromMilliseconds(100));\n\n        GC.SuppressFinalize(this);\n    }\n\n    public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)\n    {\n        var result = _commands.Count;\n\n        using (Session = await MongoClient.StartSessionAsync(cancellationToken: cancellationToken))\n        {\n            Session.StartTransaction();\n\n            try\n            {\n                var commandTasks = _commands.Select(c => c());\n\n                await Task.WhenAll(commandTasks);\n\n                await Session.CommitTransactionAsync(cancellationToken);\n            }\n            catch (System.Exception ex)\n            {\n                await Session.AbortTransactionAsync(cancellationToken);\n                _commands.Clear();\n                throw;\n            }\n        }\n\n        _commands.Clear();\n        return result;\n    }\n\n    public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        Session = await MongoClient.StartSessionAsync(cancellationToken: cancellationToken);\n        Session.StartTransaction();\n    }\n\n    public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        if (Session is { IsInTransaction: true })\n            await Session.CommitTransactionAsync(cancellationToken);\n\n        Session?.Dispose();\n    }\n\n    public async Task RollbackTransaction(CancellationToken cancellationToken = default)\n    {\n        await Session?.AbortTransactionAsync(cancellationToken)!;\n    }\n\n    public void AddCommand(Func<Task> func)\n    {\n        _commands.Add(func);\n    }\n\n    public async Task ExecuteTransactionalAsync(Func<Task> action, CancellationToken cancellationToken = default)\n    {\n        await BeginTransactionAsync(cancellationToken);\n        try\n        {\n            await action();\n\n            await CommitTransactionAsync(cancellationToken);\n        }\n        catch\n        {\n            await RollbackTransaction(cancellationToken);\n            throw;\n        }\n    }\n\n    public async Task<T> ExecuteTransactionalAsync<T>(\n        Func<Task<T>> action,\n        CancellationToken cancellationToken = default)\n    {\n        await BeginTransactionAsync(cancellationToken);\n        try\n        {\n            var result = await action();\n\n            await CommitTransactionAsync(cancellationToken);\n\n            return result;\n        }\n        catch\n        {\n            await RollbackTransaction(cancellationToken);\n            throw;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/MongoOptions.cs",
    "content": "namespace BuildingBlocks.Mongo;\n\npublic class MongoOptions\n{\n    public string ConnectionString { get; set; } = null!;\n    public string DatabaseName { get; set; } = null!;\n    public static Guid UniqueId { get; set; } = Guid.NewGuid();\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/MongoRepository.cs",
    "content": "using System.Linq.Expressions;\nusing BuildingBlocks.Core.Model;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace BuildingBlocks.Mongo;\n\npublic class MongoRepository<TEntity, TId> : IMongoRepository<TEntity, TId>\n    where TEntity : class, IAggregate<TId>\n{\n    private readonly IMongoDbContext _context;\n    protected readonly IMongoCollection<TEntity> DbSet;\n\n    public MongoRepository(IMongoDbContext context)\n    {\n        _context = context;\n        DbSet = _context.GetCollection<TEntity>();\n    }\n\n    public void Dispose()\n    {\n        _context?.Dispose();\n    }\n\n    public Task<TEntity?> FindByIdAsync(TId id, CancellationToken cancellationToken = default)\n    {\n        return FindOneAsync(e => e.Id.Equals(id), cancellationToken);\n    }\n\n    public Task<TEntity?> FindOneAsync(\n        Expression<Func<TEntity, bool>> predicate,\n        CancellationToken cancellationToken = default)\n    {\n        return DbSet.Find(predicate).SingleOrDefaultAsync(cancellationToken: cancellationToken)!;\n    }\n\n    public async Task<IReadOnlyList<TEntity>> FindAsync(\n        Expression<Func<TEntity, bool>> predicate,\n        CancellationToken cancellationToken = default)\n    {\n        return await DbSet.Find(predicate).ToListAsync(cancellationToken: cancellationToken)!;\n    }\n\n    public async Task<IReadOnlyList<TEntity>> GetAllAsync(CancellationToken cancellationToken = default)\n    {\n        return await DbSet.AsQueryable().ToListAsync(cancellationToken);\n    }\n\n    public Task<IReadOnlyList<TEntity>> RawQuery(\n        string query,\n        CancellationToken cancellationToken = default,\n        params object[] queryParams)\n    {\n        throw new NotImplementedException();\n    }\n\n    public async Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default)\n    {\n        await DbSet.InsertOneAsync(entity, new InsertOneOptions(), cancellationToken);\n\n        return entity;\n    }\n\n    public async Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)\n    {\n        await DbSet.ReplaceOneAsync(e => e.Id.Equals(entity.Id), entity, new ReplaceOptions(), cancellationToken);\n\n        return entity;\n    }\n\n    public Task DeleteRangeAsync(IReadOnlyList<TEntity> entities, CancellationToken cancellationToken = default)\n    {\n        return DbSet.DeleteOneAsync(e => entities.Any(i => e.Id.Equals(i.Id)), cancellationToken);\n    }\n\n    public Task DeleteAsync(\n        Expression<Func<TEntity, bool>> predicate,\n        CancellationToken cancellationToken = default)\n        => DbSet.DeleteOneAsync(predicate, cancellationToken);\n\n    public Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default)\n    {\n        return DbSet.DeleteOneAsync(e => e.Id.Equals(entity.Id), cancellationToken);\n    }\n\n    public Task DeleteByIdAsync(TId id, CancellationToken cancellationToken = default)\n    {\n        return DbSet.DeleteOneAsync(e => e.Id.Equals(id), cancellationToken);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Mongo/MongoUnitOfWork.cs",
    "content": "namespace BuildingBlocks.Mongo;\n\npublic class MongoUnitOfWork<TContext> : IMongoUnitOfWork<TContext>, ITransactionAble\n    where TContext : MongoDbContext\n{\n    public MongoUnitOfWork(TContext context) => Context = context;\n\n    public TContext Context { get; }\n\n    public async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        await Context.SaveChangesAsync(cancellationToken);\n    }\n\n    public Task BeginTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        return Context.BeginTransactionAsync(cancellationToken);\n    }\n\n    public Task RollbackTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        return Context.RollbackTransaction(cancellationToken);\n    }\n\n    public Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        return Context.CommitTransactionAsync(cancellationToken);\n    }\n\n    public void Dispose() => Context.Dispose();\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenApi/Extensions.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Scalar.AspNetCore;\n\nnamespace BuildingBlocks.OpenApi\n{\n    public static class Extensions\n    {\n        // ref: https://github.com/dotnet/eShop/blob/main/src/eShop.ServiceDefaults/OpenApi.Extensions.cs\n        public static IServiceCollection AddAspnetOpenApi(this IServiceCollection services)\n        {\n            string[] versions = [\"v1\"];\n\n            foreach (var description in versions)\n            {\n                services.AddOpenApi(\n                    description,\n                    options =>\n                    {\n                        options.AddDocumentTransformer<SecuritySchemeDocumentTransformer>();\n                    });\n            }\n\n            return services;\n        }\n\n        public static IApplicationBuilder UseAspnetOpenApi(this WebApplication app)\n        {\n            app.MapOpenApi();\n\n            app.UseSwaggerUI(\n                options =>\n                {\n                    var descriptions = app.DescribeApiVersions();\n\n                    // build a swagger endpoint for each discovered API version\n                    foreach (var description in descriptions)\n                    {\n                        var openApiUrl = $\"/openapi/{description.GroupName}.json\";\n                        var name = description.GroupName.ToUpperInvariant();\n                        options.SwaggerEndpoint(openApiUrl, name);\n                    }\n                });\n\n            // Add scalar ui\n            app.MapScalarApiReference(\n                redocOptions =>\n                {\n                    redocOptions.WithOpenApiRoutePattern(\"/openapi/{documentName}.json\");\n                });\n\n            return app;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenApi/SecuritySchemeDocumentTransformer.cs",
    "content": "using Microsoft.AspNetCore.OpenApi;\nusing Microsoft.OpenApi;\n\npublic class SecuritySchemeDocumentTransformer : IOpenApiDocumentTransformer\n{\n    public Task TransformAsync(\n        OpenApiDocument document,\n        OpenApiDocumentTransformerContext context,\n        CancellationToken cancellationToken\n    )\n    {\n        document.Components ??= new OpenApiComponents();\n\n        // Initialize with the correct interface type\n        document.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>();\n\n        var securitySchemes = new Dictionary<string, IOpenApiSecurityScheme>\n        {\n            [\"Bearer\"] = new OpenApiSecurityScheme\n            {\n                Name = \"Authorization\",\n                Type = SecuritySchemeType.Http,\n                Scheme = \"bearer\",\n                BearerFormat = \"JWT\",\n                In = ParameterLocation.Header,\n                Description =\n                    \"Enter 'Bearer' [space] and your token in the text input below.\\n\\nExample: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'\",\n            },\n            [\"ApiKey\"] = new OpenApiSecurityScheme\n            {\n                Name = \"X-API-KEY\",\n                Type = SecuritySchemeType.ApiKey,\n                In = ParameterLocation.Header,\n                Description = \"Enter your API key in the text input below.\\n\\nExample: '12345-abcdef'\",\n            },\n        };\n\n        foreach (var (key, scheme) in securitySchemes)\n        {\n            if (!document.Components.SecuritySchemes.ContainsKey(key))\n            {\n                document.Components.SecuritySchemes.Add(key, scheme);\n            }\n        }\n\n        return Task.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/ActivityExtensions.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\n\nnamespace BuildingBlocks.OpenTelemetryCollector;\n\ninternal static class ActivityExtensions\n{\n    /// <summary>\n    /// Retrieves the tags from the parent of the current Activity, if available.\n    /// </summary>\n    /// <param name=\"activity\">The current Activity.</param>\n    /// <returns>A dictionary containing the parent tags, or an empty dictionary if no parent tags are available.</returns>\n    public static Dictionary<string, object?> GetParentTags(this Activity activity)\n    {\n        ArgumentNullException.ThrowIfNull(activity);\n\n        var parentTags = new Dictionary<string, object?>();\n\n        // Check if the current activity has a parent\n        var parentActivity = activity.Parent;\n\n        if (parentActivity != null)\n        {\n            foreach (var tag in parentActivity.Tags)\n            {\n                parentTags[tag.Key] = tag.Value;\n            }\n        }\n        else\n        {\n            // If no parent Activity is available, check for links\n            foreach (var link in activity.Links)\n            {\n                // Extract tags from the first link's context (assuming it's the parent-like context)\n                if (link.Tags != null)\n                {\n                    foreach (var tag in link.Tags)\n                    {\n                        parentTags[tag.Key] = tag.Value;\n                    }\n                }\n\n                // Break after processing the first link, as there should only be one parent context.\n                break;\n            }\n        }\n\n        return parentTags;\n    }\n\n    /// <summary>\n    /// Extracts important information from an Activity into an ActivityInfo object.\n    /// </summary>\n    /// <param name=\"activity\">The Activity from which to extract information.</param>\n    /// <returns>An ActivityInfo object containing the extracted information.</returns>\n    public static ActivityInfo ExtractImportantInformation(this Activity activity)\n    {\n        ArgumentNullException.ThrowIfNull(activity);\n\n        var activityInfo = new ActivityInfo\n        {\n            Name = activity.DisplayName,\n            StartTime = activity.StartTimeUtc,\n            Duration = activity.Duration,\n            Status =\n                activity.Tags.FirstOrDefault(tag => tag.Key == TelemetryTags.Tracing.Otel.StatusCode).Value\n                ?? \"Unknown\",\n            StatusDescription = activity\n                .Tags.FirstOrDefault(tag => tag.Key == TelemetryTags.Tracing.Otel.StatusDescription)\n                .Value,\n            Tags = activity.Tags.ToDictionary(tag => tag.Key, tag => tag.Value),\n            Events = activity\n                .Events.Select(e => new ActivityEventInfo\n                {\n                    Name = e.Name,\n                    Timestamp = e.Timestamp,\n                    Attributes = e.Tags.ToDictionary(tag => tag.Key, tag => tag.Value),\n                })\n                .ToList(),\n            TraceId = activity.TraceId.ToString(),\n            SpanId = activity.SpanId.ToString(),\n        };\n\n        return activityInfo;\n    }\n\n    /// <summary>\n    /// Sets an \"OK\" status on the provided Activity, indicating a successful operation.\n    /// </summary>\n    /// <param name=\"activity\">The Activity to update.</param>\n    /// <param name=\"description\">An optional description of the successful operation.</param>\n    /// <returns>The updated Activity with the status and tags set.</returns>\n    public static Activity SetOkStatus(this Activity activity, string? description = null)\n    {\n        ArgumentNullException.ThrowIfNull(activity);\n\n        // Set the status of the activity to \"OK\"\n        activity.SetStatus(ActivityStatusCode.Ok, description);\n\n        // Add telemetry tags for status\n        activity.SetTag(\n            TelemetryTags.Tracing.Otel.StatusCode,\n            nameof(ActivityStatusCode.Ok).ToUpper(CultureInfo.InvariantCulture)\n        );\n        if (!string.IsNullOrEmpty(description))\n            activity.SetTag(TelemetryTags.Tracing.Otel.StatusDescription, description);\n\n        return activity;\n    }\n\n    /// <summary>\n    /// Sets an \"Unset\" status on the provided Activity, indicating no explicit status was applied.\n    /// </summary>\n    /// <param name=\"activity\">The Activity to update.</param>\n    /// <param name=\"description\">An optional description of the unset status.</param>\n    /// <returns>The updated Activity with the status and tags set.</returns>\n    public static Activity SetUnsetStatus(this Activity activity, string? description = null)\n    {\n        ArgumentNullException.ThrowIfNull(activity);\n\n        // Set the status of the activity to \"Unset\"\n        activity.SetStatus(ActivityStatusCode.Unset, description);\n\n        // Add telemetry tags for status\n        activity.SetTag(\n            TelemetryTags.Tracing.Otel.StatusCode,\n            nameof(ActivityStatusCode.Unset).ToUpper(CultureInfo.InvariantCulture)\n        );\n        if (!string.IsNullOrEmpty(description))\n            activity.SetTag(TelemetryTags.Tracing.Otel.StatusDescription, description);\n\n        return activity;\n    }\n\n    /// <summary>\n    /// Sets an \"Error\" status on the provided Activity, indicating a failed operation.\n    /// </summary>\n    /// <param name=\"activity\">The Activity to update.</param>\n    /// <param name=\"exception\">The exception associated with the error, if available.</param>\n    /// <param name=\"description\">An optional description of the error.</param>\n    /// <returns>The updated Activity with the status, error details, and tags set.</returns>\n    public static Activity SetErrorStatus(this Activity activity, System.Exception? exception, string? description = null)\n    {\n        ArgumentNullException.ThrowIfNull(activity);\n\n        // Add telemetry tags for status\n        activity.SetTag(\n            TelemetryTags.Tracing.Otel.StatusCode,\n            nameof(ActivityStatusCode.Error).ToUpper(CultureInfo.InvariantCulture)\n        );\n        if (!string.IsNullOrEmpty(description))\n            activity.SetTag(TelemetryTags.Tracing.Otel.StatusDescription, description);\n\n        // Add detailed exception tags, if an exception is provided\n        return activity.SetExceptionTags(exception);\n    }\n\n    // See https://opentelemetry.io/docs/specs/otel/trace/semantic_conventions/exceptions/\n    public static Activity SetExceptionTags(this Activity activity, System.Exception? ex)\n    {\n        if (ex is null)\n        {\n            return activity;\n        }\n\n        activity.SetStatus(ActivityStatusCode.Error);\n        activity.AddException(ex);\n\n        activity.AddTag(TelemetryTags.Tracing.Exception.Message, ex.Message);\n        activity.AddTag(TelemetryTags.Tracing.Exception.Stacktrace, ex.ToString());\n        activity.AddTag(TelemetryTags.Tracing.Exception.Type, ex.GetType().FullName);\n\n        return activity;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/ActivityInfo.cs",
    "content": "using System.Diagnostics;\n\nnamespace BuildingBlocks.OpenTelemetryCollector;\n\npublic class ActivityInfo\n{\n    public string Name { get; set; } = default!;\n    public DateTime StartTime { get; set; }\n    public TimeSpan Duration { get; set; }\n    public string Status { get; set; } = default!;\n    public string? StatusDescription { get; set; }\n    public IDictionary<string, string?> Tags { get; set; } = new Dictionary<string, string?>();\n    public IList<ActivityEventInfo> Events { get; set; } = new List<ActivityEventInfo>();\n    public string TraceId { get; set; } = default!;\n    public string SpanId { get; set; } = default!;\n\n    public string? ParentId { get; set; }\n\n    public ActivityContext? Parent { get; set; }\n\n    public ActivityKind Kind { get; set; }\n}\n\npublic class ActivityEventInfo\n{\n    public string Name { get; set; } = default!;\n    public DateTimeOffset Timestamp { get; set; }\n    public IDictionary<string, object?> Attributes { get; set; } = new Dictionary<string, object?>();\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/Behaviors/ObservabilityPipelineBehavior.cs",
    "content": "using BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Commands;\nusing BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Query;\nusing MediatR;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.Behaviors;\n\npublic class ObservabilityPipelineBehavior<TRequest, TResponse>(\n    CommandHandlerActivity commandActivity,\n    CommandHandlerMetrics commandMetrics,\n    QueryHandlerActivity queryActivity,\n    QueryHandlerMetrics queryMetrics\n) : IPipelineBehavior<TRequest, TResponse>\n    where TRequest : IRequest<TResponse>\n    where TResponse : notnull\n{\n    public async Task<TResponse> Handle(TRequest message, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)\n    {\n        var isCommand = message is IQuery<TResponse>;\n        var isQuery = message is ICommand<TResponse>;\n\n        if (isCommand)\n        {\n            commandMetrics.StartExecuting<TRequest>();\n        }\n\n        if (isQuery)\n        {\n            queryMetrics.StartExecuting<TRequest>();\n        }\n\n        try\n        {\n            if (isCommand)\n            {\n                var commandResult = await commandActivity.Execute<TRequest, TResponse>(\n                                        async (activity, ct) =>\n                                        {\n                                            var response = await next();\n\n                                            return response;\n                                        },\n                                        cancellationToken\n                                    );\n\n                commandMetrics.FinishExecuting<TRequest>();\n\n                return commandResult;\n            }\n\n            if (isQuery)\n            {\n                var queryResult = await queryActivity.Execute<TRequest, TResponse>(\n                                      async (activity, ct) =>\n                                      {\n                                          var response = await next();\n\n                                          return response;\n                                      },\n                                      cancellationToken\n                                  );\n\n                queryMetrics.FinishExecuting<TRequest>();\n\n                return queryResult;\n            }\n        }\n        catch (System.Exception)\n        {\n            if (isQuery)\n            {\n                queryMetrics.FailedCommand<TRequest>();\n            }\n\n            if (isCommand)\n            {\n                commandMetrics.FailedCommand<TRequest>();\n            }\n\n            throw;\n        }\n\n        return await next();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/CoreDiagnostics/Commands/CommandHandlerActivity.cs",
    "content": "using System.Diagnostics;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Commands;\n\npublic class CommandHandlerActivity(IDiagnosticsProvider diagnosticsProvider)\n{\n    public async Task Execute<TCommand>(\n        Func<Activity?, CancellationToken, Task> action,\n        CancellationToken cancellationToken\n    )\n    {\n        var commandName = typeof(TCommand).Name;\n        var handlerType = typeof(TCommand)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TCommand)\n                    )\n            );\n        var commandHandlerName = handlerType?.Name;\n\n        // usually we use class/methodName\n        var activityName = $\"{ObservabilityConstant.Components.CommandHandler}.{commandHandlerName}/{commandName}\";\n\n        await diagnosticsProvider.ExecuteActivityAsync(\n            new CreateActivityInfo\n            {\n                Name = activityName,\n                ActivityKind = ActivityKind.Consumer,\n                Tags = new Dictionary<string, object?>\n                {\n                    { TelemetryTags.Tracing.Application.Commands.Command, commandName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandType, typeof(TCommand).FullName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandHandler, commandHandlerName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandHandlerType, handlerType?.FullName },\n                },\n            },\n            action,\n            cancellationToken\n        );\n    }\n\n    public async Task<TResult> Execute<TCommand, TResult>(\n        Func<Activity?, CancellationToken, Task<TResult>> action,\n        CancellationToken cancellationToken\n    )\n    {\n        var commandName = typeof(TCommand).Name;\n        var handlerType = typeof(TCommand)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TCommand)\n                    )\n            );\n        var commandHandlerName = handlerType?.Name;\n\n        // usually we use class/methodName\n        var activityName = $\"{ObservabilityConstant.Components.CommandHandler}.{commandHandlerName}/{commandName}\";\n\n        return await diagnosticsProvider.ExecuteActivityAsync(\n            new CreateActivityInfo\n            {\n                Name = activityName,\n                ActivityKind = ActivityKind.Consumer,\n                Tags = new Dictionary<string, object?>\n                {\n                    { TelemetryTags.Tracing.Application.Commands.Command, commandName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandType, typeof(TCommand).FullName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandHandler, commandHandlerName },\n                    { TelemetryTags.Tracing.Application.Commands.CommandHandlerType, handlerType?.FullName },\n                },\n            },\n            action,\n            cancellationToken\n        );\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/CoreDiagnostics/Commands/CommandHandlerMetrics.cs",
    "content": "using System.Diagnostics;\nusing System.Diagnostics.Metrics;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.OpenTelemetryCollector;\nusing BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Commands;\n\npublic class CommandHandlerMetrics\n{\n    private readonly UpDownCounter<long> _activeCommandsCounter;\n    private readonly Counter<long> _totalCommandsNumber;\n    private readonly Counter<long> _successCommandsNumber;\n    private readonly Counter<long> _failedCommandsNumber;\n    private readonly Histogram<double> _handlerDuration;\n\n    private Stopwatch _timer;\n\n    public CommandHandlerMetrics(IDiagnosticsProvider diagnosticsProvider)\n    {\n        _activeCommandsCounter = diagnosticsProvider.Meter.CreateUpDownCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.ActiveCount,\n            unit: \"{active_commands}\",\n            description: \"Number of commands currently being handled\"\n        );\n\n        _totalCommandsNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.TotalExecutedCount,\n            unit: \"{total_commands}\",\n            description: \"Total number of executed command that sent to command handlers\"\n        );\n\n        _successCommandsNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.SuccessCount,\n            unit: \"{success_commands}\",\n            description: \"Number commands that handled successfully\"\n        );\n\n        _failedCommandsNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.FaildCount,\n            unit: \"{failed_commands}\",\n            description: \"Number commands that handled with errors\"\n        );\n\n        _handlerDuration = diagnosticsProvider.Meter.CreateHistogram<double>(\n            TelemetryTags.Metrics.Application.Commands.HandlerDuration,\n            unit: \"s\",\n            description: \"Measures the duration of command handler\"\n        );\n    }\n\n    public void StartExecuting<TCommand>()\n    {\n        var commandName = typeof(TCommand).Name;\n        var handlerType = typeof(TCommand)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TCommand)\n                    )\n            );\n        var commandHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Commands.Command, commandName },\n            { TelemetryTags.Tracing.Application.Commands.CommandType, typeof(TCommand).FullName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandler, commandHandlerName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandlerType, handlerType?.FullName },\n        };\n\n        if (_activeCommandsCounter.Enabled)\n        {\n            _activeCommandsCounter.Add(1, tags);\n        }\n\n        if (_totalCommandsNumber.Enabled)\n        {\n            _totalCommandsNumber.Add(1, tags);\n        }\n\n        _timer = Stopwatch.StartNew();\n    }\n\n    public void FinishExecuting<TCommand>()\n    {\n        var commandName = typeof(TCommand).Name;\n        var handlerType = typeof(TCommand)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TCommand)\n                    )\n            );\n        var commandHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Commands.Command, commandName },\n            { TelemetryTags.Tracing.Application.Commands.CommandType, typeof(TCommand).FullName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandler, commandHandlerName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandlerType, handlerType?.FullName },\n        };\n\n        if (_activeCommandsCounter.Enabled)\n        {\n            _activeCommandsCounter.Add(-1, tags);\n        }\n\n        if (!_handlerDuration.Enabled)\n            return;\n\n        var elapsedTimeSeconds = _timer.Elapsed.Seconds;\n\n        _handlerDuration.Record(elapsedTimeSeconds, tags);\n\n        if (_successCommandsNumber.Enabled)\n        {\n            _successCommandsNumber.Add(1, tags);\n        }\n    }\n\n    public void FailedCommand<TCommand>()\n    {\n        var commandName = typeof(TCommand).Name;\n        var handlerType = typeof(TCommand)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TCommand)\n                    )\n            );\n        var commandHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Commands.Command, commandName },\n            { TelemetryTags.Tracing.Application.Commands.CommandType, typeof(TCommand).FullName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandler, commandHandlerName },\n            { TelemetryTags.Tracing.Application.Commands.CommandHandlerType, handlerType?.FullName },\n        };\n\n        if (_failedCommandsNumber.Enabled)\n        {\n            _failedCommandsNumber.Add(1, tags);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/CoreDiagnostics/Query/QueryHandlerActivity.cs",
    "content": "using System.Diagnostics;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Query;\n\npublic class QueryHandlerActivity(IDiagnosticsProvider diagnosticsProvider)\n{\n    public async Task<TResult> Execute<TQuery, TResult>(\n        Func<Activity?, CancellationToken, Task<TResult>> action,\n        CancellationToken cancellationToken\n    )\n    {\n        var queryName = typeof(TQuery).Name;\n        var handlerType = typeof(TQuery)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TQuery)\n                    )\n            );\n        var queryHandlerName = handlerType?.Name;\n\n        // usually we use class/methodName\n        var activityName = $\"{ObservabilityConstant.Components.QueryHandler}.{queryHandlerName}/{queryName}\";\n\n        return await diagnosticsProvider.ExecuteActivityAsync(\n            new CreateActivityInfo\n            {\n                Name = activityName,\n                ActivityKind = ActivityKind.Consumer,\n                Tags = new Dictionary<string, object?>\n                {\n                    { TelemetryTags.Tracing.Application.Queries.Query, queryName },\n                    { TelemetryTags.Tracing.Application.Queries.QueryType, typeof(TQuery).FullName },\n                    { TelemetryTags.Tracing.Application.Queries.QueryHandler, queryHandlerName },\n                    { TelemetryTags.Tracing.Application.Queries.QueryHandlerType, handlerType?.FullName },\n                },\n            },\n            action,\n            cancellationToken\n        );\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/CoreDiagnostics/Query/QueryHandlerMetrics.cs",
    "content": "using System.Diagnostics;\nusing System.Diagnostics.Metrics;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Query;\n\npublic class QueryHandlerMetrics\n{\n    private readonly UpDownCounter<long> _activeQueriesCounter;\n    private readonly Counter<long> _totalQueriesNumber;\n    private readonly Counter<long> _successQueriesNumber;\n    private readonly Counter<long> _failedQueriesNumber;\n    private readonly Histogram<double> _handlerDuration;\n\n    private Stopwatch _timer;\n\n    public QueryHandlerMetrics(IDiagnosticsProvider diagnosticsProvider)\n    {\n        _activeQueriesCounter = diagnosticsProvider.Meter.CreateUpDownCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.ActiveCount,\n            unit: \"{active_queries}\",\n            description: \"Number of queries currently being handled\"\n        );\n\n        _totalQueriesNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.TotalExecutedCount,\n            unit: \"{total_queries}\",\n            description: \"Total number of executed query that sent to query handlers\"\n        );\n\n        _successQueriesNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.SuccessCount,\n            unit: \"{success_queries}\",\n            description: \"Number queries that handled successfully\"\n        );\n\n        _failedQueriesNumber = diagnosticsProvider.Meter.CreateCounter<long>(\n            TelemetryTags.Metrics.Application.Commands.FaildCount,\n            unit: \"{failed_queries}\",\n            description: \"Number queries that handled with errors\"\n        );\n\n        _handlerDuration = diagnosticsProvider.Meter.CreateHistogram<double>(\n            TelemetryTags.Metrics.Application.Commands.HandlerDuration,\n            unit: \"s\",\n            description: \"Measures the duration of query handler\"\n        );\n    }\n\n    public void StartExecuting<TQuery>()\n    {\n        var queryName = typeof(TQuery).Name;\n        var handlerType = typeof(TQuery)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TQuery)\n                    )\n            );\n        var queryHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Queries.Query, queryName },\n            { TelemetryTags.Tracing.Application.Queries.QueryType, typeof(TQuery).FullName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandler, queryHandlerName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandlerType, handlerType?.FullName },\n        };\n\n        if (_activeQueriesCounter.Enabled)\n        {\n            _activeQueriesCounter.Add(1, tags);\n        }\n\n        if (_totalQueriesNumber.Enabled)\n        {\n            _totalQueriesNumber.Add(1, tags);\n        }\n\n        _timer = Stopwatch.StartNew();\n    }\n\n    public void FinishExecuting<TQuery>()\n    {\n        var queryName = typeof(TQuery).Name;\n        var handlerType = typeof(TQuery)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TQuery)\n                    )\n            );\n        var queryHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Queries.Query, queryName },\n            { TelemetryTags.Tracing.Application.Queries.QueryType, typeof(TQuery).FullName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandler, queryHandlerName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandlerType, handlerType?.FullName },\n        };\n\n        if (_activeQueriesCounter.Enabled)\n        {\n            _activeQueriesCounter.Add(-1, tags);\n        }\n\n        if (!_handlerDuration.Enabled)\n            return;\n\n        var elapsedTimeSeconds = _timer.Elapsed.Seconds;\n\n        _handlerDuration.Record(elapsedTimeSeconds, tags);\n\n        if (_successQueriesNumber.Enabled)\n        {\n            _successQueriesNumber.Add(1, tags);\n        }\n    }\n\n    public void FailedCommand<TQuery>()\n    {\n        var queryName = typeof(TQuery).Name;\n        var handlerType = typeof(TQuery)\n            .Assembly.GetTypes()\n            .FirstOrDefault(t =>\n                t.GetInterfaces()\n                    .Any(i =>\n                        i.IsGenericType\n                        && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>)\n                        && i.GetGenericArguments()[0] == typeof(TQuery)\n                    )\n            );\n        var queryHandlerName = handlerType?.Name;\n\n        var tags = new TagList\n        {\n            { TelemetryTags.Tracing.Application.Queries.Query, queryName },\n            { TelemetryTags.Tracing.Application.Queries.QueryType, typeof(TQuery).FullName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandler, queryHandlerName },\n            { TelemetryTags.Tracing.Application.Queries.QueryHandlerType, handlerType?.FullName },\n        };\n\n        if (_failedQueriesNumber.Enabled)\n        {\n            _failedQueriesNumber.Add(1, tags);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/CreateActivityInfo.cs",
    "content": "using System.Diagnostics;\n\nnamespace BuildingBlocks.OpenTelemetryCollector;\n\npublic class CreateActivityInfo\n{\n    public required string Name { get; set; }\n    public IDictionary<string, object?> Tags { get; set; } = new Dictionary<string, object?>();\n    public string? ParentId { get; set; }\n    public ActivityContext? Parent { get; set; }\n    public required ActivityKind ActivityKind = ActivityKind.Internal;\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/DiagnosticsProvider/CustomeDiagnosticsProvider.cs",
    "content": "using System.Diagnostics;\nusing System.Diagnostics.Metrics;\nusing System.Reflection;\nusing Microsoft.Extensions.Options;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\npublic class CustomeDiagnosticsProvider(IMeterFactory meterFactory, IOptions<ObservabilityOptions> options)\n    : IDiagnosticsProvider\n{\n    private readonly Version? _version = Assembly.GetCallingAssembly().GetName().Version;\n    private ActivitySource? _activitySource;\n    private ActivityListener? _listener;\n    private Meter? _meter;\n\n    public string InstrumentationName { get; } = options.Value.InstrumentationName ?? throw new ArgumentException(\"InstrumentationName cannot be null or empty.\");\n\n    // https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs\n    public ActivitySource ActivitySource\n    {\n        get\n        {\n            if (_activitySource != null)\n                return _activitySource;\n\n            _activitySource = new(InstrumentationName, _version?.ToString());\n\n            _listener = new ActivityListener\n            {\n                ShouldListenTo = x => true,\n                Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllDataAndRecorded,\n            };\n            ActivitySource.AddActivityListener(_listener);\n\n            return _activitySource;\n        }\n    }\n\n    // https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation\n    public Meter Meter\n    {\n        get\n        {\n            if (_meter != null)\n                return _meter;\n\n            _meter = meterFactory.Create(InstrumentationName, _version?.ToString());\n\n            return _meter;\n        }\n    }\n\n    public async Task ExecuteActivityAsync(\n        CreateActivityInfo createActivityInfo,\n        Func<Activity?, CancellationToken, Task> action,\n        CancellationToken cancellationToken = default\n    )\n    {\n        if (!options.Value.TracingEnabled)\n        {\n            await action(null, cancellationToken);\n\n            return;\n        }\n\n        using var activity =\n            ActivitySource\n                .CreateActivity(\n                    name: $\"{InstrumentationName}.{createActivityInfo.Name}\",\n                    kind: createActivityInfo.ActivityKind,\n                    parentContext: createActivityInfo.Parent ?? default,\n                    idFormat: ActivityIdFormat.W3C,\n                    tags: createActivityInfo.Tags\n                )\n                ?.Start() ?? Activity.Current;\n\n        try\n        {\n            await action(activity!, cancellationToken);\n            activity?.SetOkStatus();\n        }\n        catch (System.Exception ex)\n        {\n            activity?.SetErrorStatus(ex);\n            throw;\n        }\n    }\n\n    public async Task<TResult?> ExecuteActivityAsync<TResult>(\n        CreateActivityInfo createActivityInfo,\n        Func<Activity?, CancellationToken, Task<TResult>> action,\n        CancellationToken cancellationToken = default\n    )\n    {\n        if (!options.Value.TracingEnabled)\n        {\n            return await action(null, cancellationToken);\n        }\n\n        using var activity =\n            ActivitySource\n                .CreateActivity(\n                    name: $\"{InstrumentationName}.{createActivityInfo.Name}\",\n                    kind: createActivityInfo.ActivityKind,\n                    parentContext: createActivityInfo.Parent ?? default,\n                    idFormat: ActivityIdFormat.W3C,\n                    tags: createActivityInfo.Tags\n                )\n                ?.Start() ?? Activity.Current;\n\n        try\n        {\n            var result = await action(activity!, cancellationToken);\n\n            activity?.SetOkStatus();\n\n            return result;\n        }\n        catch (System.Exception ex)\n        {\n            activity?.SetErrorStatus(ex);\n            throw;\n        }\n    }\n\n    public void Dispose()\n    {\n        _listener?.Dispose();\n        _meter?.Dispose();\n        _activitySource?.Dispose();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/DiagnosticsProvider/IDiagnosticsProvider.cs",
    "content": "using System.Diagnostics;\nusing System.Diagnostics.Metrics;\n\nnamespace BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\n\npublic interface IDiagnosticsProvider : IDisposable\n{\n    string InstrumentationName { get; }\n    ActivitySource ActivitySource { get; }\n    Meter Meter { get; }\n\n    Task ExecuteActivityAsync(\n        CreateActivityInfo createActivityInfo,\n        Func<Activity?, CancellationToken, Task> action,\n        CancellationToken cancellationToken = default\n    );\n\n    Task<TResult> ExecuteActivityAsync<TResult>(\n        CreateActivityInfo createActivityInfo,\n        Func<Activity?, CancellationToken, Task<TResult>> action,\n        CancellationToken cancellationToken = default\n    );\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/Extensions.cs",
    "content": "using System.Diagnostics;\nusing System.Reflection;\nusing BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Commands;\nusing BuildingBlocks.OpenTelemetryCollector.CoreDiagnostics.Query;\nusing BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;\nusing BuildingBlocks.Web;\nusing Grafana.OpenTelemetry;\nusing MassTransit.Logging;\nusing MassTransit.Monitoring;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http.Features;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Npgsql;\nusing OpenTelemetry;\nusing OpenTelemetry.Exporter;\nusing OpenTelemetry.Logs;\nusing OpenTelemetry.Metrics;\nusing OpenTelemetry.Resources;\nusing OpenTelemetry.Trace;\n\nnamespace BuildingBlocks.OpenTelemetryCollector;\n\n// https://learn.microsoft.com/en-us/dotnet/core/diagnostics/observability-otlp-example\n// https://learn.microsoft.com/en-us/dotnet/core/diagnostics/observability-prgrja-example\n// https://learn.microsoft.com/en-us/dotnet/core/diagnostics/observability-prgrja-example\n// https://blog.codingmilitia.com/2023/09/05/observing-dotnet-microservices-with-opentelemetry-logs-traces-metrics/\npublic static class Extensions\n{\n    private const string HealthEndpointPath = \"/health\";\n    private const string AlivenessEndpointPath = \"/alive\";\n\n    public static WebApplicationBuilder AddCustomObservability(this WebApplicationBuilder builder)\n    {\n        Activity.DefaultIdFormat = ActivityIdFormat.W3C;\n        builder.Services.AddSingleton<IDiagnosticsProvider, CustomeDiagnosticsProvider>();\n        builder.AddCoreDiagnostics();\n\n        builder.Services.AddValidateOptions<ObservabilityOptions>();\n        var observabilityOptions = builder.Services.GetOptions<ObservabilityOptions>(nameof(ObservabilityOptions));\n\n        // InstrumentationName property option is mandatory and can't be empty\n        ArgumentException.ThrowIfNullOrEmpty(observabilityOptions.InstrumentationName);\n        ObservabilityConstant.InstrumentationName = observabilityOptions.InstrumentationName;\n\n        if (observabilityOptions is { MetricsEnabled: false, TracingEnabled: false, LoggingEnabled: false })\n        {\n            return builder;\n        }\n\n        void ConfigureResourceBuilder(ResourceBuilder resourceBuilder)\n        {\n            resourceBuilder.AddAttributes([new(\"service.environment\", builder.Environment.EnvironmentName)]);\n\n            resourceBuilder.AddService(\n                serviceName: observabilityOptions.ServiceName ?? builder.Environment.ApplicationName,\n                serviceVersion: Assembly.GetCallingAssembly().GetName().Version?.ToString() ?? \"unknown\",\n                serviceInstanceId: Environment.MachineName\n            );\n        }\n\n        if (observabilityOptions.LoggingEnabled)\n        {\n            // logging\n            // opentelemtry logging works with .net default logging providers and doesn't work for `serilog`, in serilog we should enable `WriteToProviders=true`\n            builder.Logging.AddOpenTelemetry(options =>\n            {\n                var resourceBuilder = ResourceBuilder.CreateDefault();\n                ConfigureResourceBuilder(resourceBuilder);\n                options.SetResourceBuilder(resourceBuilder);\n\n                options.IncludeFormattedMessage = true;\n                options.IncludeScopes = true;\n                // this allows the state value passed to the logger.Log method to be parsed, in case it isn't a collection of KeyValuePair<string, object?>, which is the case when we use things like logger.LogInformation.\n                options.ParseStateValues = true;\n                // which means the message wouldn't have the placeholders replaced\n                options.IncludeFormattedMessage = true;\n\n                // add some metadata to exported logs\n                options.SetResourceBuilder(\n                    ResourceBuilder\n                        .CreateDefault()\n                        .AddService(\n                            observabilityOptions.ServiceName ?? builder.Environment.ApplicationName,\n                            serviceVersion: Assembly.GetCallingAssembly().GetName().Version?.ToString() ?? \"unknown\",\n                            serviceInstanceId: Environment.MachineName\n                        )\n                );\n\n                options.AddLoggingExporters(observabilityOptions);\n            });\n        }\n\n        if (observabilityOptions is { MetricsEnabled: false, TracingEnabled: false })\n        {\n            return builder;\n        }\n\n        OpenTelemetryBuilder otel = null!;\n\n        if (observabilityOptions.MetricsEnabled || observabilityOptions.TracingEnabled)\n        {\n            // metrics and tracing\n            otel = builder.Services.AddOpenTelemetry();\n            otel.ConfigureResource(ConfigureResourceBuilder);\n        }\n\n        if (observabilityOptions.MetricsEnabled)\n        {\n            otel.WithMetrics(metrics =>\n            {\n                metrics\n                    .AddAspNetCoreInstrumentation()\n                    .AddHttpClientInstrumentation()\n                    .AddProcessInstrumentation()\n                    .AddRuntimeInstrumentation()\n                    .AddMeter(InstrumentationOptions.MeterName)\n                    .AddMeter(observabilityOptions.InstrumentationName)\n                    // metrics provides by ASP.NET Core in .NET 8\n                    .AddView(\n                        \"http.server.request.duration\",\n                        new ExplicitBucketHistogramConfiguration\n                        {\n                            Boundaries = [0, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10],\n                        }\n                    )\n                    .AddMeter(\"System.Runtime\")\n                    .AddMeter(\"Microsoft.AspNetCore.Hosting\")\n                    .AddMeter(\"Microsoft.AspNetCore.Server.Kestrel\");\n\n                AddMetricsExporter(observabilityOptions, metrics);\n            });\n        }\n\n        if (observabilityOptions.TracingEnabled)\n        {\n            otel.WithTracing(tracing =>\n            {\n                if (builder.Environment.IsDevelopment())\n                {\n                    // We want to view all traces in development\n                    tracing.SetSampler(new AlwaysOnSampler());\n                }\n\n                tracing\n                    .SetErrorStatusOnException()\n                    .AddAspNetCoreInstrumentation(options =>\n                    {\n                        options.RecordException = true;\n                        // Don't trace requests to the health endpoint to avoid filling the dashboard with noise\n                        options.Filter = httpContext =>\n                                             !(httpContext.Request.Path.StartsWithSegments(\n                                                   HealthEndpointPath, StringComparison.OrdinalIgnoreCase) ||\n                                               httpContext.Request.Path.StartsWithSegments(\n                                                   AlivenessEndpointPath, StringComparison.OrdinalIgnoreCase\n                                               ));\n                    })\n                    .AddGrpcClientInstrumentation()\n                    .AddHttpClientInstrumentation(instrumentationOptions =>\n                    {\n                        instrumentationOptions.RecordException = true;\n                    })\n                    .AddEntityFrameworkCoreInstrumentation()\n                    .AddSource(DiagnosticHeaders.DefaultListenerName)\n                    .AddNpgsql()\n                    // `AddSource` for adding custom activity sources\n                    .AddSource(observabilityOptions.InstrumentationName)\n                    // metrics provides by ASP.NET Core in .NET 8\n                    .AddSource(\"Microsoft.AspNetCore.Hosting\")\n                    .AddSource(\"Microsoft.AspNetCore.Server.Kestrel\");\n\n                AddTracingExporter(observabilityOptions, tracing);\n            });\n        }\n\n        return builder;\n    }\n\n\n    public static WebApplication UseCustomObservability(this WebApplication app)\n    {\n        var options = app.Services.GetRequiredService<IOptions<ObservabilityOptions>>().Value;\n\n        app.Use(\n            async (context, next) =>\n            {\n                var metricsFeature = context.Features.Get<IHttpMetricsTagsFeature>();\n                if (metricsFeature != null && context.Request.Path is { Value: \"/metrics\" or \"/health\" })\n                {\n                    metricsFeature.MetricsDisabled = true;\n                }\n\n                await next(context);\n            }\n        );\n\n        if (options.UsePrometheusExporter)\n        {\n            // export application metrics in `/metrics` endpoint and should scrape in the Prometheus config file and `scrape_configs`\n            // https://github.com/open-telemetry/opentelemetry-dotnet/tree/e330e57b04fa3e51fe5d63b52bfff891fb5b7961/src/OpenTelemetry.Exporter.Prometheus.AspNetCore\n            app.UseOpenTelemetryPrometheusScrapingEndpoint(); // http://localhost:4000/metrics\n        }\n\n        return app;\n    }\n\n    private static void AddTracingExporter(ObservabilityOptions observabilityOptions, TracerProviderBuilder tracing)\n    {\n        if (observabilityOptions.UseJaegerExporter)\n        {\n            ArgumentNullException.ThrowIfNull(observabilityOptions.JaegerOptions);\n            // https://github.com/open-telemetry/opentelemetry-dotnet/tree/e330e57b04fa3e51fe5d63b52bfff891fb5b7961/docs/trace/getting-started-jaeger\n            // `OpenTelemetry.Exporter.Jaeger` package and `AddJaegerExporter` to use Http endpoint (http://localhost:14268/api/traces) is deprecated, and we should use `OpenTelemetry.Exporter.OpenTelemetryProtocol` and `AddOtlpExporter` with OTLP port `4317` on Jaeger\n            // tracing.AddJaegerExporter(\n            //     x => x.Endpoint = new Uri(observabilityOptions.JaegerOptions.HttpExporterEndpoint)); // http://localhost:14268/api/traces\n            tracing.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.JaegerOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseZipkinExporter)\n        {\n            ArgumentNullException.ThrowIfNull(observabilityOptions.ZipkinOptions);\n            // https://github.com/open-telemetry/opentelemetry-dotnet/tree/e330e57b04fa3e51fe5d63b52bfff891fb5b7961/src/OpenTelemetry.Exporter.Zipkin\n            tracing.AddZipkinExporter(x =>\n                x.Endpoint = new Uri(observabilityOptions.ZipkinOptions.HttpExporterEndpoint)\n            ); // \"http://localhost:9411/api/v2/spans\"\n        }\n\n        if (observabilityOptions.UseConsoleExporter)\n        {\n            tracing.AddConsoleExporter();\n        }\n\n        if (observabilityOptions.UseOTLPExporter)\n        {\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            tracing.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.OTLPOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseAspireOTLPExporter)\n        {\n            // we can just one `AddOtlpExporter` and in development use `aspire-dashboard` OTLP endpoint address as `OTLPExporterEndpoint` and in production we can use `otel-collector` OTLP endpoint address\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            tracing.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.AspireDashboardOTLPOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseGrafanaExporter)\n        {\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/docs/configuration.md#aspnet-core\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/docs/configuration.md#sending-to-an-agent-or-collector-via-otlp\n            // https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/instrument/dotnet/\n            tracing.UseGrafana();\n        }\n    }\n\n    private static void AddMetricsExporter(ObservabilityOptions observabilityOptions, MeterProviderBuilder metrics)\n    {\n        if (observabilityOptions.UsePrometheusExporter)\n        {\n            // https://github.com/open-telemetry/opentelemetry-dotnet/tree/e330e57b04fa3e51fe5d63b52bfff891fb5b7961/src/OpenTelemetry.Exporter.Prometheus.AspNetCore\n            // for exporting app metrics to `/metrics` endpoint\n            metrics.AddPrometheusExporter(o => o.DisableTotalNameSuffixForCounters = true); // http://localhost:4000/metrics\n        }\n\n        if (observabilityOptions.UseConsoleExporter)\n        {\n            metrics.AddConsoleExporter();\n        }\n\n        if (observabilityOptions.UseOTLPExporter)\n        {\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            metrics.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.OTLPOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseAspireOTLPExporter)\n        {\n            // we can just one `AddOtlpExporter` and in development use `aspire-dashboard` OTLP endpoint address as `OTLPExporterEndpoint` and in production we can use `otel-collector` OTLP endpoint address\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            metrics.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.AspireDashboardOTLPOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseGrafanaExporter)\n        {\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/docs/configuration.md#aspnet-core\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/docs/configuration.md#sending-to-an-agent-or-collector-via-otlp\n            // https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/instrument/dotnet/\n            metrics.UseGrafana();\n        }\n    }\n\n    private static void AddLoggingExporters(\n        this OpenTelemetryLoggerOptions openTelemetryLoggerOptions,\n        ObservabilityOptions observabilityOptions\n    )\n    {\n        if (observabilityOptions.UseOTLPExporter)\n        {\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            openTelemetryLoggerOptions.AddOtlpExporter(options =>\n            {\n                options.Endpoint = new Uri(observabilityOptions.OTLPOptions.OTLPGrpcExporterEndpoint);\n                options.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseAspireOTLPExporter)\n        {\n            // we can just one `AddOtlpExporter` and in development use `aspire-dashboard` OTLP endpoint address as `OTLPExporterEndpoint` and in production we can use `otel-collector` OTLP endpoint address\n            ArgumentNullException.ThrowIfNull(observabilityOptions.OTLPOptions);\n            openTelemetryLoggerOptions.AddOtlpExporter(x =>\n            {\n                x.Endpoint = new Uri(observabilityOptions.AspireDashboardOTLPOptions.OTLPGrpcExporterEndpoint);\n                x.Protocol = OtlpExportProtocol.Grpc;\n            });\n        }\n\n        if (observabilityOptions.UseGrafanaExporter)\n        {\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/\n            // https://github.com/grafana/grafana-opentelemetry-dotnet/blob/main/docs/configuration.md#aspnet-core\n            // https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/instrument/dotnet/\n            openTelemetryLoggerOptions.UseGrafana();\n        }\n\n        if (observabilityOptions.UseConsoleExporter)\n        {\n            openTelemetryLoggerOptions.AddConsoleExporter();\n        }\n    }\n\n    private static WebApplicationBuilder AddCoreDiagnostics(this WebApplicationBuilder builder)\n    {\n        builder.Services.AddTransient<CommandHandlerActivity>();\n        builder.Services.AddTransient<CommandHandlerMetrics>();\n        builder.Services.AddTransient<QueryHandlerActivity>();\n        builder.Services.AddTransient<QueryHandlerMetrics>();\n\n        return builder;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/ObservabilityConstant.cs",
    "content": "namespace BuildingBlocks.OpenTelemetryCollector;\n\npublic static class ObservabilityConstant\n{\n    public static string InstrumentationName = default!;\n\n    public static class Components\n    {\n        public const string CommandHandler = \"CommandHandler\";\n        public const string QueryHandler = \"QueryHandler\";\n        public const string EventStore = \"EventStore\";\n        public const string Producer = \"Producer\";\n        public const string Consumer = \"Consumer\";\n        public const string EventHandler = \"EventHandler\";\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/ObservabilityOptions.cs",
    "content": "namespace BuildingBlocks.OpenTelemetryCollector;\n\npublic class ObservabilityOptions\n{\n    public string InstrumentationName { get; set; } = default!;\n    public string? ServiceName { get; set; }\n    public bool MetricsEnabled { get; set; } = true;\n    public bool TracingEnabled { get; set; } = true;\n    public bool LoggingEnabled { get; set; } = true;\n    public bool UsePrometheusExporter { get; set; } = true;\n    public bool UseOTLPExporter { get; set; } = true;\n    public bool UseAspireOTLPExporter { get; set; } = true;\n    public bool UseGrafanaExporter { get; set; }\n    public bool UseConsoleExporter { get; set; }\n    public bool UseJaegerExporter { get; set; }\n    public bool UseZipkinExporter { get; set; }\n    public ZipkinOptions ZipkinOptions { get; set; } = default!;\n    public JaegerOptions JaegerOptions { get; set; } = default!;\n    public OTLPOptions OTLPOptions { get; set; } = default!;\n    public AspireDashboardOTLPOptions AspireDashboardOTLPOptions { get; set; } = default!;\n}\n\n// https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Zipkin/README.md\npublic class ZipkinOptions\n{\n    /// <summary>\n    /// Gets or sets endpoint address to receive telemetry\n    /// </summary>\n    public string HttpExporterEndpoint { get; set; } = \"http://localhost:9411/api/v2/spans\";\n}\n\npublic class JaegerOptions\n{\n    public string OTLPGrpcExporterEndpoint { get; set; } = \"http://localhost:14317\";\n    public string HttpExporterEndpoint { get; set; } = \"http://localhost:14268/api/traces\";\n}\n\npublic class OTLPOptions\n{\n    public string OTLPGrpcExporterEndpoint { get; set; } = \"http://localhost:4317\";\n    public string OTLPHttpExporterEndpoint { get; set; } = \"http://localhost:4318\";\n}\n\npublic class AspireDashboardOTLPOptions\n{\n    public string OTLPGrpcExporterEndpoint { get; set; } = \"http://localhost:4319\";\n}"
  },
  {
    "path": "src/BuildingBlocks/OpenTelemetryCollector/TelemetryTags.cs",
    "content": "namespace BuildingBlocks.OpenTelemetryCollector;\n\n/// <summary>\n/// Telemetry tags use for adding tags to activities as tag name\n/// </summary>\npublic static class TelemetryTags\n{\n    // https://opentelemetry.io/docs/specs/semconv/general/trace/\n    // https://opentelemetry.io/docs/specs/semconv/general/attribute-naming/\n    public static class Tracing\n    {\n        // https://opentelemetry.io/docs/specs/semconv/resource/#service\n        // https://opentelemetry.io/docs/specs/semconv/attributes-registry/peer/#peer-attributes\n        public static class Service\n        {\n            public const string PeerService = \"peer.service\";\n            public const string Name = \"service.name\";\n            public const string InstanceId = \"service.instance.id\";\n            public const string Version = \"service.version\";\n            public const string NameSpace = \"service.namespace\";\n        }\n\n        // https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging/#general-messaging-attributes\n        // https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/\n        public static class Messaging\n        {\n            // https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging/#messaging-operation-type\n            public static class OperationType\n            {\n                public const string Key = \"messaging.operation.type\";\n                public const string Receive = \"receive\";\n                public const string Send = \"send\";\n                public const string Process = \"process\";\n            }\n\n            // https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging/#messaging-system\n            public static class System\n            {\n                public const string Key = \"messaging.system\";\n                public const string ActiveMQ = \"activemq\";\n                public const string RabbitMQ = \"rabbitmq\";\n                public const string AwsSqs = \"aws_sqs\";\n                public const string EventGrid = \"eventgrid\";\n                public const string EventHubs = \"eventhubs\";\n                public const string GcpPubSub = \"gcp_pubsub\";\n                public const string Kafka = \"kafka\";\n                public const string Pulsar = \"pulsar\";\n                public const string ServiceBus = \"servicebus\";\n            }\n\n            public const string Destination = \"messaging.destination\";\n            public const string DestinationKind = \"messaging.destination_kind\";\n            public const string Url = \"messaging.url\";\n            public const string MessageId = \"messaging.message_id\";\n            public const string ConversationId = \"messaging.conversation_id\";\n            public const string CorrelationId = \"messaging.correlation_id\";\n            public const string CausationId = \"messaging.causation_id\";\n            public const string Operation = \"messaging.operation\";\n            public const string OperationName = \"messaging.operation.name\";\n            public const string DestinationName = \"messaging.destination.name\";\n            public const string ConsumerGroup = \"messaging.consumer.group.name\";\n            public const string DestinationPartition = \"messaging.destination.partition.id\";\n\n            // https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging/#rabbitmq-attributes\n            // https://opentelemetry.io/docs/specs/semconv/messaging/rabbitmq/\n            public static class RabbitMQ\n            {\n                public const string RoutingKey = \"messaging.rabbitmq.destination.routing_key\";\n                public const string DeliveryTag = \"messaging.rabbitmq.message.delivery_tag\";\n\n                public static IDictionary<string, object?> ProducerTags(\n                    string serviceName,\n                    string topicName,\n                    string routingKey,\n                    string? deliveryTag = null\n                ) =>\n                    new Dictionary<string, object?>\n                    {\n                        { System.Key, System.Kafka },\n                        { DeliveryTag, deliveryTag },\n                        { Destination, topicName },\n                        { OperationType.Key, OperationType.Send },\n                        { Service.Name, serviceName },\n                        { RoutingKey, routingKey },\n                    };\n\n                public static IDictionary<string, object?> ConsumerTags(\n                    string serviceName,\n                    string topicName,\n                    string routingKey,\n                    string? consumerGroup = null\n                ) =>\n                    new Dictionary<string, object?>\n                    {\n                        { System.Key, System.Kafka },\n                        { Destination, topicName },\n                        { OperationType.Key, OperationType.Receive },\n                        { Service.Name, serviceName },\n                        { ConsumerGroup, consumerGroup },\n                        { RoutingKey, routingKey },\n                    };\n            }\n\n            // https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging/#kafka-attributes\n            // https://opentelemetry.io/docs/specs/semconv/messaging/kafka/\n            public static class Kafka\n            {\n                public const string MessageKey = \"messaging.kafka.message.key\";\n                public const string Tombstone = \"messaging.kafka.message.tombstone\";\n                public const string Offset = \"messaging.kafka.offset\";\n\n                public static IDictionary<string, object?> ProducerTags(\n                    string serviceName,\n                    string topicName,\n                    string messageKey\n                ) =>\n                    new Dictionary<string, object?>\n                    {\n                        { System.Key, System.Kafka },\n                        { Destination, topicName },\n                        { OperationType.Key, OperationType.Send },\n                        { Service.Name, serviceName },\n                        { MessageKey, messageKey },\n                    };\n\n                public static IDictionary<string, object?> ConsumerTags(\n                    string serviceName,\n                    string topicName,\n                    string messageKey,\n                    string partitionName,\n                    string consumerGroup\n                ) =>\n                    new Dictionary<string, object?>\n                    {\n                        { System.Key, System.Kafka },\n                        { Destination, topicName },\n                        { OperationType.Key, OperationType.Receive },\n                        { Service.Name, serviceName },\n                        { MessageKey, messageKey },\n                        { DestinationPartition, partitionName },\n                        { ConsumerGroup, consumerGroup },\n                    };\n            }\n        }\n\n        // https://opentelemetry.io/docs/specs/semconv/database/database-spans/#common-attributes\n        // https://opentelemetry.io/docs/specs/semconv/database/postgresql/#attributes\n        public static class Db\n        {\n            public const string System = \"db.system\";\n            public const string ConnectionString = \"db.connection_string\";\n            public const string User = \"db.user\";\n            public const string MsSqlInstanceName = \"db.mssql.instance_name\";\n            public const string Name = \"db.name\";\n            public const string Statement = \"db.statement\";\n            public const string Operation = \"db.operation\";\n            public const string Instance = \"db.instance\";\n            public const string Url = \"db.url\";\n            public const string CassandraKeyspace = \"db.cassandra.keyspace\";\n            public const string RedisDatabaseIndex = \"db.redis.database_index\";\n            public const string MongoDbCollection = \"db.mongodb.collection\";\n        }\n\n        // https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#exception-event\n        public static class Exception\n        {\n            public const string EventName = \"exception\";\n            public const string Type = \"exception.type\";\n            public const string Message = \"exception.message\";\n            public const string Stacktrace = \"exception.stacktrace\";\n        }\n\n        // https://opentelemetry.io/docs/specs/semconv/attributes-registry/otel/#otel-attributes\n        public static class Otel\n        {\n            public const string StatusCode = \"otel.status_code\";\n            public const string StatusDescription = \"otel.status_description\";\n        }\n\n        public static class Message\n        {\n            public const string Type = \"message.type\";\n            public const string Id = \"message.id\";\n        }\n\n        public static class Application\n        {\n            public static string AppService = $\"{ObservabilityConstant.InstrumentationName}.appservice\";\n            public static string Consumer = $\"{ObservabilityConstant.InstrumentationName}.consumer\";\n            public static string Producer = $\"{ObservabilityConstant.InstrumentationName}.producer\";\n\n            public static class Commands\n            {\n                public static string Command = $\"{ObservabilityConstant.InstrumentationName}.command\";\n                public static string CommandType = $\"{Command}.type\";\n                public static string CommandHandler = $\"{Command}.handler\";\n                public static string CommandHandlerType = $\"{CommandHandler}.type\";\n            }\n\n            public static class Queries\n            {\n                public static string Query = $\"{ObservabilityConstant.InstrumentationName}.query\";\n                public static string QueryType = $\"{Query}.type\";\n                public static string QueryHandler = $\"{Query}.handler\";\n                public static string QueryHandlerType = $\"{QueryHandler}.type\";\n            }\n\n            public static class Events\n            {\n                public static string Event = $\"{ObservabilityConstant.InstrumentationName}.event\";\n                public static string EventType = $\"{Event}.type\";\n                public static string EventHandler = $\"{Event}.handler\";\n                public static string EventHandlerType = $\"{EventHandler}.type\";\n            }\n        }\n    }\n\n    // https://opentelemetry.io/docs/specs/semconv/general/metrics/\n    // https://opentelemetry.io/docs/specs/semconv/general/attribute-naming/\n    public static class Metrics\n    {\n        public static class Application\n        {\n            public static string AppService = $\"{ObservabilityConstant.InstrumentationName}.appservice\";\n            public static string Consumer = $\"{ObservabilityConstant.InstrumentationName}.consumer\";\n            public static string Producer = $\"{ObservabilityConstant.InstrumentationName}.producer\";\n\n            public static class Commands\n            {\n                public static string Command = $\"{ObservabilityConstant.InstrumentationName}.command\";\n                public static string CommandType = $\"{Command}.type\";\n                public static string CommandHandler = $\"{Command}.handler\";\n                public static string SuccessCount = $\"{CommandHandler}.success.count\";\n                public static string FaildCount = $\"{CommandHandler}.failed.count\";\n                public static string ActiveCount = $\"{CommandHandler}.active.count\";\n                public static string TotalExecutedCount = $\"{CommandHandler}.total.count\";\n                public static string HandlerDuration = $\"{CommandHandler}.duration\";\n            }\n\n            public static class Queries\n            {\n                public static string Query = $\"{ObservabilityConstant.InstrumentationName}.query\";\n                public static string QueryType = $\"{Query}.type\";\n                public static string QueryHandler = $\"{Query}.handler\";\n                public static string SuccessCount = $\"{QueryHandler}.success.count\";\n                public static string FaildCount = $\"{QueryHandler}.failed.count\";\n                public static string ActiveCount = $\"{QueryHandler}.active.count\";\n                public static string TotalExecutedCount = $\"{QueryHandler}.total.count\";\n                public static string HandlerDuration = $\"{QueryHandler}.duration\";\n            }\n\n            public static class Events\n            {\n                public static string Event = $\"{ObservabilityConstant.InstrumentationName}.event\";\n                public static string EventType = $\"{Event}.type\";\n                public static string EventHandler = $\"{Event}.handler\";\n                public static string SuccessCount = $\"{EventHandler}.success.count\";\n                public static string FaildCount = $\"{EventHandler}.failed.count\";\n                public static string ActiveCount = $\"{EventHandler}.active.count\";\n                public static string TotalExecutedCount = $\"{EventHandler}.total.count\";\n                public static string HandlerDuration = $\"{EventHandler}.duration\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/Extensions.cs",
    "content": "using BuildingBlocks.Web;\nusing Humanizer;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\npublic static class Extensions\n{\n    public static IServiceCollection AddPersistMessageProcessor(this WebApplicationBuilder builder, string? connectionName = \"persist-message\")\n    {\n        AppContext.SetSwitch(\"Npgsql.EnableLegacyTimestampBehavior\", true);\n\n        builder.Services.AddValidateOptions<PersistMessageOptions>();\n\n        builder.Services.AddDbContext<PersistMessageDbContext>(\n            (sp, options) =>\n            {\n                var aspireConnectionString = builder.Configuration.GetConnectionString(connectionName.Kebaberize());\n\n                var connectionString = aspireConnectionString ?? sp.GetRequiredService<PersistMessageOptions>().ConnectionString;\n\n                ArgumentException.ThrowIfNullOrEmpty(connectionString);\n\n                options.UseNpgsql(\n                        connectionString,\n                        dbOptions =>\n                        {\n                            dbOptions.MigrationsAssembly(\n                                typeof(PersistMessageDbContext).Assembly.GetName().Name);\n                        })\n                    // https://github.com/efcore/EFCore.NamingConventions\n                    .UseSnakeCaseNamingConvention();\n\n                // Todo: follow up the issues of .net 9 to use better approach taht will provide by .net!\n                options.ConfigureWarnings(\n                    w => w.Ignore(RelationalEventId.PendingModelChangesWarning));\n            });\n\n        builder.Services.AddScoped<IPersistMessageDbContext>(\n            provider =>\n            {\n                var persistMessageDbContext =\n                    provider.GetRequiredService<PersistMessageDbContext>();\n\n                persistMessageDbContext.Database.EnsureCreated();\n                persistMessageDbContext.CreatePersistMessageTableIfNotExists();\n\n                return persistMessageDbContext;\n            });\n\n        builder.Services.AddScoped<IPersistMessageProcessor, PersistMessageProcessor>();\n\n        builder.Services.AddHostedService<PersistMessageBackgroundService>();\n\n        return builder.Services;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/IPersistMessageDbContext.cs",
    "content": "using Microsoft.EntityFrameworkCore;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\npublic interface IPersistMessageDbContext\n{\n    DbSet<PersistMessage> PersistMessage { get; }\n    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);\n    Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/IPersistMessageProcessor.cs",
    "content": "using System.Linq.Expressions;\nusing BuildingBlocks.Core.Event;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\n// Ref: http://www.kamilgrzybek.com/design/the-outbox-pattern/\n// Ref: https://event-driven.io/en/outbox_inbox_patterns_and_delivery_guarantees_explained/\n// Ref: https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/\n// Ref: https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus\n// Ref: https://github.com/kgrzybek/modular-monolith-with-ddd#38-internal-processing\npublic interface IPersistMessageProcessor\n{\n    Task PublishMessageAsync<TMessageEnvelope>(\n        TMessageEnvelope messageEnvelope,\n        CancellationToken cancellationToken = default)\n        where TMessageEnvelope : MessageEnvelope;\n\n    Task<Guid> AddReceivedMessageAsync<TMessageEnvelope>(\n        TMessageEnvelope messageEnvelope,\n        CancellationToken cancellationToken = default)\n        where TMessageEnvelope : MessageEnvelope;\n\n    Task AddInternalMessageAsync<TCommand>(\n        TCommand internalCommand,\n        CancellationToken cancellationToken = default)\n        where TCommand : class, IInternalCommand;\n\n    Task<IReadOnlyList<PersistMessage>> GetByFilterAsync(\n        Expression<Func<PersistMessage, bool>> predicate,\n        CancellationToken cancellationToken = default);\n\n    Task<PersistMessage> ExistMessageAsync(\n        Guid messageId,\n        CancellationToken cancellationToken = default);\n\n    Task ProcessInboxAsync(\n        Guid messageId,\n        CancellationToken cancellationToken = default);\n\n    Task ProcessAsync(Guid messageId, MessageDeliveryType deliveryType, CancellationToken cancellationToken = default);\n\n    Task ProcessAllAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/MessageDeliveryType.cs",
    "content": "namespace BuildingBlocks.PersistMessageProcessor;\n\n[Flags]\npublic enum MessageDeliveryType\n{\n    Unknown = 0,\n    Outbox = 1,\n    Inbox = 2,\n    Internal = 3\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/MessageStatus.cs",
    "content": "namespace BuildingBlocks.PersistMessageProcessor;\n\npublic enum MessageStatus\n{\n    Unknown = 0,\n    InProgress = 1,\n    Processed = 2\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/PersistMessage.cs",
    "content": "using BuildingBlocks.Core.Model;\nnamespace BuildingBlocks.PersistMessageProcessor;\n\n\npublic class PersistMessage : IVersion\n{\n    public PersistMessage(Guid id, string dataType, string data, MessageDeliveryType deliveryType)\n    {\n        Id = id;\n        DataType = dataType;\n        Data = data;\n        DeliveryType = deliveryType;\n        Created = DateTime.Now;\n        MessageStatus = MessageStatus.InProgress;\n        RetryCount = 0;\n    }\n\n    public Guid Id { get; private set; }\n    public string DataType { get; private set; }\n    public string Data { get; private set; }\n    public DateTime Created { get; private set; }\n    public int RetryCount { get; private set; }\n    public MessageStatus MessageStatus { get; private set; }\n    public MessageDeliveryType DeliveryType { get; private set; }\n    public long Version { get; set; }\n\n    public void ChangeState(MessageStatus messageStatus)\n    {\n        MessageStatus = messageStatus;\n    }\n\n    public void IncreaseRetry()\n    {\n        RetryCount++;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/PersistMessageBackgroundService.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\npublic class PersistMessageBackgroundService(\n    ILogger<PersistMessageBackgroundService> logger,\n    IServiceProvider serviceProvider,\n    IOptions<PersistMessageOptions> options\n)\n    : BackgroundService\n{\n    private PersistMessageOptions _options = options.Value;\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        logger.LogInformation(\"PersistMessage Background Service Start\");\n\n        await ProcessAsync(stoppingToken);\n    }\n\n    public override Task StopAsync(CancellationToken cancellationToken)\n    {\n        logger.LogInformation(\"PersistMessage Background Service Stop\");\n\n        return base.StopAsync(cancellationToken);\n    }\n\n    private async Task ProcessAsync(CancellationToken stoppingToken)\n    {\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            await using (var scope = serviceProvider.CreateAsyncScope())\n            {\n                var service = scope.ServiceProvider.GetRequiredService<IPersistMessageProcessor>();\n                await service.ProcessAllAsync(stoppingToken);\n            }\n\n            var delay = _options.Interval is { }\n                            ? TimeSpan.FromSeconds((int)_options.Interval)\n                            : TimeSpan.FromSeconds(30);\n\n            await Task.Delay(delay, stoppingToken);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/PersistMessageDbContext.cs",
    "content": "using BuildingBlocks.Core.Model;\nusing BuildingBlocks.EFCore;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\nusing IsolationLevel = System.Data.IsolationLevel;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\npublic class PersistMessageDbContext : DbContext, IPersistMessageDbContext\n{\n    private readonly ILogger<PersistMessageDbContext>? _logger;\n\n    public PersistMessageDbContext(DbContextOptions<PersistMessageDbContext> options,\n        ILogger<PersistMessageDbContext>? logger = null)\n        : base(options)\n    {\n        _logger = logger;\n    }\n\n    public DbSet<PersistMessage> PersistMessage => Set<PersistMessage>();\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        base.OnModelCreating(builder);\n        builder.ToSnakeCaseTables();\n    }\n\n    //ref: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency#execution-strategies-and-transactions\n    public Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default)\n    {\n        var strategy = Database.CreateExecutionStrategy();\n        return strategy.ExecuteAsync(async () =>\n        {\n            await using var transaction =\n                await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken);\n            try\n            {\n                await SaveChangesAsync(cancellationToken);\n                await transaction.CommitAsync(cancellationToken);\n            }\n            catch\n            {\n                await transaction.RollbackAsync(cancellationToken);\n                throw;\n            }\n        });\n    }\n\n    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)\n    {\n        OnBeforeSaving();\n\n        try\n        {\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n        //ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=data-annotations#resolving-concurrency-conflicts\n        catch (DbUpdateConcurrencyException ex)\n        {\n            foreach (var entry in ex.Entries)\n            {\n                var databaseValues = await entry.GetDatabaseValuesAsync(cancellationToken);\n\n                if (databaseValues == null)\n                {\n                    _logger.LogError(\"The record no longer exists in the database, The record has been deleted by another user.\");\n                    throw;\n                }\n\n                // Refresh the original values to bypass next concurrency check\n                entry.OriginalValues.SetValues(databaseValues);\n            }\n\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n    }\n\n    public void CreatePersistMessageTableIfNotExists()\n    {\n        string createTableSql = @\"\n            create table if not exists persist_message (\n            id uuid not null,\n            data_type text,\n            data text,\n            created timestamp with time zone not null,\n            retry_count integer not null,\n            message_status text not null default 'InProgress'::text,\n            delivery_type text not null default 'Outbox'::text,\n            version bigint not null,\n            constraint pk_persist_message primary key (id)\n            )\";\n\n        Database.ExecuteSqlRaw(createTableSql);\n    }\n\n    private void OnBeforeSaving()\n    {\n        try\n        {\n            foreach (var entry in ChangeTracker.Entries<IVersion>())\n            {\n                switch (entry.State)\n                {\n                    case EntityState.Modified:\n                        entry.Entity.Version++;\n                        break;\n\n                    case EntityState.Deleted:\n                        entry.Entity.Version++;\n                        break;\n                }\n            }\n        }\n        catch (System.Exception ex)\n        {\n            throw new System.Exception(\"try for find IVersion\", ex);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/PersistMessageOptions.cs",
    "content": "namespace BuildingBlocks.PersistMessageProcessor;\n\npublic class PersistMessageOptions\n{\n    public int? Interval { get; set; } = 30;\n    public bool Enabled { get; set; } = true;\n    public string? ConnectionString { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/PersistMessageProcessor/PersistMessageProcessor.cs",
    "content": "using System.Linq.Expressions;\nusing System.Text.Json;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Utils;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.PersistMessageProcessor;\n\nusing Microsoft.EntityFrameworkCore;\n\npublic class PersistMessageProcessor : IPersistMessageProcessor\n{\n    private readonly ILogger<PersistMessageProcessor> _logger;\n    private readonly IMediator _mediator;\n    private readonly IPersistMessageDbContext _persistMessageDbContext;\n    private readonly IPublishEndpoint _publishEndpoint;\n    public PersistMessageProcessor(\n        ILogger<PersistMessageProcessor> logger,\n        IMediator mediator,\n        IPersistMessageDbContext persistMessageDbContext,\n        IPublishEndpoint publishEndpoint)\n    {\n        _logger = logger;\n        _mediator = mediator;\n        _persistMessageDbContext = persistMessageDbContext;\n        _publishEndpoint = publishEndpoint;\n    }\n\n    public async Task PublishMessageAsync<TMessageEnvelope>(\n        TMessageEnvelope messageEnvelope,\n        CancellationToken cancellationToken = default)\n        where TMessageEnvelope : MessageEnvelope\n    {\n        await SavePersistMessageAsync(messageEnvelope, MessageDeliveryType.Outbox, cancellationToken);\n    }\n\n    public Task<Guid> AddReceivedMessageAsync<TMessageEnvelope>(TMessageEnvelope messageEnvelope,\n        CancellationToken cancellationToken = default) where TMessageEnvelope : MessageEnvelope\n    {\n        return SavePersistMessageAsync(messageEnvelope, MessageDeliveryType.Inbox, cancellationToken);\n    }\n\n    public async Task AddInternalMessageAsync<TCommand>(TCommand internalCommand,\n        CancellationToken cancellationToken = default) where TCommand : class, IInternalCommand\n    {\n        await SavePersistMessageAsync(new MessageEnvelope(internalCommand), MessageDeliveryType.Internal,\n            cancellationToken);\n    }\n\n    public async Task<IReadOnlyList<PersistMessage>> GetByFilterAsync(Expression<Func<PersistMessage, bool>> predicate,\n        CancellationToken cancellationToken = default)\n    {\n        return (await _persistMessageDbContext.PersistMessage.Where(predicate).ToListAsync(cancellationToken))\n            .AsReadOnly();\n    }\n\n    public Task<PersistMessage> ExistMessageAsync(Guid messageId, CancellationToken cancellationToken = default)\n    {\n        return _persistMessageDbContext.PersistMessage.FirstOrDefaultAsync(x =>\n                x.Id == messageId &&\n                x.DeliveryType == MessageDeliveryType.Inbox &&\n                x.MessageStatus == MessageStatus.Processed,\n            cancellationToken);\n    }\n\n    public async Task ProcessAsync(\n        Guid messageId,\n        MessageDeliveryType deliveryType,\n        CancellationToken cancellationToken = default)\n    {\n        var message =\n            await _persistMessageDbContext.PersistMessage.FirstOrDefaultAsync(\n                x => x.Id == messageId && x.DeliveryType == deliveryType, cancellationToken);\n\n        if (message is null)\n            return;\n\n        switch (deliveryType)\n        {\n            case MessageDeliveryType.Internal:\n                var sentInternalMessage = await ProcessInternalAsync(message, cancellationToken);\n                if (sentInternalMessage)\n                {\n                    await ChangeMessageStatusAsync(message, cancellationToken);\n                    break;\n                }\n                else\n                {\n                    return;\n                }\n\n            case MessageDeliveryType.Outbox:\n                var sentOutbox = await ProcessOutboxAsync(message, cancellationToken);\n                if (sentOutbox)\n                {\n                    await ChangeMessageStatusAsync(message, cancellationToken);\n                    break;\n                }\n                else\n                {\n                    return;\n                }\n        }\n    }\n\n    public async Task ProcessAllAsync(CancellationToken cancellationToken = default)\n    {\n        var messages = await _persistMessageDbContext.PersistMessage\n            .Where(x => x.MessageStatus != MessageStatus.Processed)\n            .ToListAsync(cancellationToken);\n\n        foreach (var message in messages)\n        {\n            await ProcessAsync(message.Id, message.DeliveryType, cancellationToken);\n        }\n    }\n\n    public async Task ProcessInboxAsync(Guid messageId, CancellationToken cancellationToken = default)\n    {\n        var message = await _persistMessageDbContext.PersistMessage.FirstOrDefaultAsync(\n            x => x.Id == messageId &&\n                 x.DeliveryType == MessageDeliveryType.Inbox &&\n                 x.MessageStatus == MessageStatus.InProgress,\n            cancellationToken);\n\n        await ChangeMessageStatusAsync(message, cancellationToken);\n    }\n\n    private async Task<bool> ProcessOutboxAsync(PersistMessage message, CancellationToken cancellationToken)\n    {\n        var messageEnvelope = JsonSerializer.Deserialize<MessageEnvelope>(message.Data);\n\n        if (messageEnvelope is null || messageEnvelope.Message is null)\n            return false;\n\n        var data = JsonSerializer.Deserialize(messageEnvelope.Message.ToString() ?? string.Empty,\n            TypeProvider.GetFirstMatchingTypeFromCurrentDomainAssembly(message.DataType) ?? typeof(object));\n\n        if (data is not IEvent)\n            return false;\n\n        await _publishEndpoint.Publish(data, context =>\n        {\n            foreach (var header in messageEnvelope.Headers)\n                context.Headers.Set(header.Key, header.Value);\n        }, cancellationToken);\n\n        _logger.LogInformation(\n            \"Message with id: {MessageId} and delivery type: {DeliveryType} processed from the persistence message store.\",\n            message.Id,\n            message.DeliveryType);\n\n        return true;\n    }\n\n    private async Task<bool> ProcessInternalAsync(PersistMessage message, CancellationToken cancellationToken)\n    {\n        var messageEnvelope = JsonSerializer.Deserialize<MessageEnvelope>(message.Data);\n\n        if (messageEnvelope is null || messageEnvelope.Message is null)\n            return false;\n\n        var data = JsonSerializer.Deserialize(messageEnvelope.Message.ToString() ?? string.Empty,\n            TypeProvider.GetFirstMatchingTypeFromCurrentDomainAssembly(message.DataType) ?? typeof(object));\n\n        if (data is not IInternalCommand internalCommand)\n            return false;\n\n        await _mediator.Send(internalCommand, cancellationToken);\n\n        _logger.LogInformation(\n            \"InternalCommand with id: {EventID} and delivery type: {DeliveryType} processed from the persistence message store.\",\n            message.Id,\n            message.DeliveryType);\n\n        return true;\n    }\n\n    private async Task<Guid> SavePersistMessageAsync(\n        MessageEnvelope messageEnvelope,\n        MessageDeliveryType deliveryType,\n        CancellationToken cancellationToken = default)\n    {\n        Guard.Against.Null(messageEnvelope.Message, nameof(messageEnvelope.Message));\n\n        Guid id;\n        if (messageEnvelope.Message is IEvent message)\n            id = message.EventId;\n        else\n            id = NewId.NextGuid();\n\n        await _persistMessageDbContext.PersistMessage.AddAsync(\n            new PersistMessage(\n                id,\n                messageEnvelope.Message.GetType().ToString(),\n                JsonSerializer.Serialize(messageEnvelope),\n                deliveryType),\n            cancellationToken);\n\n        await _persistMessageDbContext.SaveChangesAsync(cancellationToken);\n\n        _logger.LogInformation(\n            \"Message with id: {MessageID} and delivery type: {DeliveryType} saved in persistence message store.\",\n            id,\n            deliveryType.ToString());\n\n        return id;\n    }\n\n    private async Task ChangeMessageStatusAsync(PersistMessage message, CancellationToken cancellationToken)\n    {\n        message.ChangeState(MessageStatus.Processed);\n\n        _persistMessageDbContext.PersistMessage.Update(message);\n\n        await _persistMessageDbContext.SaveChangesAsync(cancellationToken);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Polly/Extensions.cs",
    "content": "using Microsoft.Extensions.Logging;\n\nnamespace BuildingBlocks.Polly;\n\nusing global::Polly;\nusing Exception = System.Exception;\n\npublic static class Extensions\n{\n    public static ILogger Logger { get; set; } = null!;\n\n    public static T RetryOnFailure<T>(this object retrySource, Func<T> action, int retryCount = 3)\n    {\n        var retryPolicy = Policy\n            .Handle<Exception>()\n            .Retry(retryCount, (exception, retryAttempt, context) =>\n                               {\n                                   Logger.LogInformation($\"Retry attempt: {retryAttempt}\");\n                                   Logger.LogError($\"Exception: {exception.Message}\");\n                               });\n\n        return retryPolicy.Execute(action);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/ProblemDetails/Extensions.cs",
    "content": "namespace BuildingBlocks.ProblemDetails;\n\nusing Exception;\nusing Grpc.Core;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Diagnostics;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.WebUtilities;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\npublic static class Extensions\n{\n    public static WebApplication UseCustomProblemDetails(this WebApplication app)\n    {\n        app.UseStatusCodePages(statusCodeHandlerApp =>\n        {\n            statusCodeHandlerApp.Run(async context =>\n            {\n                context.Response.ContentType = \"application/problem+json\";\n\n                if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)\n                {\n                    await problemDetailsService.WriteAsync(new ProblemDetailsContext\n                    {\n                        HttpContext = context,\n                        ProblemDetails =\n                        {\n                            Detail = ReasonPhrases.GetReasonPhrase(context.Response.StatusCode),\n                            Status = context.Response.StatusCode\n                        }\n                    });\n                }\n            });\n        });\n\n        app.UseExceptionHandler(exceptionHandlerApp =>\n        {\n            exceptionHandlerApp.Run(async context =>\n            {\n                context.Response.ContentType = \"application/problem+json\";\n\n                if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)\n                {\n                    var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();\n                    var exceptionType = exceptionHandlerFeature?.Error;\n\n                    if (exceptionType is not null)\n                    {\n                        (string Detail, string Title, int StatusCode) details = exceptionType switch\n                        {\n                            ConflictException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status409Conflict\n                            ),\n                            ValidationException validationException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = (int)validationException.StatusCode\n                            ),\n                            BadRequestException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status400BadRequest\n                            ),\n                            NotFoundException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status404NotFound\n                            ),\n                            AppException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status400BadRequest\n                            ),\n                            DbUpdateConcurrencyException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status409Conflict\n                            ),\n                            RpcException =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status400BadRequest\n                            ),\n                            _ =>\n                            (\n                                exceptionType.Message,\n                                exceptionType.GetType().Name,\n                                context.Response.StatusCode = StatusCodes.Status500InternalServerError\n                            )\n                        };\n\n                        var problem = new ProblemDetailsContext\n                        {\n                            HttpContext = context,\n                            ProblemDetails =\n                            {\n                                Title = details.Title,\n                                Detail = details.Detail,\n                                Status = details.StatusCode\n                            }\n                        };\n\n                        if (app.Environment.IsDevelopment())\n                        {\n                            problem.ProblemDetails.Extensions.Add(\"exception\", exceptionHandlerFeature?.Error.ToString());\n                        }\n\n                        await problemDetailsService.WriteAsync(problem);\n                    }\n                }\n            });\n        });\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/TestBase/TestBase.cs",
    "content": "using System.Net;\nusing System.Security.Claims;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Mongo;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing EasyNetQ.Management.Client;\nusing Grpc.Net.Client;\nusing MassTransit;\nusing MassTransit.Testing;\nusing MediatR;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing MongoDB.Driver;\nusing NSubstitute;\nusing Respawn;\nusing WebMotions.Fake.Authentication.JwtBearer;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace BuildingBlocks.TestBase;\n\nusing System.Globalization;\nusing Npgsql;\nusing Testcontainers.EventStoreDb;\nusing Testcontainers.MongoDb;\nusing Testcontainers.PostgreSql;\nusing Testcontainers.RabbitMq;\n\npublic class TestFixture<TEntryPoint> : IAsyncLifetime\n    where TEntryPoint : class\n{\n    private readonly WebApplicationFactory<TEntryPoint> _factory;\n    private int Timeout => 120; // Second\n    public ITestHarness TestHarness => ServiceProvider?.GetTestHarness();\n    private Action<IServiceCollection> TestRegistrationServices { get; set; }\n    private PostgreSqlContainer PostgresTestcontainer;\n    private PostgreSqlContainer PostgresPersistTestContainer;\n    public RabbitMqContainer RabbitMqTestContainer;\n    public MongoDbContainer MongoDbTestContainer;\n    public EventStoreDbContainer EventStoreDbTestContainer;\n    public CancellationTokenSource CancellationTokenSource;\n\n    public PersistMessageBackgroundService PersistMessageBackgroundService =>\n        ServiceProvider.GetRequiredService<PersistMessageBackgroundService>();\n\n    public HttpClient HttpClient\n    {\n        get\n        {\n            var claims = new Dictionary<string, object>\n            {\n                { ClaimTypes.Name, \"test@sample.com\" },\n                { ClaimTypes.Role, \"admin\" },\n                { \"scope\", \"flight-api\" },\n            };\n\n            var httpClient = _factory.CreateClient();\n            httpClient.SetFakeBearerToken(claims); // Uses FakeJwtBearer\n            return httpClient;\n        }\n    }\n\n    public GrpcChannel Channel =>\n        GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });\n\n    public IServiceProvider ServiceProvider => _factory?.Services;\n    public IConfiguration Configuration => _factory?.Services.GetRequiredService<IConfiguration>();\n    public ILogger Logger { get; set; }\n\n    protected TestFixture()\n    {\n        _factory = new WebApplicationFactory<TEntryPoint>().WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureAppConfiguration(AddCustomAppSettings);\n\n            builder.UseEnvironment(\"test\");\n\n            builder.ConfigureServices(services =>\n            {\n                TestRegistrationServices?.Invoke(services);\n                services.ReplaceSingleton(AddHttpContextAccessorMock);\n\n                services.AddSingleton<PersistMessageBackgroundService>();\n                services.RemoveHostedService<PersistMessageBackgroundService>();\n\n                // Register all ITestDataSeeder implementations dynamically\n                services.Scan(scan =>\n                    scan.FromApplicationDependencies() // Scan the current app and its dependencies\n                        .AddClasses(classes => classes.AssignableTo<ITestDataSeeder>()) // Find classes that implement ITestDataSeeder\n                        .AsImplementedInterfaces()\n                        .WithScopedLifetime()\n                );\n\n                // Add Fake JWT Authentication - we can use SetAdminUser method to set authenticate user to existing HttContextAccessor\n                // https://github.com/webmotions/fake-authentication-jwtbearer\n                // https://github.com/webmotions/fake-authentication-jwtbearer/issues/14\n                services\n                    .AddAuthentication(options =>\n                    {\n                        options.DefaultAuthenticateScheme = FakeJwtBearerDefaults.AuthenticationScheme;\n\n                        options.DefaultChallengeScheme = FakeJwtBearerDefaults.AuthenticationScheme;\n                    })\n                    .AddFakeJwtBearer();\n\n                // Mock Authorization Policies\n                services.AddAuthorization(options =>\n                {\n                    options.AddPolicy(\n                        nameof(ApiScope),\n                        policy =>\n                        {\n                            policy.AddAuthenticationSchemes(FakeJwtBearerDefaults.AuthenticationScheme);\n                            policy.RequireAuthenticatedUser();\n                            policy.RequireClaim(\"scope\", \"flight-api\"); // Test-specific scope\n                        }\n                    );\n                });\n            });\n        });\n    }\n\n    public async Task InitializeAsync()\n    {\n        CancellationTokenSource = new CancellationTokenSource();\n        await StartTestContainerAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        await StopTestContainerAsync();\n        await _factory.DisposeAsync();\n        await CancellationTokenSource.CancelAsync();\n    }\n\n    public virtual void RegisterServices(Action<IServiceCollection> services)\n    {\n        TestRegistrationServices += services;\n    }\n\n    // ref: https://github.com/trbenning/serilog-sinks-xunit\n    public ILogger CreateLogger(ITestOutputHelper output)\n    {\n        if (output == null)\n            return null;\n\n        var loggerFactory = LoggerFactory.Create(builder =>\n        {\n            builder.AddXunit(output);\n            builder.SetMinimumLevel(LogLevel.Debug);\n        });\n        return loggerFactory.CreateLogger(\"TestLogger\");\n    }\n\n    protected async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)\n    {\n        using var scope = ServiceProvider.CreateScope();\n        await action(scope.ServiceProvider);\n    }\n\n    protected async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)\n    {\n        using var scope = ServiceProvider.CreateScope();\n\n        var result = await action(scope.ServiceProvider);\n\n        return result;\n    }\n\n    public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)\n    {\n        return ExecuteScopeAsync(sp =>\n        {\n            var mediator = sp.GetRequiredService<IMediator>();\n\n            return mediator.Send(request);\n        });\n    }\n\n    public Task SendAsync(IRequest request)\n    {\n        return ExecuteScopeAsync(sp =>\n        {\n            var mediator = sp.GetRequiredService<IMediator>();\n            return mediator.Send(request);\n        });\n    }\n\n    public async Task Publish<TMessage>(TMessage message, CancellationToken cancellationToken = default)\n        where TMessage : class, IEvent\n    {\n        // Use harness bus to ensure publish happens only after the bus is started.\n        await TestHarness.Bus.Publish(message, cancellationToken);\n    }\n\n    public async Task<bool> WaitForPublishing<TMessage>(CancellationToken cancellationToken = default)\n        where TMessage : class, IEvent\n    {\n        var result = await WaitUntilConditionMet(\n            async () =>\n            {\n                var published = await TestHarness.Published.Any<TMessage>(cancellationToken);\n\n                return published;\n            },\n            cancellationToken: cancellationToken\n        );\n\n        return result;\n    }\n\n    public Task<bool> WaitUntilAsync(\n        Func<Task<bool>> condition,\n        TimeSpan? timeout = null,\n        TimeSpan? pollInterval = null,\n        CancellationToken cancellationToken = default\n    )\n    {\n        var effectiveTimeout = timeout ?? TimeSpan.FromSeconds(Timeout);\n        var effectivePollInterval = pollInterval ?? TimeSpan.FromMilliseconds(200);\n\n        return WaitUntilConditionMet(\n            conditionToMet: async () =>\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n                return await condition();\n            },\n            timeoutSecond: (int)Math.Ceiling(effectiveTimeout.TotalSeconds),\n            pollInterval: effectivePollInterval,\n            cancellationToken: cancellationToken\n        );\n    }\n\n    // Ref: https://tech.energyhelpline.com/in-memory-testing-with-masstransit/\n    private async Task<bool> WaitUntilConditionMet(\n        Func<Task<bool>> conditionToMet,\n        int? timeoutSecond = null,\n        TimeSpan? pollInterval = null,\n        CancellationToken cancellationToken = default\n    )\n    {\n        var time = timeoutSecond ?? Timeout;\n        var delay = pollInterval ?? TimeSpan.FromMilliseconds(100);\n\n        var startTime = DateTime.UtcNow;\n        while (DateTime.UtcNow - startTime <= TimeSpan.FromSeconds(time))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            if (await conditionToMet.Invoke())\n                return true;\n\n            await Task.Delay(delay, cancellationToken);\n        }\n\n        return false;\n    }\n\n    private async Task StartTestContainerAsync()\n    {\n        PostgresTestcontainer = TestContainers.PostgresTestContainer();\n        PostgresPersistTestContainer = TestContainers.PostgresPersistTestContainer();\n        RabbitMqTestContainer = TestContainers.RabbitMqTestContainer();\n        MongoDbTestContainer = TestContainers.MongoTestContainer();\n        EventStoreDbTestContainer = TestContainers.EventStoreTestContainer();\n\n        await MongoDbTestContainer.StartAsync();\n        await PostgresTestcontainer.StartAsync();\n        await PostgresPersistTestContainer.StartAsync();\n        await RabbitMqTestContainer.StartAsync();\n        await EventStoreDbTestContainer.StartAsync();\n    }\n\n    private async Task StopTestContainerAsync()\n    {\n        await PostgresTestcontainer.StopAsync();\n        await PostgresPersistTestContainer.StopAsync();\n        await RabbitMqTestContainer.StopAsync();\n        await MongoDbTestContainer.StopAsync();\n        await EventStoreDbTestContainer.StopAsync();\n    }\n\n    private void AddCustomAppSettings(IConfigurationBuilder configuration)\n    {\n        //todo: provide better approach for reading `PostgresOptions`\n        configuration.AddInMemoryCollection(\n            new KeyValuePair<string, string>[]\n            {\n                new(\"PostgresOptions:ConnectionString\", PostgresTestcontainer.GetConnectionString()),\n                new(\"PostgresOptions:ConnectionString:Flight\", PostgresTestcontainer.GetConnectionString()),\n                new(\"PostgresOptions:ConnectionString:Identity\", PostgresTestcontainer.GetConnectionString()),\n                new(\"PostgresOptions:ConnectionString:Passenger\", PostgresTestcontainer.GetConnectionString()),\n                new(\"PersistMessageOptions:ConnectionString\", PostgresPersistTestContainer.GetConnectionString()),\n                new(\"RabbitMqOptions:HostName\", \"127.0.0.1\"),\n                new(\"RabbitMqOptions:UserName\", TestContainers.RabbitMqContainerConfiguration.UserName),\n                new(\"RabbitMqOptions:Password\", TestContainers.RabbitMqContainerConfiguration.Password),\n                new(\n                    \"RabbitMqOptions:Port\",\n                    RabbitMqTestContainer\n                        .GetMappedPublicPort(TestContainers.RabbitMqContainerConfiguration.Port)\n                        .ToString(NumberFormatInfo.InvariantInfo)\n                ),\n                new(\"MongoOptions:ConnectionString\", MongoDbTestContainer.GetConnectionString()),\n                new(\"MongoOptions:DatabaseName\", TestContainers.MongoContainerConfiguration.Name),\n                new(\"EventStoreOptions:ConnectionString\", EventStoreDbTestContainer.GetConnectionString()),\n            }\n        );\n    }\n\n    private IHttpContextAccessor AddHttpContextAccessorMock(IServiceProvider serviceProvider)\n    {\n        var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>();\n        using var scope = serviceProvider.CreateScope();\n\n        httpContextAccessorMock.HttpContext = new DefaultHttpContext { RequestServices = scope.ServiceProvider };\n\n        httpContextAccessorMock.HttpContext.Request.Host = new HostString(\"localhost\", 6012);\n        httpContextAccessorMock.HttpContext.Request.Scheme = \"http\";\n\n        return httpContextAccessorMock;\n    }\n}\n\npublic class TestWriteFixture<TEntryPoint, TWContext> : TestFixture<TEntryPoint>\n    where TEntryPoint : class\n    where TWContext : DbContext\n{\n    public Task ExecuteDbContextAsync(Func<TWContext, Task> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>()));\n    }\n\n    public Task ExecuteDbContextAsync(Func<TWContext, ValueTask> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>()).AsTask());\n    }\n\n    public Task ExecuteDbContextAsync(Func<TWContext, IMediator, Task> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>(), sp.GetRequiredService<IMediator>()));\n    }\n\n    public Task<T> ExecuteDbContextAsync<T>(Func<TWContext, Task<T>> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>()));\n    }\n\n    public Task<T> ExecuteDbContextAsync<T>(Func<TWContext, ValueTask<T>> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>()).AsTask());\n    }\n\n    public Task<T> ExecuteDbContextAsync<T>(Func<TWContext, IMediator, Task<T>> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TWContext>(), sp.GetRequiredService<IMediator>()));\n    }\n\n    public Task InsertAsync<T>(params T[] entities)\n        where T : class\n    {\n        return ExecuteDbContextAsync(db =>\n        {\n            foreach (var entity in entities)\n            {\n                db.Set<T>().Add(entity);\n            }\n\n            return db.SaveChangesAsync();\n        });\n    }\n\n    public async Task InsertAsync<TEntity>(TEntity entity)\n        where TEntity : class\n    {\n        await ExecuteDbContextAsync(db =>\n        {\n            db.Set<TEntity>().Add(entity);\n\n            return db.SaveChangesAsync();\n        });\n    }\n\n    public Task InsertAsync<TEntity, TEntity2>(TEntity entity, TEntity2 entity2)\n        where TEntity : class\n        where TEntity2 : class\n    {\n        return ExecuteDbContextAsync(db =>\n        {\n            db.Set<TEntity>().Add(entity);\n            db.Set<TEntity2>().Add(entity2);\n\n            return db.SaveChangesAsync();\n        });\n    }\n\n    public Task InsertAsync<TEntity, TEntity2, TEntity3>(TEntity entity, TEntity2 entity2, TEntity3 entity3)\n        where TEntity : class\n        where TEntity2 : class\n        where TEntity3 : class\n    {\n        return ExecuteDbContextAsync(db =>\n        {\n            db.Set<TEntity>().Add(entity);\n            db.Set<TEntity2>().Add(entity2);\n            db.Set<TEntity3>().Add(entity3);\n\n            return db.SaveChangesAsync();\n        });\n    }\n\n    public Task InsertAsync<TEntity, TEntity2, TEntity3, TEntity4>(\n        TEntity entity,\n        TEntity2 entity2,\n        TEntity3 entity3,\n        TEntity4 entity4\n    )\n        where TEntity : class\n        where TEntity2 : class\n        where TEntity3 : class\n        where TEntity4 : class\n    {\n        return ExecuteDbContextAsync(db =>\n        {\n            db.Set<TEntity>().Add(entity);\n            db.Set<TEntity2>().Add(entity2);\n            db.Set<TEntity3>().Add(entity3);\n            db.Set<TEntity4>().Add(entity4);\n\n            return db.SaveChangesAsync();\n        });\n    }\n\n    public Task<T> FindAsync<T, TKey>(TKey id)\n        where T : class, IEntity\n    {\n        return ExecuteDbContextAsync(db => db.Set<T>().FindAsync(id).AsTask());\n    }\n\n    public Task<T> FirstOrDefaultAsync<T>()\n        where T : class, IEntity\n    {\n        return ExecuteDbContextAsync(db => db.Set<T>().FirstOrDefaultAsync());\n    }\n}\n\npublic class TestReadFixture<TEntryPoint, TRContext> : TestFixture<TEntryPoint>\n    where TEntryPoint : class\n    where TRContext : MongoDbContext\n{\n    public Task ExecuteReadContextAsync(Func<TRContext, Task> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TRContext>()));\n    }\n\n    public Task<T> ExecuteReadContextAsync<T>(Func<TRContext, Task<T>> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TRContext>()));\n    }\n\n    public async Task InsertMongoDbContextAsync<T>(string collectionName, params T[] entities)\n        where T : class\n    {\n        await ExecuteReadContextAsync(async db =>\n        {\n            await db.GetCollection<T>(collectionName).InsertManyAsync(entities.ToList());\n        });\n    }\n}\n\npublic class TestFixture<TEntryPoint, TWContext, TRContext> : TestWriteFixture<TEntryPoint, TWContext>\n    where TEntryPoint : class\n    where TWContext : DbContext\n    where TRContext : MongoDbContext\n{\n    public Task ExecuteReadContextAsync(Func<TRContext, Task> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TRContext>()));\n    }\n\n    public Task<T> ExecuteReadContextAsync<T>(Func<TRContext, Task<T>> action)\n    {\n        return ExecuteScopeAsync(sp => action(sp.GetRequiredService<TRContext>()));\n    }\n\n    public async Task InsertMongoDbContextAsync<T>(string collectionName, params T[] entities)\n        where T : class\n    {\n        await ExecuteReadContextAsync(async db =>\n        {\n            await db.GetCollection<T>(collectionName).InsertManyAsync(entities.ToList());\n        });\n    }\n}\n\npublic class TestFixtureCore<TEntryPoint> : IAsyncLifetime\n    where TEntryPoint : class\n{\n    private Respawner _reSpawnerDefaultDb;\n    private Respawner _reSpawnerPersistDb;\n    private NpgsqlConnection DefaultDbConnection { get; set; }\n    private NpgsqlConnection PersistDbConnection { get; set; }\n    private Type _dbContextType;\n\n    public TestFixtureCore(\n        TestFixture<TEntryPoint> integrationTestFixture,\n        ITestOutputHelper outputHelper,\n        Type dbContextType = null\n    )\n    {\n        Fixture = integrationTestFixture;\n        integrationTestFixture.RegisterServices(RegisterTestsServices);\n        integrationTestFixture.Logger = integrationTestFixture.CreateLogger(outputHelper);\n        _dbContextType = dbContextType;\n    }\n\n    public TestFixture<TEntryPoint> Fixture { get; }\n\n    public async Task InitializeAsync()\n    {\n        await InitPostgresAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        await ResetPostgresAsync();\n        await ResetMongoAsync();\n        await ResetRabbitMqAsync();\n    }\n\n    private async Task InitPostgresAsync()\n    {\n        var postgresOptions = Fixture.ServiceProvider.GetService<PostgresOptions>();\n        var persistOptions = Fixture.ServiceProvider.GetService<PersistMessageOptions>();\n\n        if (!string.IsNullOrEmpty(persistOptions?.ConnectionString))\n        {\n            PersistDbConnection = new NpgsqlConnection(persistOptions.ConnectionString);\n            await PersistDbConnection.OpenAsync();\n\n            using var scope = Fixture.ServiceProvider.CreateScope();\n            var dbContext = scope.ServiceProvider.GetRequiredService<PersistMessageDbContext>();\n            await dbContext.Database.EnsureCreatedAsync();\n\n            await Fixture.PersistMessageBackgroundService.StartAsync(Fixture.CancellationTokenSource.Token);\n\n            _reSpawnerPersistDb = await Respawner.CreateAsync(\n                PersistDbConnection,\n                new RespawnerOptions { DbAdapter = DbAdapter.Postgres }\n            );\n        }\n\n        if (!string.IsNullOrEmpty(postgresOptions?.ConnectionString) && _dbContextType != null)\n        {\n            DefaultDbConnection = new NpgsqlConnection(postgresOptions.ConnectionString);\n            await DefaultDbConnection.OpenAsync();\n\n            using var scope = Fixture.ServiceProvider.CreateScope();\n\n            if (scope.ServiceProvider.GetRequiredService(_dbContextType) is DbContext dbContext)\n            {\n                await dbContext.Database.EnsureCreatedAsync();\n            }\n\n            _reSpawnerDefaultDb = await Respawner.CreateAsync(\n                DefaultDbConnection,\n                new RespawnerOptions { DbAdapter = DbAdapter.Postgres, TablesToIgnore = [\"__EFMigrationsHistory\"] }\n            );\n\n            await SeedDataAsync();\n        }\n    }\n\n    private async Task ResetPostgresAsync()\n    {\n        if (PersistDbConnection is not null)\n        {\n            await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);\n\n            await Fixture.PersistMessageBackgroundService.StopAsync(Fixture.CancellationTokenSource.Token);\n        }\n\n        if (DefaultDbConnection is not null)\n        {\n            await _reSpawnerDefaultDb.ResetAsync(DefaultDbConnection);\n        }\n    }\n\n    private async Task ResetMongoAsync(CancellationToken cancellationToken = default)\n    {\n        //https://stackoverflow.com/questions/3366397/delete-everything-in-a-mongodb-database\n        var dbClient = new MongoClient(Fixture.MongoDbTestContainer?.GetConnectionString());\n\n        var collections = await dbClient\n            .GetDatabase(TestContainers.MongoContainerConfiguration.Name)\n            .ListCollectionsAsync(cancellationToken: cancellationToken);\n\n        foreach (var collection in collections.ToList())\n        {\n            await dbClient\n                .GetDatabase(TestContainers.MongoContainerConfiguration.Name)\n                .DropCollectionAsync(collection[\"name\"].AsString, cancellationToken);\n        }\n    }\n\n    private async Task ResetRabbitMqAsync(CancellationToken cancellationToken = default)\n    {\n        var port =\n            Fixture.RabbitMqTestContainer?.GetMappedPublicPort(TestContainers.RabbitMqContainerConfiguration.ApiPort)\n            ?? TestContainers.RabbitMqContainerConfiguration.ApiPort;\n\n        var managementClient = new ManagementClient(\n            Fixture.RabbitMqTestContainer?.Hostname,\n            TestContainers.RabbitMqContainerConfiguration?.UserName,\n            TestContainers.RabbitMqContainerConfiguration?.Password,\n            port\n        );\n\n        var bd = await managementClient.GetBindingsAsync(cancellationToken);\n\n        var bindings = bd.Where(x => !string.IsNullOrEmpty(x.Source) && !string.IsNullOrEmpty(x.Destination));\n\n        foreach (var binding in bindings)\n        {\n            await managementClient.DeleteBindingAsync(binding, cancellationToken);\n        }\n\n        var queues = await managementClient.GetQueuesAsync(cancellationToken: cancellationToken);\n\n        foreach (var queue in queues)\n        {\n            await managementClient.PurgeAsync(queue, cancellationToken);\n        }\n    }\n\n    protected virtual void RegisterTestsServices(IServiceCollection services) { }\n\n    private async Task SeedDataAsync()\n    {\n        using var scope = Fixture.ServiceProvider.CreateScope();\n\n        var seedManager = scope.ServiceProvider.GetService<ISeedManager>();\n        await seedManager.ExecuteTestSeedAsync();\n    }\n}\n\npublic abstract class TestReadBase<TEntryPoint, TRContext> : TestFixtureCore<TEntryPoint>\n    // ,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>\n    where TEntryPoint : class\n    where TRContext : MongoDbContext\n{\n    protected TestReadBase(\n        TestReadFixture<TEntryPoint, TRContext> integrationTestFixture,\n        ITestOutputHelper outputHelper = null\n    )\n        : base(integrationTestFixture, outputHelper)\n    {\n        Fixture = integrationTestFixture;\n    }\n\n    public TestReadFixture<TEntryPoint, TRContext> Fixture { get; }\n}\n\npublic abstract class TestWriteBase<TEntryPoint, TWContext> : TestFixtureCore<TEntryPoint>\n    //,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>\n    where TEntryPoint : class\n    where TWContext : DbContext\n{\n    protected TestWriteBase(\n        TestWriteFixture<TEntryPoint, TWContext> integrationTestFixture,\n        ITestOutputHelper outputHelper = null\n    )\n        : base(integrationTestFixture, outputHelper, typeof(TWContext))\n    {\n        Fixture = integrationTestFixture;\n    }\n\n    public TestWriteFixture<TEntryPoint, TWContext> Fixture { get; }\n}\n\npublic abstract class TestBase<TEntryPoint, TWContext, TRContext> : TestFixtureCore<TEntryPoint>\n    //,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext, TRContext>>\n    where TEntryPoint : class\n    where TWContext : DbContext\n    where TRContext : MongoDbContext\n{\n    protected TestBase(\n        TestFixture<TEntryPoint, TWContext, TRContext> integrationTestFixture,\n        ITestOutputHelper outputHelper = null\n    )\n        : base(integrationTestFixture, outputHelper, typeof(TWContext))\n    {\n        Fixture = integrationTestFixture;\n    }\n\n    public TestFixture<TEntryPoint, TWContext, TRContext> Fixture { get; }\n}\n"
  },
  {
    "path": "src/BuildingBlocks/TestBase/TestContainers.cs",
    "content": "using DotNet.Testcontainers.Builders;\n\nnamespace BuildingBlocks.TestBase;\n\nusing Testcontainers.EventStoreDb;\nusing Testcontainers.MongoDb;\nusing Testcontainers.PostgreSql;\nusing Testcontainers.RabbitMq;\nusing Web;\n\npublic static class TestContainers\n{\n    public static RabbitMqContainerOptions RabbitMqContainerConfiguration { get; }\n    public static PostgresContainerOptions PostgresContainerConfiguration { get; }\n    public static PostgresPersistContainerOptions PostgresPersistContainerConfiguration { get; }\n    public static MongoContainerOptions MongoContainerConfiguration { get; }\n    public static EventStoreContainerOptions EventStoreContainerConfiguration { get; }\n\n    static TestContainers()\n    {\n        var configuration = ConfigurationHelper.GetConfiguration();\n\n        RabbitMqContainerConfiguration = configuration.GetOptions<RabbitMqContainerOptions>(\n            nameof(RabbitMqContainerOptions)\n        );\n        PostgresContainerConfiguration = configuration.GetOptions<PostgresContainerOptions>(\n            nameof(PostgresContainerOptions)\n        );\n        PostgresPersistContainerConfiguration = configuration.GetOptions<PostgresPersistContainerOptions>(\n            nameof(PostgresPersistContainerOptions)\n        );\n        MongoContainerConfiguration = configuration.GetOptions<MongoContainerOptions>(nameof(MongoContainerOptions));\n        EventStoreContainerConfiguration = configuration.GetOptions<EventStoreContainerOptions>(\n            nameof(EventStoreContainerOptions)\n        );\n    }\n\n    public static PostgreSqlContainer PostgresTestContainer()\n    {\n        var baseBuilder = new PostgreSqlBuilder()\n            .WithUsername(PostgresContainerConfiguration.UserName)\n            .WithPassword(PostgresContainerConfiguration.Password)\n            .WithLabel(\"Key\", \"Value\");\n\n        var builder = baseBuilder\n            .WithImage(PostgresContainerConfiguration.ImageName)\n            .WithName(PostgresContainerConfiguration.Name)\n            .WithCommand(new string[2] { \"-c\", \"max_prepared_transactions=10\" })\n            .WithPortBinding(PostgresContainerConfiguration.Port, true)\n            .Build();\n\n        return builder;\n    }\n\n    public static PostgreSqlContainer PostgresPersistTestContainer()\n    {\n        var baseBuilder = new PostgreSqlBuilder()\n            .WithUsername(PostgresPersistContainerConfiguration.UserName)\n            .WithPassword(PostgresPersistContainerConfiguration.Password)\n            .WithLabel(\"Key\", \"Value\");\n\n        var builder = baseBuilder\n            .WithImage(PostgresPersistContainerConfiguration.ImageName)\n            .WithName(PostgresPersistContainerConfiguration.Name)\n            .WithCommand(new string[2] { \"-c\", \"max_prepared_transactions=10\" })\n            .WithPortBinding(PostgresPersistContainerConfiguration.Port, true)\n            .Build();\n\n        return builder;\n    }\n\n    public static MongoDbContainer MongoTestContainer()\n    {\n        var baseBuilder = new MongoDbBuilder()\n            .WithUsername(MongoContainerConfiguration.UserName)\n            .WithPassword(MongoContainerConfiguration.Password)\n            .WithLabel(\"Key\", \"Value\");\n\n        var builder = baseBuilder\n            .WithImage(MongoContainerConfiguration.ImageName)\n            .WithName(MongoContainerConfiguration.Name)\n            .WithPortBinding(MongoContainerConfiguration.Port, true)\n            .Build();\n\n        return builder;\n    }\n\n    public static RabbitMqContainer RabbitMqTestContainer()\n    {\n        var baseBuilder = new RabbitMqBuilder()\n            .WithUsername(RabbitMqContainerConfiguration.UserName)\n            .WithPassword(RabbitMqContainerConfiguration.Password)\n            .WithLabel(\"Key\", \"Value\");\n\n        var builder = baseBuilder\n            .WithImage(RabbitMqContainerConfiguration.ImageName)\n            .WithName(RabbitMqContainerConfiguration.Name)\n            .WithPortBinding(RabbitMqContainerConfiguration.ApiPort, true)\n            .WithPortBinding(RabbitMqContainerConfiguration.Port, true)\n            .Build();\n\n        return builder;\n    }\n\n    public static EventStoreDbContainer EventStoreTestContainer()\n    {\n        var baseBuilder = new EventStoreDbBuilder().WithLabel(\"Key\", \"Value\");\n\n        var builder = baseBuilder\n            .WithImage(EventStoreContainerConfiguration.ImageName)\n            .WithName(EventStoreContainerConfiguration.Name)\n            .Build();\n\n        return builder;\n    }\n\n    public sealed class RabbitMqContainerOptions\n    {\n        public string Name { get; set; } = \"rabbitmq_\" + Guid.NewGuid();\n        public int Port { get; set; } = 5672;\n        public int ApiPort { get; set; } = 15672;\n        public string ImageName { get; set; } = \"rabbitmq:management\";\n        public string UserName { get; set; } = \"guest\";\n        public string Password { get; set; } = \"guest\";\n    }\n\n    public sealed class PostgresContainerOptions\n    {\n        public string Name { get; set; } = \"postgreSql_\" + Guid.NewGuid().ToString(\"D\");\n        public int Port { get; set; } = 5432;\n        public string ImageName { get; set; } = \"postgres:latest\";\n        public string UserName { get; set; } = Guid.NewGuid().ToString(\"D\");\n        public string Password { get; set; } = Guid.NewGuid().ToString(\"D\");\n    }\n\n    public sealed class PostgresPersistContainerOptions\n    {\n        public string Name { get; set; } = \"postgreSql_\" + Guid.NewGuid().ToString(\"D\");\n        public int Port { get; set; } = 5432;\n        public string ImageName { get; set; } = \"postgres:latest\";\n        public string UserName { get; set; } = Guid.NewGuid().ToString(\"D\");\n        public string Password { get; set; } = Guid.NewGuid().ToString(\"D\");\n    }\n\n    public sealed class MongoContainerOptions\n    {\n        public string Name { get; set; } = \"mongo_\" + Guid.NewGuid().ToString(\"D\");\n        public int Port { get; set; } = 27017;\n        public string ImageName { get; set; } = \"mongo:latest\";\n        public string UserName { get; set; } = Guid.NewGuid().ToString(\"D\");\n        public string Password { get; set; } = Guid.NewGuid().ToString(\"D\");\n    }\n\n    public sealed class EventStoreContainerOptions\n    {\n        public string Name { get; set; } = \"event_store_\" + Guid.NewGuid().ToString(\"D\");\n        public int Port { get; set; } = 2113;\n        public string ImageName { get; set; } = \"eventstore/eventstore:latest\";\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Utils/NoSynchronizationContextScope.cs",
    "content": "namespace BuildingBlocks.Utils;\n\npublic static class NoSynchronizationContextScope\n{\n    public static Disposable Enter()\n    {\n        var context = SynchronizationContext.Current;\n        SynchronizationContext.SetSynchronizationContext(null);\n        return new Disposable(context);\n    }\n\n    public struct Disposable : IDisposable\n    {\n        private readonly SynchronizationContext? synchronizationContext;\n\n        public Disposable(SynchronizationContext? synchronizationContext)\n        {\n            this.synchronizationContext = synchronizationContext;\n        }\n\n        public void Dispose() =>\n            SynchronizationContext.SetSynchronizationContext(synchronizationContext);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Utils/ServiceLocator.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Utils;\n\n//ref: https://dotnetcoretutorials.com/2018/05/06/servicelocator-shim-for-net-core/\npublic class ServiceLocator\n{\n    private IServiceProvider _currentServiceProvider;\n    private static IServiceProvider _serviceProvider;\n\n    public ServiceLocator(IServiceProvider currentServiceProvider)\n    {\n        _currentServiceProvider = currentServiceProvider;\n    }\n\n    public static ServiceLocator Current\n    {\n        get\n        {\n            return new ServiceLocator(_serviceProvider);\n        }\n    }\n\n    public static void SetLocatorProvider(IServiceProvider serviceProvider)\n    {\n        _serviceProvider = serviceProvider;\n    }\n\n    public object GetInstance(Type serviceType)\n    {\n        return _currentServiceProvider.GetService(serviceType);\n    }\n\n    public TService GetInstance<TService>()\n    {\n        return _currentServiceProvider.GetService<TService>();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Utils/TypeProvider.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\n\nnamespace BuildingBlocks.Utils;\n\npublic static class TypeProvider\n{\n    private static bool IsRecord(this Type objectType)\n    {\n        return objectType.GetMethod(\"<Clone>$\") != null ||\n               ((TypeInfo)objectType)\n               .DeclaredProperties.FirstOrDefault(x => x.Name == \"EqualityContract\")?\n               .GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) != null;\n    }\n\n    public static Type? GetTypeFromAnyReferencingAssembly(string typeName)\n    {\n        var referencedAssemblies = Assembly.GetEntryAssembly()?\n            .GetReferencedAssemblies()\n            .Select(a => a.FullName);\n\n        if (referencedAssemblies == null)\n            return null;\n\n        return AppDomain.CurrentDomain.GetAssemblies()\n            .Where(a => referencedAssemblies.Contains(a.FullName))\n            .SelectMany(a => a.GetTypes().Where(x => x.FullName == typeName || x.Name == typeName))\n            .FirstOrDefault();\n    }\n\n    public static Type? GetFirstMatchingTypeFromCurrentDomainAssembly(string typeName)\n    {\n        var result = AppDomain.CurrentDomain.GetAssemblies()\n            .SelectMany(a => a.GetTypes().Where(x => x.FullName == typeName || x.Name == typeName))\n            .FirstOrDefault();\n\n        return result;\n    }\n\n    public static IReadOnlyList<Assembly> GetReferencedAssemblies(Assembly? rootAssembly)\n    {\n        var visited = new HashSet<string>();\n        var queue = new Queue<Assembly?>();\n        var listResult = new List<Assembly>();\n\n        var root = rootAssembly ?? Assembly.GetEntryAssembly();\n        queue.Enqueue(root);\n\n        do\n        {\n            var asm = queue.Dequeue();\n\n            if (asm == null)\n                break;\n\n            listResult.Add(asm);\n\n            foreach (var reference in asm.GetReferencedAssemblies())\n            {\n                if (!visited.Contains(reference.FullName))\n                {\n                    // Load will add assembly into the application domain of the caller. loading assemblies explicitly to AppDomain, because assemblies are loaded lazily\n                    // https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load\n                    queue.Enqueue(Assembly.Load(reference));\n                    visited.Add(reference.FullName);\n                }\n            }\n        } while (queue.Count > 0);\n\n        return listResult.Distinct().ToList().AsReadOnly();\n    }\n\n    public static IReadOnlyList<Assembly> GetApplicationPartAssemblies(Assembly rootAssembly)\n    {\n        var rootNamespace = rootAssembly.GetName().Name!.Split('.').First();\n        var list = rootAssembly!.GetCustomAttributes<ApplicationPartAttribute>()\n            .Where(x => x.AssemblyName.StartsWith(rootNamespace, StringComparison.InvariantCulture))\n            .Select(name => Assembly.Load(name.AssemblyName))\n            .Distinct();\n\n        return list.ToList().AsReadOnly();\n    }\n\n}"
  },
  {
    "path": "src/BuildingBlocks/Validation/Extensions.cs",
    "content": "using BuildingBlocks.Exception;\nusing FluentValidation;\n\nnamespace BuildingBlocks.Validation\n{\n    public static class Extensions\n    {\n        /// <summary>\n        /// Ref https://www.jerriepelser.com/blog/validation-response-aspnet-core-webapi\n        /// </summary>\n        public static async Task HandleValidationAsync<TRequest>(this IValidator<TRequest> validator, TRequest request)\n        {\n            var validationResult = await validator.ValidateAsync(request);\n            if (!validationResult.IsValid)\n            {\n                throw new Exception.ValidationException(validationResult.Errors?.First()?.ErrorMessage);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Validation/ValidationBehavior.cs",
    "content": "using FluentValidation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Validation;\n\npublic sealed class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>\n    where TRequest : class, IRequest<TResponse>\n{\n    private IValidator<TRequest> _validator;\n    private readonly IServiceProvider _serviceProvider;\n\n    public ValidationBehavior(IServiceProvider serviceProvider)\n    {\n        _serviceProvider = serviceProvider;\n    }\n\n    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,\n        CancellationToken cancellationToken)\n    {\n        _validator = _serviceProvider.GetService<IValidator<TRequest>>();\n        if (_validator is null)\n            return await next();\n\n        await _validator.HandleValidationAsync(request);\n\n        return await next();\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Validation/ValidationError.cs",
    "content": "namespace BuildingBlocks.Validation\n{\n    public class ValidationError\n    {\n        public string Field { get; }\n\n        public string Message { get; }\n\n        public ValidationError(string field, string message)\n        {\n            Field = field != string.Empty ? field : null;\n            Message = message;\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Validation/ValidationResultModel.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Text.Json;\nusing FluentValidation.Results;\n\nnamespace BuildingBlocks.Validation\n{\n    public class ValidationResultModel\n    {\n        public int StatusCode { get; set; } = (int)HttpStatusCode.BadRequest;\n        public string Message { get; set; } = \"Validation Failed.\";\n\n        public List<ValidationFailure> Errors { get; set; }\n\n        public override string ToString()\n        {\n            return JsonSerializer.Serialize(this);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/ApiVersioningExtensions.cs",
    "content": "using Asp.Versioning;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Web;\n\npublic static class ApiVersioningExtensions\n{\n    public static void AddCustomVersioning(\n        this IServiceCollection services,\n        Action<ApiVersioningOptions>? configurator = null)\n    {\n        // https://www.meziantou.net/versioning-an-asp-net-core-api.htm\n        // https://dotnetthoughts.net/aspnetcore-api-versioning-with-net-6-minimal-apis/\n        // https://im5tu.io/article/2022/10/asp.net-core-versioning-minimal-apis/\n        // https://www.youtube.com/watch?v=YRJGKyzjFlY\n        // https://www.nuget.org/packages/Asp.Versioning.Http\n\n        // Support versioning in minimal apis with (Asp.Versioning.Http) dll\n        services.AddApiVersioning(options =>\n            {\n                // Add the headers \"api-supported-versions\" and \"api-deprecated-versions\"\n                // This is better for discoverability\n                options.ReportApiVersions = true;\n\n                // AssumeDefaultVersionWhenUnspecified should only be enabled when supporting legacy services that did not previously\n                // support API versioning. Forcing existing clients to specify an explicit API version for an\n                // existing service introduces a breaking change. Conceptually, clients in this situation are\n                // bound to some API version of a service, but they don't know what it is and never explicit request it.\n                options.AssumeDefaultVersionWhenUnspecified = true;\n                options.DefaultApiVersion = new ApiVersion(1, 0);\n\n                // Defines how an API version is read from the current HTTP request\n                options.ApiVersionReader = ApiVersionReader.Combine(\n                    new HeaderApiVersionReader(\"api-version\"),\n                    new UrlSegmentApiVersionReader());\n\n                configurator?.Invoke(options);\n            })\n            .AddApiExplorer(\n                options =>\n                {\n                    // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service\n                    // note: the specified format code will format the version as \"'v'major[.minor][-status]\"\n                    options.GroupNameFormat = \"'v'VVV\";\n\n                    // note: this option is only necessary when versioning by url segment. the SubstitutionFormat\n                    // can also be used to control the format of the API version in route templates\n                    options.SubstituteApiVersionInUrl = true;\n                })\n\n            // Support versioning in mvc with with (Asp.Versioning.Mvc.ApiExplorer) dll\n            .AddMvc(); // https://www.nuget.org/packages/Asp.Versioning.Mvc.ApiExplorer\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/AppOptions.cs",
    "content": "namespace BuildingBlocks.Web;\n\npublic class AppOptions\n{\n    public string Name { get; set; }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/BaseController.cs",
    "content": "using Asp.Versioning;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Web;\n\nusing MapsterMapper;\n\n[Route(BaseApiPath)]\n[ApiController]\n[ApiVersion(\"1.0\")]\npublic abstract class BaseController : ControllerBase\n{\n    protected const string BaseApiPath = \"api/v{version:apiVersion}\";\n    private IMapper _mapper;\n\n    private IMediator _mediator;\n\n    protected IMediator Mediator =>\n        _mediator ??= HttpContext.RequestServices.GetService<IMediator>();\n\n    protected IMapper Mapper => _mapper ??= HttpContext.RequestServices.GetService<IMapper>();\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/ConfigurationExtensions.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace BuildingBlocks.Web;\n\nusing MassTransit;\nusing Microsoft.Extensions.Options;\n\npublic static class ConfigurationExtensions\n{\n    public static TModel GetOptions<TModel>(this IConfiguration configuration, string section) where TModel : new()\n    {\n        var model = new TModel();\n        configuration.GetSection(section).Bind(model);\n        return model;\n    }\n\n    public static TModel GetOptions<TModel>(this IServiceCollection service, string section) where TModel : new()\n    {\n        var model = new TModel();\n        var configuration = service.BuildServiceProvider().GetService<IConfiguration>();\n        configuration?.GetSection(section).Bind(model);\n        return model;\n    }\n\n    public static TModel GetOptions<TModel>(this WebApplication app, string section) where TModel : new()\n    {\n        var model = new TModel();\n        app.Configuration?.GetSection(section).Bind(model);\n        return model;\n    }\n\n    public static void AddValidateOptions<TModel>(this IServiceCollection service) where TModel : class, new()\n    {\n        service.AddOptions<TModel>()\n            .BindConfiguration(typeof(TModel).Name)\n            .ValidateDataAnnotations();\n\n        service.AddSingleton(x => x.GetRequiredService<IOptions<TModel>>().Value);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/ConfigurationHelper.cs",
    "content": "using Microsoft.Extensions.Configuration;\n\nnamespace BuildingBlocks.Web\n{\n    public static class ConfigurationHelper\n    {\n        public static IConfiguration GetConfiguration(string basePath = null)\n        {\n            basePath ??= Directory.GetCurrentDirectory();\n            var environmentVariable = Environment.GetEnvironmentVariable(\"ASPNETCORE_ENVIRONMENT\");\n\n            return new ConfigurationBuilder()\n                .SetBasePath(basePath)\n                .AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true)\n                .AddJsonFile($\"appsettings.{environmentVariable}.json\", optional: true)\n                .AddEnvironmentVariables()\n                .Build();\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/CorrelationExtensions.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\n\nnamespace BuildingBlocks.Web;\n\npublic static class CorrelationExtensions\n{\n    private const string CorrelationId = \"correlationId\";\n\n    public static IApplicationBuilder UseCorrelationId(this IApplicationBuilder app)\n    {\n        return app.Use(async (ctx, next) =>\n        {\n            if (!ctx.Request.Headers.TryGetValue(CorrelationId, out var correlationId))\n                correlationId = Guid.NewGuid().ToString(\"N\");\n\n            ctx.Items[CorrelationId] = correlationId.ToString();\n            await next();\n        });\n    }\n\n    public static Guid GetCorrelationId(this HttpContext context)\n    {\n        context.Items.TryGetValue(CorrelationId, out var correlationId);\n        return string.IsNullOrEmpty(correlationId?.ToString()) ? Guid.NewGuid() : new Guid(correlationId.ToString()!);\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/CurrentUserProvider.cs",
    "content": "using System.Security.Claims;\nusing Microsoft.AspNetCore.Http;\n\nnamespace BuildingBlocks.Web;\n\npublic interface ICurrentUserProvider\n{\n    long? GetCurrentUserId();\n}\n\npublic class CurrentUserProvider : ICurrentUserProvider\n{\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public CurrentUserProvider(IHttpContextAccessor httpContextAccessor)\n    {\n        _httpContextAccessor = httpContextAccessor;\n    }\n\n\n    public long? GetCurrentUserId()\n    {\n        var nameIdentifier = _httpContextAccessor?.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);\n\n        long.TryParse(nameIdentifier, out var userId);\n\n        return userId;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/EndpointConfig.cs",
    "content": "using Asp.Versioning.Builder;\n\nnamespace BuildingBlocks.Web;\n\npublic class EndpointConfig\n{\n    public const string BaseApiPath = \"api/v{version:apiVersion}\";\n    public static ApiVersionSet VersionSet { get; private set; } = default!;\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/IMinimalEndpoint.cs",
    "content": "using Microsoft.AspNetCore.Routing;\n\nnamespace BuildingBlocks.Web;\n\npublic interface IMinimalEndpoint\n{\n    IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder);\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/MinimalApiExtensions.cs",
    "content": "using System.Reflection;\nusing BuildingBlocks.Utils;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Scrutor;\n\nnamespace BuildingBlocks.Web;\n\npublic static class MinimalApiExtensions\n{\n\n    public static IServiceCollection AddMinimalEndpoints(\n        this WebApplicationBuilder applicationBuilder,\n        ServiceLifetime lifetime = ServiceLifetime.Scoped,\n        params Assembly[] assemblies)\n    {\n\n        var scanAssemblies = assemblies.Any()\n            ? assemblies\n            : TypeProvider.GetReferencedAssemblies(Assembly.GetCallingAssembly())\n                .Concat(TypeProvider.GetApplicationPartAssemblies(Assembly.GetCallingAssembly()))\n                .Distinct()\n                .ToArray();\n\n        applicationBuilder.Services.Scan(scan => scan\n            .FromAssemblies(scanAssemblies)\n            .AddClasses(classes => classes.AssignableTo(typeof(IMinimalEndpoint)))\n            .UsingRegistrationStrategy(RegistrationStrategy.Append)\n            .As<IMinimalEndpoint>()\n            .WithLifetime(lifetime));\n\n        return applicationBuilder.Services;\n    }\n\n    /// <summary>\n    /// Map Minimal Endpoints\n    /// </summary>\n    /// <name>builder.</name>\n    /// <returns>IEndpointRouteBuilder.</returns>\n    public static IEndpointRouteBuilder MapMinimalEndpoints(this IEndpointRouteBuilder builder)\n    {\n        var scope = builder.ServiceProvider.CreateScope();\n\n        var endpoints = scope.ServiceProvider.GetServices<IMinimalEndpoint>();\n\n        foreach (var endpoint in endpoints)\n        {\n            endpoint.MapEndpoint(builder);\n        }\n\n        return builder;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/ServiceCollectionExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\n\nnamespace BuildingBlocks.Web;\n\npublic static class ServiceCollectionExtensions\n{\n    public static void ReplaceScoped<TService, TImplementation>(this IServiceCollection services)\n        where TService : class\n        where TImplementation : class, TService\n    {\n        services.Unregister<TService>();\n        services.AddScoped<TService, TImplementation>();\n    }\n\n    public static void ReplaceScoped<TService>(this IServiceCollection services,\n        Func<IServiceProvider, TService> implementationFactory)\n        where TService : class\n    {\n        services.Unregister<TService>();\n        services.AddScoped(implementationFactory);\n    }\n\n    public static void ReplaceTransient<TService, TImplementation>(this IServiceCollection services)\n        where TService : class\n        where TImplementation : class, TService\n    {\n        services.Unregister<TService>();\n        services.AddTransient<TService, TImplementation>();\n    }\n\n    public static void ReplaceTransient<TService>(this IServiceCollection services,\n        Func<IServiceProvider, TService> implementationFactory)\n        where TService : class\n    {\n        services.Unregister<TService>();\n        services.AddTransient(implementationFactory);\n    }\n\n    public static void ReplaceSingleton<TService, TImplementation>(this IServiceCollection services)\n        where TService : class\n        where TImplementation : class, TService\n    {\n        services.Unregister<TService>();\n        services.AddSingleton<TService, TImplementation>();\n    }\n\n    public static void ReplaceSingleton<TService>(this IServiceCollection services,\n        Func<IServiceProvider, TService> implementationFactory)\n        where TService : class\n    {\n        services.Unregister<TService>();\n        services.AddSingleton(implementationFactory);\n    }\n\n    public static void Unregister<TService>(this IServiceCollection services)\n    {\n        var descriptor = services.FirstOrDefault(d => d.ServiceType == typeof(TService));\n        services.Remove(descriptor);\n    }\n\n    public static IServiceCollection ReplaceServiceWithSingletonMock<TService>(this IServiceCollection services)\n        where TService : class\n    {\n        var service = services.FirstOrDefault(d => d.ServiceType == typeof(TService));\n        services.Remove(service);\n\n        services.AddSingleton(_ => Substitute.For<TService>());\n        return services;\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/ServiceProviderExtensions.cs",
    "content": "using Microsoft.Extensions.Hosting;\n\nnamespace BuildingBlocks.Web;\n\npublic static class ServiceProviderExtensions\n{\n    public static async Task StartTestHostedServices(\n        this IServiceProvider serviceProvider,\n        Type[] hostedServiceTypes,\n        CancellationToken cancellationToken = default)\n    {\n        foreach (var hostedServiceType in hostedServiceTypes)\n        {\n            if (serviceProvider.GetService(hostedServiceType) is IHostedService hostedService)\n                await hostedService.StartAsync(cancellationToken);\n        }\n    }\n\n    public static async Task StopTestHostedServices(\n        this IServiceProvider serviceProvider,\n        Type[] hostedServiceTypes,\n        CancellationToken cancellationToken = default)\n    {\n        foreach (var hostedServiceType in hostedServiceTypes)\n        {\n            if (serviceProvider.GetService(hostedServiceType) is IHostedService hostedService)\n                await hostedService.StopAsync(cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/BuildingBlocks/Web/SlugifyParameterTransformer.cs",
    "content": "using System.Globalization;\nusing System.Text.RegularExpressions;\nusing Microsoft.AspNetCore.Routing;\n\nnamespace BuildingBlocks.Web;\n\npublic class SlugifyParameterTransformer : IOutboundParameterTransformer\n{\n    public string TransformOutbound(object value)\n    {\n        // Slugify value\n        return value == null\n            ? null\n            : Regex.Replace(value.ToString() ?? string.Empty, \"([a-z])([A-Z])\", \"$1-$2\").ToLower(CultureInfo.CurrentCulture);\n    }\n}"
  },
  {
    "path": "src/Services/Booking/Dockerfile",
    "content": "# ---------- Build Stage ----------\nFROM mcr.microsoft.com/dotnet/sdk:10.0 AS build\nWORKDIR /src\n\n# Copy solution-level files\nCOPY .editorconfig .\nCOPY global.json .\nCOPY Directory.Build.props .\n\n# Copy project files first (for Docker layer caching)\nCOPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/\nCOPY src/Services/Booking/src/Booking/Booking.csproj src/Services/Booking/src/Booking/\nCOPY src/Services/Booking/src/Booking.Api/Booking.Api.csproj src/Services/Booking/src/Booking.Api/\nCOPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/\n\n# Restore dependencies\nRUN dotnet restore src/Services/Booking/src/Booking.Api/Booking.Api.csproj\n\n# Copy the rest of the source\nCOPY src ./src\n\n# Publish (build included)\nRUN dotnet publish src/Services/Booking/src/Booking.Api/Booking.Api.csproj \\\n    -c Release \\\n    -o /app/publish \\\n    --no-restore\n\n# ---------- Runtime Stage ----------\nFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime\nWORKDIR /app\n\nCOPY --from=build /app/publish .\n\nENV ASPNETCORE_URLS=http://+:80\nENV ASPNETCORE_ENVIRONMENT=docker\n\nEXPOSE 80\n\nENTRYPOINT [\"dotnet\", \"Booking.Api.dll\"]"
  },
  {
    "path": "src/Services/Booking/src/Booking/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Unit.Test\")]\n[assembly: InternalsVisibleTo(\"Integration.Test\")]\n[assembly: InternalsVisibleTo(\"EndToEnd.Test\")]"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Dtos/CreateReservation.cs",
    "content": "namespace Booking.Booking.Dtos;\n\npublic record BookingResponseDto(Guid Id, string Name, string FlightNumber, Guid AircraftId, decimal Price,\n    DateTime FlightDate, string SeatNumber, Guid DepartureAirportId, Guid ArriveAirportId, string Description);"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/BookingAlreadyExistException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class BookingAlreadyExistException : AppException\n{\n    public BookingAlreadyExistException(int? code = default) : base(\"Booking already exist!\", HttpStatusCode.Conflict, code)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/FlightNotFoundException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class FlightNotFoundException : AppException\n{\n    public FlightNotFoundException() : base(\"Flight doesn't exist!\", HttpStatusCode.NotFound)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidAircraftIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidAircraftIdException : DomainException\n{\n    public InvalidAircraftIdException(Guid aircraftId)\n        : base($\"aircraftId: '{aircraftId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidArriveAirportIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidArriveAirportIdException : DomainException\n{\n    public InvalidArriveAirportIdException(Guid arriveAirportId)\n        : base($\"arriveAirportId: '{arriveAirportId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidDepartureAirportIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidDepartureAirportIdException : DomainException\n{\n    public InvalidDepartureAirportIdException(Guid departureAirportId)\n        : base($\"departureAirportId: '{departureAirportId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidFlightDateException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidFlightDateException : DomainException\n{\n    public InvalidFlightDateException(DateTime flightDate)\n        : base($\"Flight Date: '{flightDate}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidFlightNumberException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidFlightNumberException : DomainException\n{\n    public InvalidFlightNumberException(string flightNumber)\n        : base($\"Flight Number: '{flightNumber}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidPassengerNameException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidPassengerNameException : DomainException\n{\n    public InvalidPassengerNameException(string passengerName)\n        : base($\"Passenger Name: '{passengerName}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/InvalidPriceException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class InvalidPriceException : DomainException\n{\n    public InvalidPriceException(decimal price)\n        : base($\"Price: '{price}' must be grater than or equal 0.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Exceptions/SeatNumberException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Booking.Booking.Exceptions;\n\npublic class SeatNumberException : DomainException\n{\n    public SeatNumberException(string seatNumber)\n        : base($\"Seat Number: '{seatNumber}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Features/BookingMappings.cs",
    "content": "using Booking.Booking.Dtos;\nusing Mapster;\n\nnamespace Booking.Booking.Features;\n\nusing CreatingBook.V1;\n\npublic class BookingMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.Default.NameMatchingStrategy(NameMatchingStrategy.Flexible);\n\n        config.NewConfig<Models.Booking, BookingResponseDto>()\n            .ConstructUsing(x => new BookingResponseDto(x.Id, x.PassengerInfo.Name, x.Trip.FlightNumber,\n                x.Trip.AircraftId, x.Trip.Price, x.Trip.FlightDate, x.Trip.SeatNumber, x.Trip.DepartureAirportId, x.Trip.ArriveAirportId,\n                x.Trip.Description));\n\n\n        config.NewConfig<CreateBookingRequestDto, CreateBooking>()\n            .ConstructUsing(x => new CreateBooking(x.PassengerId, x.FlightId, x.Description));\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Features/CreatingBook/V1/CreateBooking.cs",
    "content": "namespace Booking.Booking.Features.CreatingBook.V1;\n\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\nusing BuildingBlocks.EventStoreDB.Repository;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Flight;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Passenger;\nusing ValueObjects;\n\npublic record CreateBooking(Guid PassengerId, Guid FlightId, string Description) : ICommand<CreateBookingResult>\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record CreateBookingResult(ulong Id);\n\npublic record BookingCreatedDomainEvent(Guid Id, PassengerInfo PassengerInfo, Trip Trip) : Entity<Guid>, IDomainEvent;\n\npublic record CreateBookingRequestDto(Guid PassengerId, Guid FlightId, string Description);\n\npublic record CreateBookingResponseDto(ulong Id);\n\npublic class CreateBookingEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/booking\", async (CreateBookingRequestDto request,\n                IMediator mediator, IMapper mapper,\n                CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<CreateBooking>(request);\n\n                var result = await mediator.Send(command, cancellationToken);\n\n                var response = result.Adapt<CreateBookingResponseDto>();\n\n                return Results.Ok(response);\n            })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CreateBooking\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Booking\").Build())\n            .Produces<CreateBookingResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Create Booking\")\n            .WithDescription(\"Create Booking\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class CreateBookingValidator : AbstractValidator<CreateBooking>\n{\n    public CreateBookingValidator()\n    {\n        RuleFor(x => x.FlightId).NotNull().WithMessage(\"FlightId is required!\");\n        RuleFor(x => x.PassengerId).NotNull().WithMessage(\"PassengerId is required!\");\n    }\n}\n\ninternal class CreateBookingCommandHandler : ICommandHandler<CreateBooking, CreateBookingResult>\n{\n    private readonly IEventStoreDBRepository<Models.Booking> _eventStoreDbRepository;\n    private readonly ICurrentUserProvider _currentUserProvider;\n    private readonly IEventDispatcher _eventDispatcher;\n    private readonly FlightGrpcService.FlightGrpcServiceClient _flightGrpcServiceClient;\n    private readonly PassengerGrpcService.PassengerGrpcServiceClient _passengerGrpcServiceClient;\n\n    public CreateBookingCommandHandler(IEventStoreDBRepository<Models.Booking> eventStoreDbRepository,\n        ICurrentUserProvider currentUserProvider,\n        IEventDispatcher eventDispatcher,\n        FlightGrpcService.FlightGrpcServiceClient flightGrpcServiceClient,\n        PassengerGrpcService.PassengerGrpcServiceClient passengerGrpcServiceClient)\n    {\n        _eventStoreDbRepository = eventStoreDbRepository;\n        _currentUserProvider = currentUserProvider;\n        _eventDispatcher = eventDispatcher;\n        _flightGrpcServiceClient = flightGrpcServiceClient;\n        _passengerGrpcServiceClient = passengerGrpcServiceClient;\n    }\n\n    public async Task<CreateBookingResult> Handle(CreateBooking command, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(command, nameof(command));\n\n        var flight =\n            await _flightGrpcServiceClient.GetByIdAsync(new Flight.GetByIdRequest { Id = command.FlightId.ToString() }, cancellationToken: cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFoundException();\n        }\n\n        var passenger =\n            await _passengerGrpcServiceClient.GetByIdAsync(new Passenger.GetByIdRequest { Id = command.PassengerId.ToString() }, cancellationToken: cancellationToken);\n\n        var emptySeat = (await _flightGrpcServiceClient\n                .GetAvailableSeatsAsync(new GetAvailableSeatsRequest { FlightId = command.FlightId.ToString() }, cancellationToken: cancellationToken)\n                .ResponseAsync)\n            ?.SeatDtos?.FirstOrDefault();\n\n        var reservation = await _eventStoreDbRepository.Find(command.Id, cancellationToken);\n\n        if (reservation is not null && !reservation.IsDeleted)\n        {\n            throw new BookingAlreadyExistException();\n        }\n\n        var aggrigate = Models.Booking.Create(command.Id, PassengerInfo.Of(passenger.PassengerDto?.Name), Trip.Of(\n                flight.FlightDto.FlightNumber, new Guid(flight.FlightDto.AircraftId),\n                new Guid(flight.FlightDto.DepartureAirportId),\n                new Guid(flight.FlightDto.ArriveAirportId), flight.FlightDto.FlightDate.ToDateTime(),\n                (decimal)flight.FlightDto.Price, command.Description,\n                emptySeat?.SeatNumber),\n            false, _currentUserProvider.GetCurrentUserId());\n\n        await _eventDispatcher.SendAsync(aggrigate.DomainEvents, cancellationToken: cancellationToken);\n\n        await _flightGrpcServiceClient.ReserveSeatAsync(new ReserveSeatRequest\n        {\n            FlightId = flight.FlightDto.Id,\n            SeatNumber = emptySeat?.SeatNumber\n        }, cancellationToken: cancellationToken);\n\n        var result = await _eventStoreDbRepository.Add(\n            aggrigate,\n            cancellationToken);\n\n        return new CreateBookingResult(result);\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Models/Booking.cs",
    "content": "using BuildingBlocks.EventStoreDB.Events;\n\nnamespace Booking.Booking.Models;\n\nusing Features.CreatingBook.V1;\nusing ValueObjects;\n\npublic record Booking : AggregateEventSourcing<Guid>\n{\n    public Trip Trip { get; private set; }\n    public PassengerInfo PassengerInfo { get; private set; }\n\n    public static Booking Create(Guid id, PassengerInfo passengerInfo, Trip trip, bool isDeleted = false, long? userId = null)\n    {\n        var booking = new Booking { Id = id, Trip = trip, PassengerInfo = passengerInfo, IsDeleted = isDeleted };\n\n        var @event = new BookingCreatedDomainEvent(booking.Id, booking.PassengerInfo, booking.Trip)\n        {\n            IsDeleted = booking.IsDeleted,\n            CreatedAt = DateTime.Now,\n            CreatedBy = userId\n        };\n\n        booking.AddDomainEvent(@event);\n        booking.Apply(@event);\n\n        return booking;\n    }\n\n    public override void When(object @event)\n    {\n        switch (@event)\n        {\n            case BookingCreatedDomainEvent bookingCreated:\n                {\n                    Apply(bookingCreated);\n                    return;\n                }\n        }\n    }\n\n    private void Apply(BookingCreatedDomainEvent @event)\n    {\n        Id = @event.Id;\n        Trip = @event.Trip;\n        PassengerInfo = @event.PassengerInfo;\n        IsDeleted = @event.IsDeleted;\n        Version++;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/Models/BookingReadModel.cs",
    "content": "namespace Booking.Booking.Models;\n\nusing ValueObjects;\n\npublic class BookingReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid BookId { get; init; }\n    public required Trip Trip { get; init; }\n    public required PassengerInfo PassengerInfo { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/ValueObjects/PassengerInfo.cs",
    "content": "namespace Booking.Booking.ValueObjects;\n\nusing Exceptions;\n\npublic record PassengerInfo\n{\n    public string Name { get; }\n\n    private PassengerInfo(string name)\n    {\n        Name = name;\n    }\n\n    public static PassengerInfo Of(string name)\n    {\n        if (string.IsNullOrWhiteSpace(name))\n        {\n            throw new InvalidPassengerNameException(name);\n        }\n\n        return new PassengerInfo(name);\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking/ValueObjects/Trip.cs",
    "content": "namespace Booking.Booking.ValueObjects;\n\nusing Exceptions;\n\npublic record Trip\n{\n    public string FlightNumber { get; }\n    public Guid AircraftId { get; }\n    public Guid DepartureAirportId { get; }\n    public Guid ArriveAirportId { get; }\n    public DateTime FlightDate { get; }\n    public decimal Price { get; }\n    public string Description { get; }\n    public string SeatNumber { get; }\n\n    private Trip(string flightNumber, Guid aircraftId, Guid departureAirportId, Guid arriveAirportId,\n        DateTime flightDate, decimal price, string description, string seatNumber)\n    {\n        FlightNumber = flightNumber;\n        AircraftId = aircraftId;\n        DepartureAirportId = departureAirportId;\n        ArriveAirportId = arriveAirportId;\n        FlightDate = flightDate;\n        Price = price;\n        Description = description;\n        SeatNumber = seatNumber;\n    }\n\n    public static Trip Of(string flightNumber, Guid aircraftId, Guid departureAirportId, Guid arriveAirportId,\n        DateTime flightDate, decimal price, string description, string seatNumber)\n    {\n        if (string.IsNullOrWhiteSpace(flightNumber))\n        {\n            throw new InvalidFlightNumberException(flightNumber);\n        }\n\n        if (aircraftId == Guid.Empty)\n        {\n            throw new InvalidAircraftIdException(aircraftId);\n        }\n\n        if (departureAirportId == Guid.Empty)\n        {\n            throw new InvalidDepartureAirportIdException(departureAirportId);\n        }\n\n        if (arriveAirportId == Guid.Empty)\n        {\n            throw new InvalidArriveAirportIdException(departureAirportId);\n        }\n\n        if (flightDate == default)\n        {\n            throw new InvalidFlightDateException(flightDate);\n        }\n\n        if (price < 0)\n        {\n            throw new InvalidPriceException(price);\n        }\n\n        if (string.IsNullOrWhiteSpace(seatNumber))\n        {\n            throw new SeatNumberException(seatNumber);\n        }\n\n        return new Trip(flightNumber, aircraftId, departureAirportId, arriveAirportId, flightDate, price, description, seatNumber);\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Booking.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.Tools\" Version=\"2.78.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"GrpcClient\\Protos\\flight.proto\" GrpcServices=\"Both\" />\n    <Protobuf Include=\"GrpcClient\\Protos\\passenger.proto\" GrpcServices=\"Both\" />\n    <Folder Include=\"GrpcClient\\Protos\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\Aspire\\src\\ServiceDefaults\\ServiceDefaults.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Booking/src/Booking/BookingEventMapper.cs",
    "content": "using BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.Event;\n\nnamespace Booking;\n\nusing Booking.Features.CreatingBook.V1;\n\npublic sealed class BookingEventMapper : IEventMapper\n{\n    public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            BookingCreatedDomainEvent e => new BookingCreated(e.Id),\n            _ => null\n        };\n    }\n\n    public IInternalCommand? MapToInternalCommand(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            _ => null\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/BookingProjection.cs",
    "content": "using Booking.Data;\nusing BuildingBlocks.EventStoreDB.Events;\nusing BuildingBlocks.EventStoreDB.Projections;\nusing MediatR;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace Booking;\n\nusing Booking.Features.CreatingBook.V1;\nusing Booking.Models;\nusing MassTransit;\n\npublic class BookingProjection : IProjectionProcessor\n{\n    private readonly BookingReadDbContext _bookingReadDbContext;\n\n    public BookingProjection(BookingReadDbContext bookingReadDbContext)\n    {\n        _bookingReadDbContext = bookingReadDbContext;\n    }\n\n    public async Task ProcessEventAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default)\n        where T : INotification\n    {\n        switch (streamEvent.Data)\n        {\n            case BookingCreatedDomainEvent bookingCreatedDomainEvent:\n                await Apply(bookingCreatedDomainEvent, cancellationToken);\n                break;\n        }\n    }\n\n    private async Task Apply(BookingCreatedDomainEvent @event, CancellationToken cancellationToken = default)\n    {\n        var reservation =\n            await _bookingReadDbContext.Booking.AsQueryable().SingleOrDefaultAsync(x => x.Id == @event.Id && !x.IsDeleted,\n                cancellationToken);\n\n        if (reservation == null)\n        {\n            var bookingReadModel = new BookingReadModel\n            {\n                Id = NewId.NextGuid(),\n                Trip = @event.Trip,\n                BookId = @event.Id,\n                PassengerInfo = @event.PassengerInfo,\n                IsDeleted = @event.IsDeleted\n            };\n\n            await _bookingReadDbContext.Booking.InsertOneAsync(bookingReadModel, cancellationToken: cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/BookingRoot.cs",
    "content": "namespace Booking;\n\npublic class BookingRoot\n{\n\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Configuration/GrpcOptions.cs",
    "content": "namespace Booking.Configuration;\n\npublic class GrpcOptions\n{\n    public string FlightAddress { get; set; }\n    public string PassengerAddress { get; set; }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Data/BookingReadDbContext.cs",
    "content": "using BuildingBlocks.Mongo;\nusing Humanizer;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace Booking.Data;\n\nusing Booking.Models;\n\npublic class BookingReadDbContext : MongoDbContext\n{\n    public BookingReadDbContext(IOptions<MongoOptions> options) : base(options)\n    {\n        Booking = GetCollection<BookingReadModel>(nameof(Booking).Underscore());\n    }\n\n    public IMongoCollection<BookingReadModel> Booking { get; }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Extensions/Infrastructure/GrpcClientExtensions.cs",
    "content": "using Booking.Configuration;\nusing BuildingBlocks.Web;\nusing Flight;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Http.Resilience;\nusing Passenger;\nusing Polly;\n\nnamespace Booking.Extensions.Infrastructure;\n\npublic static class GrpcClientExtensions\n{\n    public static IServiceCollection AddGrpcClients(this IServiceCollection services)\n    {\n        var grpcOptions = services.GetOptions<GrpcOptions>(\"Grpc\");\n        var resilienceOptions = services.GetOptions<HttpStandardResilienceOptions>(\n            nameof(HttpStandardResilienceOptions)\n        );\n\n        services\n            .AddGrpcClient<FlightGrpcService.FlightGrpcServiceClient>(o =>\n            {\n                o.Address = new Uri(grpcOptions.FlightAddress);\n            })\n            .AddResilienceHandler(\n                \"grpc-flight-resilience\",\n                options =>\n                {\n                    var timeSpan = TimeSpan.FromMinutes(1);\n\n                    options.AddRetry(new HttpRetryStrategyOptions { MaxRetryAttempts = 3 });\n\n                    options.AddCircuitBreaker(\n                        new HttpCircuitBreakerStrategyOptions { SamplingDuration = timeSpan * 2 }\n                    );\n\n                    options.AddTimeout(new HttpTimeoutStrategyOptions { Timeout = timeSpan * 3 });\n                }\n            );\n\n        services\n            .AddGrpcClient<PassengerGrpcService.PassengerGrpcServiceClient>(o =>\n            {\n                o.Address = new Uri(grpcOptions.PassengerAddress);\n            })\n            .AddResilienceHandler(\n                \"grpc-passenger-resilience\",\n                options =>\n                {\n                    var timeSpan = TimeSpan.FromMinutes(1);\n\n                    options.AddRetry(new HttpRetryStrategyOptions { MaxRetryAttempts = 3 });\n\n                    options.AddCircuitBreaker(\n                        new HttpCircuitBreakerStrategyOptions { SamplingDuration = timeSpan * 2 }\n                    );\n\n                    options.AddTimeout(new HttpTimeoutStrategyOptions { Timeout = timeSpan * 3 });\n                }\n            );\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "src/Services/Booking/src/Booking/Extensions/Infrastructure/InfrastructureExtensions.cs",
    "content": "using Booking.Data;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.EventStoreDB;\nusing BuildingBlocks.HealthCheck;\nusing BuildingBlocks.Jwt;\nusing BuildingBlocks.Mapster;\nusing BuildingBlocks.MassTransit;\nusing BuildingBlocks.Mongo;\nusing BuildingBlocks.OpenApi;\nusing BuildingBlocks.OpenTelemetryCollector;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.ProblemDetails;\nusing BuildingBlocks.Web;\nusing Figgle;\nusing Figgle.Fonts;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing ServiceDefaults;\n\nnamespace Booking.Extensions.Infrastructure;\n\npublic static class InfrastructureExtensions\n{\n    public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder)\n    {\n        var configuration = builder.Configuration;\n        var env = builder.Environment;\n\n        builder.AddServiceDefaults();\n\n        builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();\n        builder.Services.AddScoped<IEventMapper, BookingEventMapper>();\n        builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();\n\n        builder.Services.Configure<ApiBehaviorOptions>(options =>\n        {\n            options.SuppressModelStateInvalidFilter = true;\n        });\n\n        var appOptions = builder.Services.GetOptions<AppOptions>(nameof(AppOptions));\n\n        Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));\n\n        builder.AddPersistMessageProcessor(nameof(PersistMessage));\n        builder.AddMongoDbContext<BookingReadDbContext>();\n\n        builder.Services.AddEndpointsApiExplorer();\n        builder.Services.AddJwt();\n        builder.Services.AddHttpContextAccessor();\n        builder.Services.AddAspnetOpenApi();\n        builder.Services.AddCustomVersioning();\n        builder.Services.AddCustomMediatR();\n        builder.Services.AddValidatorsFromAssembly(typeof(BookingRoot).Assembly);\n        builder.Services.AddProblemDetails();\n        builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly);\n        builder.Services.AddCustomMassTransit(env, TransportType.RabbitMq, typeof(BookingRoot).Assembly);\n        builder.Services.AddTransient<AuthHeaderHandler>();\n\n        // ref: https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventStoreDB/ECommerce\n        builder.Services.AddEventStore(configuration, typeof(BookingRoot).Assembly)\n            .AddEventStoreDBSubscriptionToAll();\n\n        builder.Services.AddGrpcClients();\n\n        return builder;\n    }\n\n\n    public static WebApplication UseInfrastructure(this WebApplication app)\n    {\n        var env = app.Environment;\n        var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));\n\n        app.UseAuthentication();\n        app.UseAuthorization();\n\n        app.UseServiceDefaults();\n\n        app.UseCustomProblemDetails();\n        app.UseCorrelationId();\n        app.MapGet(\"/\", x => x.Response.WriteAsync(appOptions.Name));\n\n        if (env.IsDevelopment())\n        {\n            app.UseAspnetOpenApi();\n        }\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/Extensions/Infrastructure/MediatRExtensions.cs",
    "content": "using BuildingBlocks.Logging;\nusing BuildingBlocks.Validation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Booking.Extensions.Infrastructure;\n\npublic static class MediatRExtensions\n{\n    public static IServiceCollection AddCustomMediatR(this IServiceCollection services)\n    {\n        services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(BookingRoot).Assembly));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking/GrpcClient/Protos/flight.proto",
    "content": "syntax = \"proto3\";\n\npackage flight;\nimport \"google/protobuf/timestamp.proto\";\n\nservice FlightGrpcService {\n\n  rpc GetById (GetByIdRequest) returns (GetFlightByIdResult);\n  rpc GetAvailableSeats (GetAvailableSeatsRequest) returns (GetAvailableSeatsResult);\n  rpc ReserveSeat (ReserveSeatRequest) returns (ReserveSeatResult);\n}\n\nmessage GetByIdRequest {\n  string Id = 1;\n}\n\nmessage GetFlightByIdResult{\n  FlightResponse FlightDto = 1;\n}\n\nmessage GetAvailableSeatsResult{\nrepeated SeatDtoResponse SeatDtos = 1;\n}\n\nmessage ReserveSeatResult{\n    string Id = 1;\n}\n\nmessage FlightResponse {\n  string Id = 1;\n  string FlightNumber = 2;\n  string AircraftId = 3;\n  string DepartureAirportId = 4;\n  google.protobuf.Timestamp DepartureDate = 5;\n  google.protobuf.Timestamp ArriveDate = 6;\n  string ArriveAirportId = 7;\n  double DurationMinutes = 8;\n  google.protobuf.Timestamp FlightDate = 9;\n  FlightStatus Status = 10;\n  double Price = 11;\n  string FlightId = 12;\n}\n\nmessage GetAvailableSeatsRequest {\n  string FlightId = 1;\n}\n\nmessage SeatDtoResponse {\n  string Id = 1;\n  string SeatNumber = 2;\n  SeatType Type = 3;\n  SeatClass Class = 4;\n  string FlightId = 5;\n}\n\n\nmessage ReserveSeatRequest {\n  string FlightId = 1;\n  string SeatNumber = 2;\n}\n\n\n    enum FlightStatus {\n      FLIGHT_STATUS_UNKNOWN = 0;\n      FLIGHT_STATUS_FLYING = 1;\n      FLIGHT_STATUS_DELAY = 2;\n      FLIGHT_STATUS_CANCELED = 3;\n      FLIGHT_STATUS_COMPLETED = 4;\n    }\n\n\n    enum SeatType {\n        SEAT_TYPE_UNKNOWN = 0;\n        SEAT_TYPE_WINDOW = 1;\n        SEAT_TYPE_MIDDLE = 2;\n        SEAT_TYPE_AISLE = 3;\n    }\n\n\n    enum SeatClass {\n        SEAT_CLASS_UNKNOWN = 0;\n        SEAT_CLASS_FIRST_CLASS = 1;\n        SEAT_CLASS_BUSINESS = 2;\n        SEAT_CLASS_ECONOMY = 3;\n    }\n"
  },
  {
    "path": "src/Services/Booking/src/Booking/GrpcClient/Protos/passenger.proto",
    "content": "syntax = \"proto3\";\n\npackage passenger;\n\nservice PassengerGrpcService {\n\n  rpc GetById (GetByIdRequest) returns (GetPassengerByIdResult);\n}\n\nmessage GetByIdRequest {\n  string Id = 1;\n}\n\nmessage GetPassengerByIdResult {\n   PassengerResponse PassengerDto = 1;\n}\n\nmessage PassengerResponse {\n  string Id = 1;\n  string Name = 2;\n  string PassportNumber = 3;\n  PassengerType PassengerType = 4;\n  int32 Age = 5;\n  string Email = 6;\n}\n\n\n    enum PassengerType {\n        PASSENGER_TYPE_UNKNOWN = 0;\n        PASSENGER_TYPE_MALE = 1;\n        PASSENGER_TYPE_FEMALE = 2;\n        PASSENGER_TYPE_BABY = 3;\n    }\n\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/Booking.Api.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Booking\\Booking.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/Program.cs",
    "content": "using Booking;\nusing Booking.Extensions.Infrastructure;\nusing BuildingBlocks.Web;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddMinimalEndpoints(assemblies: typeof(BookingRoot).Assembly);\nbuilder.AddInfrastructure();\n\nvar app = builder.Build();\n\napp.MapMinimalEndpoints();\napp.UseInfrastructure();\n\napp.Run();\n\nnamespace Booking.Api\n{\n    public partial class Program\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/Properties/launchSettings.json",
    "content": "{\n    \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n    \"profiles\": {\n        \"Booking.Api\": {\n            \"commandName\": \"Project\",\n            \"dotnetRunMessages\": true,\n            \"launchUrl\": \"swagger\",\n            \"launchBrowser\": true,\n            \"applicationUrl\": \"http://localhost:6010;https://localhost:5010\",\n            \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/appsettings.Development.json",
    "content": "{\n}\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/appsettings.docker.json",
    "content": "{\n    \"App\": \"Booking-Service\",\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"EventStoreOptions\": {\n        \"ConnectionString\": \"esdb://eventstore:2113?tls=false\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://mongo:27017\",\n        \"DatabaseName\": \"booking-db\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"rabbitmq\",\n        \"ExchangeName\": \"booking\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://identity:80\",\n        \"Audience\": \"booking-api\"\n    },\n    \"Grpc\": {\n        \"FlightAddress\": \"flight:5003\",\n        \"PassengerAddress\": \"passenger:5003\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/appsettings.json",
    "content": "{\n    \"AppOptions\": {\n        \"Name\": \"Booking-Service\"\n    },\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://localhost:6005\",\n        \"Audience\": \"booking-api\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"booking\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"Grpc\": {\n        \"FlightAddress\": \"https://localhost:5003\",\n        \"PassengerAddress\": \"https://localhost:5012\"\n    },\n    \"PolicyOptions\": {\n        \"Retry\": {\n            \"RetryCount\": 3,\n            \"SleepDuration\": 1\n        },\n        \"CircuitBreaker\": {\n            \"RetryCount\": 5,\n            \"BreakDuration\": 30\n        }\n    },\n    \"EventStoreOptions\": {\n        \"ConnectionString\": \"esdb://localhost:2113?tls=false\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://localhost:27017\",\n        \"DatabaseName\": \"booking-db\"\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"HealthOptions\": {\n        \"Enabled\": false\n    },\n    \"ObservabilityOptions\": {\n        \"InstrumentationName\": \"booking_service\",\n        \"OTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4317\"\n        },\n        \"AspireDashboardOTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4319\"\n        },\n        \"ZipkinOptions\": {\n            \"HttpExporterEndpoint\": \"http://localhost:9411/api/v2/spans\"\n        },\n        \"JaegerOptions\": {\n            \"OTLPGrpcExporterEndpoint\": \"http://localhost:14317\",\n            \"HttpExporterEndpoint\": \"http://localhost:14268/api/traces\"\n        },\n        \"UsePrometheusExporter\": true,\n        \"UseOTLPExporter\": true,\n        \"UseAspireOTLPExporter\": true,\n        \"UseGrafanaExporter\": false,\n        \"ServiceName\": \"Booking Service\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Booking/src/Booking.Api/appsettings.test.json",
    "content": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"booking\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://localhost:27017\",\n        \"DatabaseName\": \"booking-db-test\"\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    }\n}\n"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Booking/Features/CreateBookingTests.cs",
    "content": "using System.Threading.Tasks;\nusing Booking.Api;\nusing Booking.Data;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight;\nusing FluentAssertions;\nusing Grpc.Core;\nusing Grpc.Core.Testing;\nusing Integration.Test.Fakes;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing NSubstitute;\nusing Passenger;\nusing Xunit;\nusing GetByIdRequest = Flight.GetByIdRequest;\n\nnamespace Integration.Test.Booking.Features\n{\n    public class CreateBookingTests : BookingIntegrationTestBase\n    {\n        public CreateBookingTests(TestReadFixture<Program, BookingReadDbContext> integrationTestFixture)\n            : base(integrationTestFixture) { }\n\n        protected override void RegisterTestsServices(IServiceCollection services)\n        {\n            MockFlightGrpcServices(services);\n            MockPassengerGrpcServices(services);\n        }\n\n        [Fact]\n        public async Task should_create_booking_to_event_store_currectly()\n        {\n            // Arrange\n            var command = new FakeCreateBookingCommand().Generate();\n\n            // Act\n            var response = await Fixture.SendAsync(command);\n\n            // Assert\n            response?.Id.Should().BeGreaterThanOrEqualTo(0);\n\n            (await Fixture.WaitForPublishing<BookingCreated>()).Should().Be(true);\n        }\n\n        private void MockPassengerGrpcServices(IServiceCollection services)\n        {\n            services.Replace(\n                ServiceDescriptor.Singleton(x =>\n                {\n                    var mockPassenger = Substitute.For<PassengerGrpcService.PassengerGrpcServiceClient>();\n\n                    mockPassenger\n                        .GetByIdAsync(Arg.Any<Passenger.GetByIdRequest>())\n                        .Returns(\n                            TestCalls.AsyncUnaryCall(\n                                Task.FromResult(FakePassengerResponse.Generate()),\n                                Task.FromResult(new Metadata()),\n                                () => Status.DefaultSuccess,\n                                () => new Metadata(),\n                                () => { }\n                            )\n                        );\n\n                    return mockPassenger;\n                })\n            );\n        }\n\n        private void MockFlightGrpcServices(IServiceCollection services)\n        {\n            services.Replace(\n                ServiceDescriptor.Singleton(x =>\n                {\n                    var mockFlight = Substitute.For<FlightGrpcService.FlightGrpcServiceClient>();\n\n                    mockFlight\n                        .GetByIdAsync(Arg.Any<GetByIdRequest>())\n                        .Returns(\n                            TestCalls.AsyncUnaryCall(\n                                Task.FromResult(FakeFlightResponse.Generate()),\n                                Task.FromResult(new Metadata()),\n                                () => Status.DefaultSuccess,\n                                () => new Metadata(),\n                                () => { }\n                            )\n                        );\n\n                    mockFlight\n                        .GetAvailableSeatsAsync(Arg.Any<GetAvailableSeatsRequest>())\n                        .Returns(\n                            TestCalls.AsyncUnaryCall(\n                                Task.FromResult(FakeGetAvailableSeatsResponse.Generate()),\n                                Task.FromResult(new Metadata()),\n                                () => Status.DefaultSuccess,\n                                () => new Metadata(),\n                                () => { }\n                            )\n                        );\n\n                    mockFlight\n                        .ReserveSeatAsync(Arg.Any<ReserveSeatRequest>())\n                        .Returns(\n                            TestCalls.AsyncUnaryCall(\n                                Task.FromResult(FakeReserveSeatResponse.Generate()),\n                                Task.FromResult(new Metadata()),\n                                () => Status.DefaultSuccess,\n                                () => new Metadata(),\n                                () => { }\n                            )\n                        );\n\n                    return mockFlight;\n                })\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/BookingIntegrationTestBase.cs",
    "content": "using Booking.Data;\nusing BuildingBlocks.TestBase;\nusing Xunit;\n\nnamespace Integration.Test;\n\n[Collection(IntegrationTestCollection.Name)]\npublic class BookingIntegrationTestBase : TestReadBase<Program, BookingReadDbContext>\n{\n    public BookingIntegrationTestBase(TestReadFixture<Program, BookingReadDbContext> integrationTestFixture)\n        : base(integrationTestFixture) { }\n}\n\n[CollectionDefinition(Name)]\npublic class IntegrationTestCollection : ICollectionFixture<TestReadFixture<Program, BookingReadDbContext>>\n{\n    public const string Name = \"Booking Integration Test\";\n}\n"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Fakes/FakeCreateBookingCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Integration.Test.Fakes;\n\nusing System;\nusing global::Booking.Booking.Features.CreatingBook.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateBookingCommand : AutoFaker<CreateBooking>\n{\n    public FakeCreateBookingCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightId, _ => new Guid(\"3c5c0000-97c6-fc34-2eb9-08db322230c9\"));\n        RuleFor(r => r.PassengerId, _ => new Guid(\"4c5c8888-97c6-fc34-2eb9-18db322230c1\"));\n    }\n}"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Fakes/FakeFlightResponse.cs",
    "content": "using System;\nusing AutoBogus;\nusing Flight;\nusing Google.Protobuf.WellKnownTypes;\n\nnamespace Integration.Test.Fakes;\n\npublic static class FakeFlightResponse\n{\n    public static GetFlightByIdResult Generate()\n    {\n        var flightMock = new GetFlightByIdResult\n        {\n            FlightDto = new FlightResponse\n            {\n                Id = new Guid(\"3c5c0000-97c6-fc34-2eb9-08db322230c9\").ToString(),\n                Price = 100,\n                Status = FlightStatus.Completed,\n                AircraftId = new Guid(\"3c5c0000-97c6-fc34-fcd3-08db322230c8\").ToString(),\n                ArriveAirportId = new Guid(\"3c5c0000-97c6-fc34-a0cb-08db322230c8\").ToString(),\n                ArriveDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),\n                DepartureDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),\n                FlightDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),\n                FlightNumber = \"1500B\",\n                DepartureAirportId = new Guid(\"3c5c0000-97c6-fc34-fc3c-08db322230c8\").ToString()\n            }\n        };\n\n        return flightMock;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Fakes/FakeGetAvailableSeatsResponse.cs",
    "content": "using System.Collections.Generic;\nusing Flight;\n\nnamespace Integration.Test.Fakes;\n\nusing System;\nusing MassTransit;\n\npublic static class FakeGetAvailableSeatsResponse\n{\n    public static GetAvailableSeatsResult Generate()\n    {\n        var result = new GetAvailableSeatsResult();\n        result.SeatDtos.AddRange(new List<SeatDtoResponse>\n        {\n            new SeatDtoResponse()\n            {\n                FlightId = new Guid(\"3c5c0000-97c6-fc34-2eb9-08db322230c9\").ToString(),\n                Class = SeatClass.Economy,\n                Type = SeatType.Aisle,\n                SeatNumber = \"33F\",\n                Id = NewId.NextGuid().ToString()\n            },\n            new SeatDtoResponse()\n            {\n                FlightId = new Guid(\"3c5c0000-97c6-fc34-2eb9-08db322230c9\").ToString(),\n                Class = SeatClass.Economy,\n                Type = SeatType.Window,\n                SeatNumber = \"22D\",\n                Id = NewId.NextGuid().ToString()\n            }\n        });\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Fakes/FakePassengerResponse.cs",
    "content": "namespace Integration.Test.Fakes;\n\nusing MassTransit;\nusing Passenger;\n\npublic static class FakePassengerResponse\n{\n    public static GetPassengerByIdResult Generate()\n    {\n        var result = new GetPassengerByIdResult\n        {\n            PassengerDto = new PassengerResponse()\n            {\n                Id = NewId.NextGuid().ToString(),\n                Name = \"Test\",\n                PassportNumber = \"121618\"\n            }\n        };\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Fakes/FakeReserveSeatResponse.cs",
    "content": "namespace Integration.Test.Fakes;\n\nusing Flight;\nusing MassTransit;\n\npublic static class FakeReserveSeatResponse\n{\n    public static ReserveSeatResult Generate()\n    {\n        var result = new ReserveSeatResult();\n        result.Id = NewId.NextGuid().ToString();\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/Integration.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Booking.Api\\Booking.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Booking/tests/IntegrationTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Booking/tests/PerformanceTest/.openapi-generator/FILES",
    "content": ".openapi-generator-ignore\nREADME.md\nscript.js\n"
  },
  {
    "path": "src/Services/Booking/tests/PerformanceTest/.openapi-generator/VERSION",
    "content": "6.6.0-SNAPSHOT\n"
  },
  {
    "path": "src/Services/Booking/tests/PerformanceTest/.openapi-generator-ignore",
    "content": "# OpenAPI Generator Ignore\n# Generated by openapi-generator https://github.com/openapitools/openapi-generator\n\n# Use this file to prevent files from being overwritten by the generator.\n# The patterns follow closely to .gitignore or .dockerignore.\n\n# As an example, the C# client generator defines ApiClient.cs.\n# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:\n#ApiClient.cs\n\n# You can match any string of characters against a directory, file or extension with a single asterisk (*):\n#foo/*/qux\n# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux\n\n# You can recursively match patterns against a directory, file or extension with a double asterisk (**):\n#foo/**/qux\n# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux\n\n# You can also negate patterns with an exclamation (!).\n# For example, you can ignore all files in a docs folder with the file extension .md:\n#docs/*.md\n# Then explicitly reverse the ignore rule for a single file:\n#!docs/README.md\n"
  },
  {
    "path": "src/Services/Booking/tests/PerformanceTest/README.md",
    "content": "# Generated k6 script\n\nThe `script.js` file contains most of the Swagger/OpenAPI specification and you can customize it to your needs.\n\nGlobal header variables are defined at the top of the file, like `api_key`. Each path in the specification is converted into a [group](https://docs.k6.io/docs/tags-and-groups) in k6 and each group contains all the request methods related to that path. Path and query parameters are extracted from the specification and put at the start of the group. The URL is constructed from the base URL plus path and query.\n\nIf the Swagger/OpenAPI specification used as the input spec contains examples at parameter level, those will be extracted and utilized as parameter values. The `handleParamValue` custom Mustache lambda registered for use in the K6 `script.mustache` template handles the conditional checks, formatting, and outputting of parameter values. If a given parameter has value specified – either in `example` or `examples` field, defined at the parameter level – that value will be used. For list (`examples`), entire list will be output in the generated script and the first element from that list will be assigned as parameter value. If a given parameter does not have an example defined, a placeholder value with `TODO_EDIT_THE_` prefix will be generated for that parameter, and you will have to assign a value before you can run the script. In other words, you can now generate K6 test scripts which are ready to run, provided the Swagger/OpenAPI specification used as the input spec contains examples for all of the path/query parameters; see `modules/openapi-generator/src/test/resources/3_0/examples.yaml` for an example of such specification, and https://swagger.io/docs/specification/adding-examples/ for more information about adding examples.\n\nk6 specific parameters are in the [`params`](https://docs.k6.io/docs/params-k6http) object, and `body` contains the [request](https://docs.k6.io/docs/http-requests) body which is in the form of `identifier: type`, which the `type` should be substituted by a proper value. Then goes the request and the check.\n\n[Check](https://docs.k6.io/docs/checks) are like asserts but differ in that they don't halt execution, instead they just store the result of the check, pass or fail, and let the script execution continue.\n\nEach request is always followed by a 0.1 second [sleep](https://docs.k6.io/docs/sleep-t-1) to prevent the script execution from flooding the system with too many requests simultaneously.\n\nNote that the default iteration count and VU count is 1. So each request in each group will be executed once. For more information, see the [k6 options](https://docs.k6.io/docs/options).\n"
  },
  {
    "path": "src/Services/Booking/tests/PerformanceTest/script.js",
    "content": "/*\n * APIs\n * An example application with OpenAPI, Swashbuckle, and API versioning.\n *\n * OpenAPI spec version: 1.0\n * Contact:\n *\n * NOTE: This class is auto generated by OpenAPI Generator.\n * https://github.com/OpenAPITools/openapi-generator\n *\n * OpenAPI generator version: 6.6.0-SNAPSHOT\n */\n\n\nimport http from \"k6/http\";\nimport { group, check, sleep } from \"k6\";\n\nconst BASE_URL = \"/\";\n// Sleep duration between successive requests.\n// You might want to edit the value of this variable or remove calls to the sleep function on the script.\nconst SLEEP_DURATION = 0.1;\n// Global variables should be initialized.\n\nexport default function() {\n    group(\"/api/v1/booking\", () => {\n\n        // Request No. 1: CreateBooking\n        {\n            let url = BASE_URL + `/api/v1/booking`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"passengerId\": \"uuid\", \"flightId\": \"uuid\", \"description\": \"string\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n}\n"
  },
  {
    "path": "src/Services/Booking/tests/tests.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"IntegrationTest\\Integration.Test.csproj\", \"{AC2806BF-F80B-4075-8240-0D3E87E41FEA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Services/Flight/Dockerfile",
    "content": "# ---------- Build Stage ----------\nFROM mcr.microsoft.com/dotnet/sdk:10.0 AS build\nWORKDIR /src\n\n# Copy solution-level files\nCOPY .editorconfig .\nCOPY global.json .\nCOPY Directory.Build.props .\n\n# Copy project files first (better layer caching)\nCOPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/\nCOPY src/Services/Flight/src/Flight/Flight.csproj src/Services/Flight/src/Flight/\nCOPY src/Services/Flight/src/Flight.Api/Flight.Api.csproj src/Services/Flight/src/Flight.Api/\nCOPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/\n\n# Restore dependencies\nRUN dotnet restore src/Services/Flight/src/Flight.Api/Flight.Api.csproj\n\n# Copy remaining source code\nCOPY src ./src\n\n# Publish (build included)\nRUN dotnet publish src/Services/Flight/src/Flight.Api/Flight.Api.csproj \\\n    -c Release \\\n    -o /app/publish \\\n    --no-restore\n\n# ---------- Runtime Stage ----------\nFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime\nWORKDIR /app\n\nCOPY --from=build /app/publish .\n\nENV ASPNETCORE_URLS=http://+:80\nENV ASPNETCORE_ENVIRONMENT=docker\n\nEXPOSE 80\n\nENTRYPOINT [\"dotnet\", \"Flight.Api.dll\"]"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Dtos/AircraftDto.cs",
    "content": "namespace Flight.Aircrafts.Dtos;\n\npublic record AircraftDto(long Id, string Name, string Model, int ManufacturingYear);"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Exceptions/AircraftAlreadyExistException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Flight.Aircrafts.Exceptions;\n\npublic class AircraftAlreadyExistException : AppException\n{\n    public AircraftAlreadyExistException() : base(\"Aircraft already exist!\", HttpStatusCode.Conflict)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidAircraftIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Aircrafts.Exceptions;\n\npublic class InvalidAircraftIdException : DomainException\n{\n    public InvalidAircraftIdException(Guid aircraftId)\n        : base($\"AircraftId: '{aircraftId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidManufacturingYearException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Aircrafts.Exceptions;\n\npublic class InvalidManufacturingYearException : DomainException\n{\n    public InvalidManufacturingYearException() : base(\"ManufacturingYear must be greater than 1900\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidModelException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Aircrafts.Exceptions;\n\npublic class InvalidModelException : DomainException\n{\n    public InvalidModelException() : base(\"Model cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidNameException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Aircrafts.Exceptions;\n\npublic class InvalidNameException : DomainException\n{\n    public InvalidNameException() : base(\"Name cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Features/AircraftMappings.cs",
    "content": "using Flight.Aircrafts.Models;\nusing Mapster;\n\nnamespace Flight.Aircrafts.Features;\n\nusing CreatingAircraft.V1;\nusing MassTransit;\nusing ValueObjects;\n\npublic class AircraftMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<CreateAircraftMongo, AircraftReadModel>()\n        .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.AircraftId, s => AircraftId.Of(s.Id));\n\n        config.NewConfig<Aircraft, AircraftReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.AircraftId, s => AircraftId.Of(s.Id.Value));\n\n        config.NewConfig<CreateAircraftRequestDto, CreatingAircraft.V1.CreateAircraft>()\n            .ConstructUsing(x => new CreatingAircraft.V1.CreateAircraft(x.Name, x.Model, x.ManufacturingYear));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraft.cs",
    "content": "namespace Flight.Aircrafts.Features.CreatingAircraft.V1;\n\nusing System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Flight.Aircrafts.ValueObjects;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing Models;\n\npublic record CreateAircraft(string Name, string Model, int ManufacturingYear) : ICommand<CreateAircraftResult>,\n    IInternalCommand\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record CreateAircraftResult(AircraftId Id);\n\npublic record AircraftCreatedDomainEvent\n    (Guid Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : IDomainEvent;\n\npublic record CreateAircraftRequestDto(string Name, string Model, int ManufacturingYear);\n\npublic record CreateAircraftResponseDto(Guid Id);\n\npublic class CreateAircraftEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/flight/aircraft\", async (CreateAircraftRequestDto request,\n                IMediator mediator, IMapper mapper,\n                CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<CreateAircraft>(request);\n\n                var result = await mediator.Send(command, cancellationToken);\n\n                var response = result.Adapt<CreateAircraftResponseDto>();\n\n                return Results.Ok(response);\n            })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CreateAircraft\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<CreateAircraftResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Create Aircraft\")\n            .WithDescription(\"Create Aircraft\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class CreateAircraftValidator : AbstractValidator<CreateAircraft>\n{\n    public CreateAircraftValidator()\n    {\n        RuleFor(x => x.Model).NotEmpty().WithMessage(\"Model is required\");\n        RuleFor(x => x.Name).NotEmpty().WithMessage(\"Name is required\");\n        RuleFor(x => x.ManufacturingYear).NotEmpty().WithMessage(\"ManufacturingYear is required\");\n    }\n}\n\ninternal class CreateAircraftHandler : IRequestHandler<CreateAircraft, CreateAircraftResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public CreateAircraftHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<CreateAircraftResult> Handle(CreateAircraft request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var aircraft = await _flightDbContext.Aircraft.SingleOrDefaultAsync(\n            a => a.Model.Value == request.Model, cancellationToken);\n\n        if (aircraft is not null)\n        {\n            throw new AircraftAlreadyExistException();\n        }\n\n        var aircraftEntity = Aircraft.Create(AircraftId.Of(request.Id), Name.Of(request.Name), Model.Of(request.Model), ManufacturingYear.Of(request.ManufacturingYear));\n\n        var newAircraft = (await _flightDbContext.Aircraft.AddAsync(aircraftEntity, cancellationToken)).Entity;\n\n        return new CreateAircraftResult(newAircraft.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftMongo.cs",
    "content": "namespace Flight.Aircrafts.Features.CreatingAircraft.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\nusing ValueObjects;\n\npublic record CreateAircraftMongo(Guid Id, string Name, string Model, int ManufacturingYear, bool IsDeleted = false) : InternalCommand;\n\ninternal class CreateAircraftMongoHandler : ICommandHandler<CreateAircraftMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public CreateAircraftMongoHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(CreateAircraftMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var aircraftReadModel = _mapper.Map<AircraftReadModel>(request);\n\n        var aircraft = await _flightReadDbContext.Aircraft.AsQueryable()\n            .FirstOrDefaultAsync(x => x.AircraftId == aircraftReadModel.AircraftId &&\n                                      !x.IsDeleted, cancellationToken);\n\n        if (aircraft is not null)\n        {\n            throw new AircraftAlreadyExistException();\n        }\n\n        await _flightReadDbContext.Aircraft.InsertOneAsync(aircraftReadModel, cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Models/Aircraft.cs",
    "content": "using BuildingBlocks.Core.Model;\n\nnamespace Flight.Aircrafts.Models;\n\nusing Features.CreatingAircraft.V1;\nusing ValueObjects;\n\npublic record Aircraft : Aggregate<AircraftId>\n{\n    public Name Name { get; private set; } = default!;\n    public Model Model { get; private set; } = default!;\n    public ManufacturingYear ManufacturingYear { get; private set; } = default!;\n\n    public static Aircraft Create(AircraftId id, Name name, Model model, ManufacturingYear manufacturingYear, bool isDeleted = false)\n    {\n        var aircraft = new Aircraft\n        {\n            Id = id,\n            Name = name,\n            Model = model,\n            ManufacturingYear = manufacturingYear\n        };\n\n        var @event = new AircraftCreatedDomainEvent(\n            aircraft.Id,\n            aircraft.Name,\n            aircraft.Model,\n            aircraft.ManufacturingYear,\n            isDeleted);\n\n        aircraft.AddDomainEvent(@event);\n\n        return aircraft;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/Models/AircraftReadModel.cs",
    "content": "namespace Flight.Aircrafts.Models;\n\nusing System;\n\npublic class AircraftReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid AircraftId { get; init; }\n    public required string Name { get; init; }\n    public required string Model { get; init; }\n    public required int ManufacturingYear { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/ValueObjects/AircraftId.cs",
    "content": "namespace Flight.Aircrafts.ValueObjects;\n\nusing System;\nusing Flight.Aircrafts.Exceptions;\n\npublic record AircraftId\n{\n    public Guid Value { get; }\n\n    private AircraftId(Guid value)\n    {\n        Value = value;\n    }\n\n    public static AircraftId Of(Guid value)\n    {\n        if (value == Guid.Empty)\n        {\n            throw new InvalidAircraftIdException(value);\n        }\n\n        return new AircraftId(value);\n    }\n\n    public static implicit operator Guid(AircraftId aircraftId)\n    {\n        return aircraftId.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/ValueObjects/ManufacturingYear.cs",
    "content": "namespace Flight.Aircrafts.ValueObjects;\n\nusing Exceptions;\n\npublic record ManufacturingYear\n{\n    public int Value { get; }\n\n    private ManufacturingYear(int value)\n    {\n        Value = value;\n    }\n\n    public static ManufacturingYear Of(int value)\n    {\n        if (value < 1900)\n        {\n            throw new InvalidManufacturingYearException();\n        }\n\n        return new ManufacturingYear(value);\n    }\n\n    public static implicit operator int(ManufacturingYear manufacturingYear)\n    {\n        return manufacturingYear.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/ValueObjects/Model.cs",
    "content": "namespace Flight.Aircrafts.ValueObjects;\n\nusing Exceptions;\n\npublic record Model\n{\n    public string Value { get; }\n\n    private Model(string value)\n    {\n        Value = value;\n    }\n\n    public static Model Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidModelException();\n        }\n\n        return new Model(value);\n    }\n\n    public static implicit operator string(Model model)\n    {\n        return model.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Aircrafts/ValueObjects/Name.cs",
    "content": "namespace Flight.Aircrafts.ValueObjects;\n\nusing Exceptions;\n\npublic record Name\n{\n    public string Value { get; }\n\n    private Name(string value)\n    {\n        Value = value;\n    }\n\n    public static Name Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidNameException();\n        }\n\n        return new Name(value);\n    }\n\n    public static implicit operator string(Name name)\n    {\n        return name.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Dtos/AirportDto.cs",
    "content": "namespace Flight.Airports.Dtos;\n\npublic record AirportDto(long Id, string Name, string Address, string Code);"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Exceptions/AirportAlreadyExistException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Flight.Airports.Exceptions;\n\npublic class AirportAlreadyExistException : AppException\n{\n    public AirportAlreadyExistException(int? code = default) : base(\"Airport already exist!\", HttpStatusCode.Conflict, code)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAddressException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Airports.Exceptions;\n\npublic class InvalidAddressException : DomainException\n{\n    public InvalidAddressException() : base(\"Address cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAirportIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Airports.Exceptions;\n\npublic class InvalidAirportIdException : DomainException\n{\n    public InvalidAirportIdException(Guid airportId)\n        : base($\"airportId: '{airportId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Exceptions/InvalidCodeException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Airports.Exceptions;\n\npublic class InvalidCodeException : DomainException\n{\n    public InvalidCodeException() : base(\"Code cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Exceptions/InvalidNameException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Airports.Exceptions;\n\npublic class InvalidNameException : DomainException\n{\n    public InvalidNameException() : base(\"Name cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Features/AirportMappings.cs",
    "content": "namespace Flight.Airports.Features;\n\nusing CreatingAirport.V1;\nusing Mapster;\nusing MassTransit;\nusing Models;\n\npublic class AirportMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<CreateAirportMongo, AirportReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.AirportId, s => s.Id);\n\n        config.NewConfig<Airport, AirportReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.AirportId, s => s.Id.Value);\n\n        config.NewConfig<CreateAirportRequestDto, CreateAirport>()\n            .ConstructUsing(x => new CreateAirport(x.Name, x.Address, x.Code));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirport.cs",
    "content": "namespace Flight.Airports.Features.CreatingAirport.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing ValueObjects;\n\npublic record CreateAirport(string Name, string Address, string Code) : ICommand<CreateAirportResult>, IInternalCommand\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record CreateAirportResult(Guid Id);\n\npublic record AirportCreatedDomainEvent\n    (Guid Id, string Name, string Address, string Code, bool IsDeleted) : IDomainEvent;\n\npublic record CreateAirportRequestDto(string Name, string Address, string Code);\n\npublic record CreateAirportResponseDto(Guid Id);\n\npublic class CreateAirportEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/flight/airport\", async (CreateAirportRequestDto request,\n                IMediator mediator, IMapper mapper,\n                CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<CreateAirport>(request);\n\n                var result = await mediator.Send(command, cancellationToken);\n\n                var response = result.Adapt<CreateAirportResponseDto>();\n\n                return Results.Ok(response);\n            })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CreateAirport\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<CreateAirportResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Create Airport\")\n            .WithDescription(\"Create Airport\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class CreateAirportValidator : AbstractValidator<CreateAirport>\n{\n    public CreateAirportValidator()\n    {\n        RuleFor(x => x.Code).NotEmpty().WithMessage(\"Code is required\");\n        RuleFor(x => x.Name).NotEmpty().WithMessage(\"Name is required\");\n        RuleFor(x => x.Address).NotEmpty().WithMessage(\"Address is required\");\n    }\n}\n\ninternal class CreateAirportHandler : IRequestHandler<CreateAirport, CreateAirportResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public CreateAirportHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<CreateAirportResult> Handle(CreateAirport request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var airport =\n            await _flightDbContext.Airports.SingleOrDefaultAsync(x => x.Code.Value == request.Code, cancellationToken);\n\n        if (airport is not null)\n        {\n            throw new AirportAlreadyExistException();\n        }\n\n        var airportEntity = Models.Airport.Create(AirportId.Of(request.Id), Name.Of(request.Name), Address.Of(request.Address), Code.Of(request.Code));\n\n        var newAirport = (await _flightDbContext.Airports.AddAsync(airportEntity, cancellationToken)).Entity;\n\n        return new CreateAirportResult(newAirport.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirportMongo.cs",
    "content": "namespace Flight.Airports.Features.CreatingAirport.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record CreateAirportMongo(Guid Id, string Name, string Address, string Code, bool IsDeleted = false) : InternalCommand;\n\ninternal class CreateAirportMongoHandler : ICommandHandler<CreateAirportMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public CreateAirportMongoHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(CreateAirportMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var airportReadModel = _mapper.Map<AirportReadModel>(request);\n\n        var aircraft = await _flightReadDbContext.Airport.AsQueryable()\n            .FirstOrDefaultAsync(x => x.AirportId == airportReadModel.AirportId &&\n                                      !x.IsDeleted, cancellationToken);\n\n        if (aircraft is not null)\n        {\n            throw new AirportAlreadyExistException();\n        }\n\n        await _flightReadDbContext.Airport.InsertOneAsync(airportReadModel, cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Models/Airport.cs",
    "content": "using BuildingBlocks.Core.Model;\n\nnamespace Flight.Airports.Models;\n\nusing Features.CreatingAirport.V1;\nusing ValueObjects;\n\npublic record Airport : Aggregate<AirportId>\n{\n    public Name Name { get; private set; } = default!;\n    public Address Address { get; private set; } = default!;\n    public Code Code { get; private set; } = default!;\n\n    public static Airport Create(AirportId id, Name name, Address address, Code code, bool isDeleted = false)\n    {\n        var airport = new Airport\n        {\n            Id = id,\n            Name = name,\n            Address = address,\n            Code = code\n        };\n\n        var @event = new AirportCreatedDomainEvent(\n            airport.Id,\n            airport.Name,\n            airport.Address,\n            airport.Code,\n            isDeleted);\n\n        airport.AddDomainEvent(@event);\n\n        return airport;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/Models/AirportReadModel.cs",
    "content": "namespace Flight.Airports.Models;\n\nusing System;\n\npublic class AirportReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid AirportId { get; init; }\n    public required string Name { get; init; }\n    public string Address { get; init; }\n    public required string Code { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/ValueObjects/Address.cs",
    "content": "namespace Flight.Airports.ValueObjects;\n\nusing Exceptions;\n\npublic class Address\n{\n    public string Value { get; }\n\n    private Address(string value)\n    {\n        Value = value;\n    }\n\n    public static Address Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidAddressException();\n        }\n\n        return new Address(value);\n    }\n\n    public static implicit operator string(Address address)\n    {\n        return address.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/ValueObjects/AirportId.cs",
    "content": "namespace Flight.Airports.ValueObjects;\n\nusing System;\nusing Flight.Airports.Exceptions;\n\npublic record AirportId\n{\n    public Guid Value { get; }\n\n    private AirportId(Guid value)\n    {\n        Value = value;\n    }\n\n    public static AirportId Of(Guid value)\n    {\n        if (value == Guid.Empty)\n        {\n            throw new InvalidAirportIdException(value);\n        }\n\n        return new AirportId(value);\n    }\n\n    public static implicit operator Guid(AirportId airportId)\n    {\n        return airportId.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/ValueObjects/Code.cs",
    "content": "namespace Flight.Airports.ValueObjects;\n\nusing Exceptions;\n\npublic record Code\n{\n    public string Value { get; }\n\n    private Code(string value)\n    {\n        Value = value;\n    }\n\n    public static Code Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidCodeException();\n        }\n\n        return new Code(value);\n    }\n\n    public static implicit operator string(Code code)\n    {\n        return code.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Airports/ValueObjects/Name.cs",
    "content": "namespace Flight.Airports.ValueObjects;\n\nusing Exceptions;\n\npublic record Name\n{\n    public string Value { get; }\n\n    private Name(string value)\n    {\n        Value = value;\n    }\n\n    public static Name Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidNameException();\n        }\n\n        return new Name(value);\n    }\n\n    public static implicit operator string(Name name)\n    {\n        return name.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Unit.Test\")]\n[assembly: InternalsVisibleTo(\"Integration.Test\")]\n[assembly: InternalsVisibleTo(\"EndToEnd.Test\")]"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Configurations/AircraftConfiguration.cs",
    "content": "using Flight.Aircrafts.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace Flight.Data.Configurations;\n\nusing System;\nusing Aircrafts.ValueObjects;\n\npublic class AircraftConfiguration : IEntityTypeConfiguration<Aircraft>\n{\n    public void Configure(EntityTypeBuilder<Aircraft> builder)\n    {\n\n        builder.ToTable(nameof(Aircraft));\n\n        builder.HasKey(r => r.Id);\n        builder.Property(r => r.Id).ValueGeneratedNever()\n            .HasConversion<Guid>(aircraftId => aircraftId.Value, dbId => AircraftId.Of(dbId));\n\n        builder.Property(r => r.Version).IsConcurrencyToken();\n\n        builder.OwnsOne(\n            x => x.Name,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Aircraft.Name))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.Model,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Aircraft.Model))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.ManufacturingYear,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Aircraft.ManufacturingYear))\n                    .HasMaxLength(5)\n                    .IsRequired();\n            }\n        );\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Configurations/AirportConfiguration.cs",
    "content": "using System;\nusing Flight.Airports.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace Flight.Data.Configurations;\n\nusing Airports.ValueObjects;\n\npublic class AirportConfiguration : IEntityTypeConfiguration<Airport>\n{\n    public void Configure(EntityTypeBuilder<Airport> builder)\n    {\n\n        builder.ToTable(nameof(Airport));\n\n        builder.HasKey(r => r.Id);\n        builder.Property(r => r.Id).ValueGeneratedNever()\n            .HasConversion<Guid>(airportId => airportId.Value, dbId => AirportId.Of(dbId));\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n\n\n        builder.OwnsOne(\n            x => x.Name,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Airport.Name))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.Address,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Airport.Address))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.Code,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Airport.Code))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Configurations/FlightConfiguration.cs",
    "content": "using Flight.Aircrafts.Models;\nusing Flight.Airports.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace Flight.Data.Configurations;\n\nusing System;\nusing Flights.Models;\nusing Flights.ValueObjects;\n\npublic class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Flight>\n{\n    public void Configure(EntityTypeBuilder<Flights.Models.Flight> builder)\n    {\n        builder.ToTable(nameof(Flight));\n\n        builder.HasKey(r => r.Id);\n        builder.Property(r => r.Id).ValueGeneratedNever()\n            .HasConversion<Guid>(flight => flight.Value, dbId => FlightId.Of(dbId));\n\n        builder.Property(r => r.Version).IsConcurrencyToken();\n\n\n        builder.OwnsOne(\n            x => x.FlightNumber,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.FlightNumber))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder\n            .HasOne<Aircraft>()\n            .WithMany()\n            .HasForeignKey(p => p.AircraftId)\n            .IsRequired();\n\n        builder\n            .HasOne<Airport>()\n            .WithMany()\n            .HasForeignKey(d => d.DepartureAirportId)\n            .IsRequired();\n\n        builder\n            .HasOne<Airport>()\n            .WithMany()\n            .HasForeignKey(d => d.ArriveAirportId)\n            .IsRequired();\n\n\n        builder.OwnsOne(\n            x => x.DurationMinutes,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.DurationMinutes))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.Property(x => x.Status)\n            .HasDefaultValue(Flights.Enums.FlightStatus.Unknown)\n            .HasConversion(\n                x => x.ToString(),\n                x => (Flights.Enums.FlightStatus)Enum.Parse(typeof(Flights.Enums.FlightStatus), x));\n\n        builder.OwnsOne(\n            x => x.Price,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.Price))\n                    .HasMaxLength(10)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.ArriveDate,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.ArriveDate))\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.DepartureDate,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.DepartureDate))\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.FlightDate,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Flight.FlightDate))\n                    .IsRequired();\n            }\n        );\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Configurations/SeatConfiguration.cs",
    "content": "using Flight.Seats.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace Flight.Data.Configurations;\n\nusing System;\nusing Seats.ValueObjects;\n\npublic class SeatConfiguration : IEntityTypeConfiguration<Seat>\n{\n    public void Configure(EntityTypeBuilder<Seat> builder)\n    {\n        builder.ToTable(nameof(Seat));\n\n        builder.HasKey(r => r.Id);\n        builder.Property(r => r.Id).ValueGeneratedNever()\n            .HasConversion<Guid>(seatId => seatId.Value, dbId => SeatId.Of(dbId));\n\n        builder.Property(r => r.Version).IsConcurrencyToken();\n\n        builder.OwnsOne(\n            x => x.SeatNumber,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Seat.SeatNumber))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder\n            .HasOne<Flights.Models.Flight>()\n            .WithMany()\n            .HasForeignKey(p => p.FlightId);\n\n        builder.Property(x => x.Class)\n            .HasDefaultValue(Seats.Enums.SeatClass.Unknown)\n            .HasConversion(\n                x => x.ToString(),\n                x => (Flight.Seats.Enums.SeatClass)Enum.Parse(typeof(Flight.Seats.Enums.SeatClass), x));\n\n        builder.Property(x => x.Type)\n            .HasDefaultValue(Seats.Enums.SeatType.Unknown)\n            .HasConversion(\n                x => x.ToString(),\n                x => (Flight.Seats.Enums.SeatType)Enum.Parse(typeof(Flight.Seats.Enums.SeatType), x));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/DesignTimeDbContextFactory.cs",
    "content": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Design;\n\nnamespace Flight.Data\n{\n    public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<FlightDbContext>\n    {\n        public FlightDbContext CreateDbContext(string[] args)\n        {\n            var builder = new DbContextOptionsBuilder<FlightDbContext>();\n\n            builder.UseNpgsql(\"Server=localhost;Port=5432;Database=flight;User Id=postgres;Password=postgres;Include Error Detail=true\")\n                .UseSnakeCaseNamingConvention();\n            return new FlightDbContext(builder.Options);\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/FlightDbContext.cs",
    "content": "using BuildingBlocks.EFCore;\nusing Flight.Aircrafts.Models;\nusing Flight.Airports.Models;\nusing Flight.Seats.Models;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Flight.Data;\n\nusing BuildingBlocks.Web;\nusing Microsoft.Extensions.Logging;\n\npublic sealed class FlightDbContext : AppDbContextBase\n{\n    public FlightDbContext(DbContextOptions<FlightDbContext> options, ICurrentUserProvider? currentUserProvider = null,\n        ILogger<FlightDbContext>? logger = null) : base(\n        options, currentUserProvider, logger)\n    {\n    }\n\n    public DbSet<Flights.Models.Flight> Flights => Set<Flights.Models.Flight>();\n    public DbSet<Airport> Airports => Set<Airport>();\n    public DbSet<Aircraft> Aircraft => Set<Aircraft>();\n    public DbSet<Seat> Seats => Set<Seat>();\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        base.OnModelCreating(builder);\n        builder.ApplyConfigurationsFromAssembly(typeof(FlightRoot).Assembly);\n        builder.FilterSoftDeletedProperties();\n        builder.ToSnakeCaseTables();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/FlightReadDbContext.cs",
    "content": "using BuildingBlocks.Mongo;\nusing Humanizer;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace Flight.Data;\n\nusing Aircrafts.Models;\nusing Airports.Models;\nusing Flights.Models;\nusing Seats.Models;\n\npublic class FlightReadDbContext : MongoDbContext\n{\n    public FlightReadDbContext(IOptions<MongoOptions> options) : base(options)\n    {\n        Flight = GetCollection<FlightReadModel>(nameof(Flight).Underscore());\n        Aircraft = GetCollection<AircraftReadModel>(nameof(Aircraft).Underscore());\n        Airport = GetCollection<AirportReadModel>(nameof(Airport).Underscore());\n        Seat = GetCollection<SeatReadModel>(nameof(Seat).Underscore());\n    }\n\n    public IMongoCollection<FlightReadModel> Flight { get; }\n    public IMongoCollection<AircraftReadModel> Aircraft { get; }\n    public IMongoCollection<AirportReadModel> Airport { get; }\n    public IMongoCollection<SeatReadModel> Seat { get; }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Migrations/20230611230948_initial.Designer.cs",
    "content": "// <auto-generated />\nusing System;\nusing Flight.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Migrations;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\n\n#nullable disable\n\nnamespace Flight.Data.Migrations\n{\n    [DbContext(typeof(FlightDbContext))]\n    [Migration(\"20230611230948_initial\")]\n    partial class initial\n    {\n        /// <inheritdoc />\n        protected override void BuildTargetModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"7.0.2\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Flight.Aircrafts.Models.Aircraft\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_aircraft\");\n\n                    b.ToTable(\"aircraft\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Airports.Models.Airport\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_airport\");\n\n                    b.ToTable(\"airport\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Flights.Models.Flight\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<Guid>(\"AircraftId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"aircraft_id\");\n\n                    b.Property<Guid>(\"ArriveAirportId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"arrive_airport_id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<Guid>(\"DepartureAirportId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"departure_airport_id\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"Status\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"status\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_flight\");\n\n                    b.HasIndex(\"AircraftId\")\n                        .HasDatabaseName(\"ix_flight_aircraft_id\");\n\n                    b.HasIndex(\"ArriveAirportId\")\n                        .HasDatabaseName(\"ix_flight_arrive_airport_id\");\n\n                    b.HasIndex(\"DepartureAirportId\")\n                        .HasDatabaseName(\"ix_flight_departure_airport_id\");\n\n                    b.ToTable(\"flight\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Seats.Models.Seat\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<string>(\"Class\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"class\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<Guid>(\"FlightId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"flight_id\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"Type\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"type\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_seat\");\n\n                    b.HasIndex(\"FlightId\")\n                        .HasDatabaseName(\"ix_seat_flight_id\");\n\n                    b.ToTable(\"seat\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Aircrafts.Models.Aircraft\", b =>\n                {\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.ManufacturingYear\", \"ManufacturingYear\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<int>(\"Value\")\n                                .HasMaxLength(5)\n                                .HasColumnType(\"integer\")\n                                .HasColumnName(\"manufacturing_year\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.Model\", \"Model\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"model\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.Navigation(\"ManufacturingYear\")\n                        .IsRequired();\n\n                    b.Navigation(\"Model\")\n                        .IsRequired();\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Airports.Models.Airport\", b =>\n                {\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Address\", \"Address\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"address\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Code\", \"Code\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"code\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.Navigation(\"Address\")\n                        .IsRequired();\n\n                    b.Navigation(\"Code\")\n                        .IsRequired();\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Flights.Models.Flight\", b =>\n                {\n                    b.HasOne(\"Flight.Aircrafts.Models.Aircraft\", null)\n                        .WithMany()\n                        .HasForeignKey(\"AircraftId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_aircraft_aircraft_id\");\n\n                    b.HasOne(\"Flight.Airports.Models.Airport\", null)\n                        .WithMany()\n                        .HasForeignKey(\"ArriveAirportId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_airport_arrive_airport_id\");\n\n                    b.HasOne(\"Flight.Airports.Models.Airport\", null)\n                        .WithMany()\n                        .HasForeignKey(\"DepartureAirportId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_airport_departure_airport_id\");\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.ArriveDate\", \"ArriveDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"arrive_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.DepartureDate\", \"DepartureDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"departure_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.DurationMinutes\", \"DurationMinutes\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<decimal>(\"Value\")\n                                .HasMaxLength(50)\n                                .HasColumnType(\"numeric\")\n                                .HasColumnName(\"duration_minutes\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.FlightDate\", \"FlightDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"flight_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.FlightNumber\", \"FlightNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"flight_number\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.Price\", \"Price\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<decimal>(\"Value\")\n                                .HasMaxLength(10)\n                                .HasColumnType(\"numeric\")\n                                .HasColumnName(\"price\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.Navigation(\"ArriveDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"DepartureDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"DurationMinutes\")\n                        .IsRequired();\n\n                    b.Navigation(\"FlightDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"FlightNumber\")\n                        .IsRequired();\n\n                    b.Navigation(\"Price\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Seats.Models.Seat\", b =>\n                {\n                    b.HasOne(\"Flight.Flights.Models.Flight\", null)\n                        .WithMany()\n                        .HasForeignKey(\"FlightId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_seat_flight_flight_id\");\n\n                    b.OwnsOne(\"Flight.Seats.ValueObjects.SeatNumber\", \"SeatNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"SeatId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"seat_number\");\n\n                            b1.HasKey(\"SeatId\")\n                                .HasName(\"pk_seat\");\n\n                            b1.ToTable(\"seat\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"SeatId\")\n                                .HasConstraintName(\"fk_seat_seat_id\");\n                        });\n\n                    b.Navigation(\"SeatNumber\")\n                        .IsRequired();\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Migrations/20230611230948_initial.cs",
    "content": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Flight.Data.Migrations\n{\n    /// <inheritdoc />\n    public partial class initial : Migration\n    {\n        /// <inheritdoc />\n        protected override void Up(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.CreateTable(\n                name: \"aircraft\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    name = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    model = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    manufacturingyear = table.Column<int>(name: \"manufacturing_year\", type: \"integer\", maxLength: 5, nullable: false),\n                    createdat = table.Column<DateTime>(name: \"created_at\", type: \"timestamp with time zone\", nullable: true),\n                    createdby = table.Column<long>(name: \"created_by\", type: \"bigint\", nullable: true),\n                    lastmodified = table.Column<DateTime>(name: \"last_modified\", type: \"timestamp with time zone\", nullable: true),\n                    lastmodifiedby = table.Column<long>(name: \"last_modified_by\", type: \"bigint\", nullable: true),\n                    isdeleted = table.Column<bool>(name: \"is_deleted\", type: \"boolean\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_aircraft\", x => x.id);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"airport\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    name = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    address = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    code = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    createdat = table.Column<DateTime>(name: \"created_at\", type: \"timestamp with time zone\", nullable: true),\n                    createdby = table.Column<long>(name: \"created_by\", type: \"bigint\", nullable: true),\n                    lastmodified = table.Column<DateTime>(name: \"last_modified\", type: \"timestamp with time zone\", nullable: true),\n                    lastmodifiedby = table.Column<long>(name: \"last_modified_by\", type: \"bigint\", nullable: true),\n                    isdeleted = table.Column<bool>(name: \"is_deleted\", type: \"boolean\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_airport\", x => x.id);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"flight\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    flightnumber = table.Column<string>(name: \"flight_number\", type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    aircraftid = table.Column<Guid>(name: \"aircraft_id\", type: \"uuid\", nullable: false),\n                    departureairportid = table.Column<Guid>(name: \"departure_airport_id\", type: \"uuid\", nullable: false),\n                    arriveairportid = table.Column<Guid>(name: \"arrive_airport_id\", type: \"uuid\", nullable: false),\n                    durationminutes = table.Column<decimal>(name: \"duration_minutes\", type: \"numeric\", maxLength: 50, nullable: false),\n                    status = table.Column<string>(type: \"text\", nullable: false, defaultValue: \"Unknown\"),\n                    price = table.Column<decimal>(type: \"numeric\", maxLength: 10, nullable: false),\n                    arrivedate = table.Column<DateTime>(name: \"arrive_date\", type: \"timestamp with time zone\", nullable: false),\n                    departuredate = table.Column<DateTime>(name: \"departure_date\", type: \"timestamp with time zone\", nullable: false),\n                    flightdate = table.Column<DateTime>(name: \"flight_date\", type: \"timestamp with time zone\", nullable: false),\n                    createdat = table.Column<DateTime>(name: \"created_at\", type: \"timestamp with time zone\", nullable: true),\n                    createdby = table.Column<long>(name: \"created_by\", type: \"bigint\", nullable: true),\n                    lastmodified = table.Column<DateTime>(name: \"last_modified\", type: \"timestamp with time zone\", nullable: true),\n                    lastmodifiedby = table.Column<long>(name: \"last_modified_by\", type: \"bigint\", nullable: true),\n                    isdeleted = table.Column<bool>(name: \"is_deleted\", type: \"boolean\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_flight\", x => x.id);\n                    table.ForeignKey(\n                        name: \"fk_flight_aircraft_aircraft_id\",\n                        column: x => x.aircraftid,\n                        principalTable: \"aircraft\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                    table.ForeignKey(\n                        name: \"fk_flight_airport_arrive_airport_id\",\n                        column: x => x.arriveairportid,\n                        principalTable: \"airport\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                    table.ForeignKey(\n                        name: \"fk_flight_airport_departure_airport_id\",\n                        column: x => x.departureairportid,\n                        principalTable: \"airport\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"seat\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    seatnumber = table.Column<string>(name: \"seat_number\", type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    type = table.Column<string>(type: \"text\", nullable: false, defaultValue: \"Unknown\"),\n                    @class = table.Column<string>(name: \"class\", type: \"text\", nullable: false, defaultValue: \"Unknown\"),\n                    flightid = table.Column<Guid>(name: \"flight_id\", type: \"uuid\", nullable: false),\n                    createdat = table.Column<DateTime>(name: \"created_at\", type: \"timestamp with time zone\", nullable: true),\n                    createdby = table.Column<long>(name: \"created_by\", type: \"bigint\", nullable: true),\n                    lastmodified = table.Column<DateTime>(name: \"last_modified\", type: \"timestamp with time zone\", nullable: true),\n                    lastmodifiedby = table.Column<long>(name: \"last_modified_by\", type: \"bigint\", nullable: true),\n                    isdeleted = table.Column<bool>(name: \"is_deleted\", type: \"boolean\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_seat\", x => x.id);\n                    table.ForeignKey(\n                        name: \"fk_seat_flight_flight_id\",\n                        column: x => x.flightid,\n                        principalTable: \"flight\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_flight_aircraft_id\",\n                table: \"flight\",\n                column: \"aircraft_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_flight_arrive_airport_id\",\n                table: \"flight\",\n                column: \"arrive_airport_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_flight_departure_airport_id\",\n                table: \"flight\",\n                column: \"departure_airport_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_seat_flight_id\",\n                table: \"seat\",\n                column: \"flight_id\");\n        }\n\n        /// <inheritdoc />\n        protected override void Down(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.DropTable(\n                name: \"seat\");\n\n            migrationBuilder.DropTable(\n                name: \"flight\");\n\n            migrationBuilder.DropTable(\n                name: \"aircraft\");\n\n            migrationBuilder.DropTable(\n                name: \"airport\");\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs",
    "content": "// <auto-generated />\nusing System;\nusing Flight.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\n\n#nullable disable\n\nnamespace Flight.Data.Migrations\n{\n    [DbContext(typeof(FlightDbContext))]\n    partial class FlightDbContextModelSnapshot : ModelSnapshot\n    {\n        protected override void BuildModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"9.0.0\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Flight.Aircrafts.Models.Aircraft\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_aircraft\");\n\n                    b.ToTable(\"aircraft\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Airports.Models.Airport\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_airport\");\n\n                    b.ToTable(\"airport\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Flights.Models.Flight\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<Guid>(\"AircraftId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"aircraft_id\");\n\n                    b.Property<Guid>(\"ArriveAirportId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"arrive_airport_id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<Guid>(\"DepartureAirportId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"departure_airport_id\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"Status\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"status\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_flight\");\n\n                    b.HasIndex(\"AircraftId\")\n                        .HasDatabaseName(\"ix_flight_aircraft_id\");\n\n                    b.HasIndex(\"ArriveAirportId\")\n                        .HasDatabaseName(\"ix_flight_arrive_airport_id\");\n\n                    b.HasIndex(\"DepartureAirportId\")\n                        .HasDatabaseName(\"ix_flight_departure_airport_id\");\n\n                    b.ToTable(\"flight\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Seats.Models.Seat\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<string>(\"Class\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"class\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<Guid>(\"FlightId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"flight_id\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"Type\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"type\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_seat\");\n\n                    b.HasIndex(\"FlightId\")\n                        .HasDatabaseName(\"ix_seat_flight_id\");\n\n                    b.ToTable(\"seat\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Flight.Aircrafts.Models.Aircraft\", b =>\n                {\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.ManufacturingYear\", \"ManufacturingYear\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<int>(\"Value\")\n                                .HasMaxLength(5)\n                                .HasColumnType(\"integer\")\n                                .HasColumnName(\"manufacturing_year\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.Model\", \"Model\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"model\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Aircrafts.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AircraftId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"AircraftId\")\n                                .HasName(\"pk_aircraft\");\n\n                            b1.ToTable(\"aircraft\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AircraftId\")\n                                .HasConstraintName(\"fk_aircraft_aircraft_id\");\n                        });\n\n                    b.Navigation(\"ManufacturingYear\")\n                        .IsRequired();\n\n                    b.Navigation(\"Model\")\n                        .IsRequired();\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Airports.Models.Airport\", b =>\n                {\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Address\", \"Address\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"address\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Code\", \"Code\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"code\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Airports.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"AirportId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"AirportId\")\n                                .HasName(\"pk_airport\");\n\n                            b1.ToTable(\"airport\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"AirportId\")\n                                .HasConstraintName(\"fk_airport_airport_id\");\n                        });\n\n                    b.Navigation(\"Address\")\n                        .IsRequired();\n\n                    b.Navigation(\"Code\")\n                        .IsRequired();\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Flights.Models.Flight\", b =>\n                {\n                    b.HasOne(\"Flight.Aircrafts.Models.Aircraft\", null)\n                        .WithMany()\n                        .HasForeignKey(\"AircraftId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_aircraft_aircraft_id\");\n\n                    b.HasOne(\"Flight.Airports.Models.Airport\", null)\n                        .WithMany()\n                        .HasForeignKey(\"ArriveAirportId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_airport_arrive_airport_id\");\n\n                    b.HasOne(\"Flight.Airports.Models.Airport\", null)\n                        .WithMany()\n                        .HasForeignKey(\"DepartureAirportId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_flight_airport_departure_airport_id\");\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.ArriveDate\", \"ArriveDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"arrive_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.DepartureDate\", \"DepartureDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"departure_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.DurationMinutes\", \"DurationMinutes\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<decimal>(\"Value\")\n                                .HasMaxLength(50)\n                                .HasColumnType(\"numeric\")\n                                .HasColumnName(\"duration_minutes\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.FlightDate\", \"FlightDate\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<DateTime>(\"Value\")\n                                .HasColumnType(\"timestamp with time zone\")\n                                .HasColumnName(\"flight_date\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.FlightNumber\", \"FlightNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"flight_number\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.OwnsOne(\"Flight.Flights.ValueObjects.Price\", \"Price\", b1 =>\n                        {\n                            b1.Property<Guid>(\"FlightId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<decimal>(\"Value\")\n                                .HasMaxLength(10)\n                                .HasColumnType(\"numeric\")\n                                .HasColumnName(\"price\");\n\n                            b1.HasKey(\"FlightId\")\n                                .HasName(\"pk_flight\");\n\n                            b1.ToTable(\"flight\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"FlightId\")\n                                .HasConstraintName(\"fk_flight_flight_id\");\n                        });\n\n                    b.Navigation(\"ArriveDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"DepartureDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"DurationMinutes\")\n                        .IsRequired();\n\n                    b.Navigation(\"FlightDate\")\n                        .IsRequired();\n\n                    b.Navigation(\"FlightNumber\")\n                        .IsRequired();\n\n                    b.Navigation(\"Price\")\n                        .IsRequired();\n                });\n\n            modelBuilder.Entity(\"Flight.Seats.Models.Seat\", b =>\n                {\n                    b.HasOne(\"Flight.Flights.Models.Flight\", null)\n                        .WithMany()\n                        .HasForeignKey(\"FlightId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_seat_flight_flight_id\");\n\n                    b.OwnsOne(\"Flight.Seats.ValueObjects.SeatNumber\", \"SeatNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"SeatId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"seat_number\");\n\n                            b1.HasKey(\"SeatId\")\n                                .HasName(\"pk_seat\");\n\n                            b1.ToTable(\"seat\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"SeatId\")\n                                .HasConstraintName(\"fk_seat_seat_id\");\n                        });\n\n                    b.Navigation(\"SeatNumber\")\n                        .IsRequired();\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Seed/FlightDataSeeder.cs",
    "content": "using BuildingBlocks.EFCore;\nusing Flight.Aircrafts.Models;\nusing Flight.Airports.Models;\nusing Flight.Flights.Models;\nusing Flight.Seats.Models;\nusing MapsterMapper;\nusing Microsoft.EntityFrameworkCore;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace Flight.Data.Seed;\n\npublic class FlightDataSeeder(\n    FlightDbContext flightDbContext,\n    FlightReadDbContext flightReadDbContext,\n    IMapper mapper\n) : IDataSeeder\n{\n    public async Task SeedAllAsync()\n    {\n        var pendingMigrations = await flightDbContext.Database.GetPendingMigrationsAsync();\n\n        if (!pendingMigrations.Any())\n        {\n            await SeedAirportAsync();\n            await SeedAircraftAsync();\n            await SeedFlightAsync();\n            await SeedSeatAsync();\n        }\n    }\n\n    private async Task SeedAirportAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Airports))\n        {\n            await flightDbContext.Airports.AddRangeAsync(InitialData.Airports);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Airport.AsQueryable()))\n            {\n                await flightReadDbContext.Airport.InsertManyAsync(mapper.Map<List<AirportReadModel>>(InitialData.Airports));\n            }\n        }\n    }\n\n    private async Task SeedAircraftAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Aircraft))\n        {\n            await flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Aircraft.AsQueryable()))\n            {\n                await flightReadDbContext.Aircraft.InsertManyAsync(mapper.Map<List<AircraftReadModel>>(InitialData.Aircrafts));\n            }\n        }\n    }\n\n\n    private async Task SeedSeatAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Seats))\n        {\n            await flightDbContext.Seats.AddRangeAsync(InitialData.Seats);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Seat.AsQueryable()))\n            {\n                await flightReadDbContext.Seat.InsertManyAsync(mapper.Map<List<SeatReadModel>>(InitialData.Seats));\n            }\n        }\n    }\n\n    private async Task SeedFlightAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Flights))\n        {\n            await flightDbContext.Flights.AddRangeAsync(InitialData.Flights);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Flight.AsQueryable()))\n            {\n                await flightReadDbContext.Flight.InsertManyAsync(mapper.Map<List<FlightReadModel>>(InitialData.Flights));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/Seed/InitialData.cs",
    "content": "namespace Flight.Data.Seed;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Aircrafts.Models;\nusing Airports.Models;\nusing Airports.ValueObjects;\nusing Flight.Aircrafts.ValueObjects;\nusing Flights.Models;\nusing Flights.ValueObjects;\nusing MassTransit;\nusing Seats.Models;\nusing Seats.ValueObjects;\nusing AirportName = Airports.ValueObjects.Name;\nusing Name = Aircrafts.ValueObjects.Name;\n\npublic static class InitialData\n{\n    public static List<Airport> Airports { get; }\n    public static List<Aircraft> Aircrafts { get; }\n    public static List<Seat> Seats { get; }\n    public static List<Flight> Flights { get; }\n\n\n    static InitialData()\n    {\n        Airports = new List<Airport>\n        {\n            Airport.Create(AirportId.Of(new Guid(\"3c5c0000-97c6-fc34-a0cb-08db322230c8\")), AirportName.Of(\"Lisbon International Airport\"), Address.Of(\"LIS\"), Code.Of(\"12988\")),\n            Airport.Create(AirportId.Of(new Guid(\"3c5c0000-97c6-fc34-fc3c-08db322230c8\")), AirportName.Of(\"Sao Paulo International Airport\"), Address.Of(\"BRZ\"), Code.Of(\"11200\"))\n        };\n\n        Aircrafts = new List<Aircraft>\n        {\n            Aircraft.Create(AircraftId.Of(new Guid(\"3c5c0000-97c6-fc34-fcd3-08db322230c8\")), Name.Of(\"Boeing 737\"), Model.Of(\"B737\"), ManufacturingYear.Of(2005)),\n            Aircraft.Create(AircraftId.Of(new Guid(\"3c5c0000-97c6-fc34-2e04-08db322230c9\")), Name.Of(\"Airbus 300\"), Model.Of(\"A300\"), ManufacturingYear.Of(2000)),\n            Aircraft.Create(AircraftId.Of(new Guid(\"3c5c0000-97c6-fc34-2e11-08db322230c9\")), Name.Of(\"Airbus 320\"), Model.Of(\"A320\"), ManufacturingYear.Of(2003))\n        };\n\n\n        Flights = new List<Flight>\n        {\n            Flight.Create(FlightId.Of(new Guid(\"3c5c0000-97c6-fc34-2eb9-08db322230c9\")), FlightNumber.Of(\"BD467\"), AircraftId.Of(Aircrafts.First().Id.Value), AirportId.Of( Airports.First().Id), DepartureDate.Of(new DateTime(2022, 1, 31, 12, 0, 0)),\n               ArriveDate.Of(new DateTime(2022, 1, 31, 14, 0, 0)),\n               AirportId.Of(Airports.Last().Id), DurationMinutes.Of(120m),\n                FlightDate.Of(new DateTime(2022, 1, 31, 13, 0, 0)), global::Flight.Flights.Enums.FlightStatus.Completed,\n                Price.Of(8000))\n        };\n\n        Seats = new List<Seat>\n        {\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of( \"12A\"), global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid)Flights.First().Id)),\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12B\"), global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid)Flights.First().Id)),\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12C\"), global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)),\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12D\"), global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)),\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12E\"), global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)),\n            Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12F\"), global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id))\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Data/readme.md",
    "content": "dotnet ef migrations add initial --context FlightDbContext -o \"Data\\Migrations\"\ndotnet ef database update --context FlightDbContext\n"
  },
  {
    "path": "src/Services/Flight/src/Flight/Extensions/Infrastructure/InfrastructureExtensions.cs",
    "content": "using BuildingBlocks.Core;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Exception;\nusing BuildingBlocks.HealthCheck;\nusing BuildingBlocks.Jwt;\nusing BuildingBlocks.Mapster;\nusing BuildingBlocks.MassTransit;\nusing BuildingBlocks.Mongo;\nusing BuildingBlocks.OpenApi;\nusing BuildingBlocks.OpenTelemetryCollector;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.ProblemDetails;\nusing BuildingBlocks.Web;\nusing Figgle;\nusing Figgle.Fonts;\nusing Flight.Data;\nusing Flight.Data.Seed;\nusing Flight.GrpcServer.Services;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing ServiceDefaults;\n\nnamespace Flight.Extensions.Infrastructure;\n\n\npublic static class InfrastructureExtensions\n{\n    public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder)\n    {\n        var configuration = builder.Configuration;\n        var env = builder.Environment;\n\n        builder.AddServiceDefaults();\n\n        builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();\n        builder.Services.AddScoped<IEventMapper, FlightEventMapper>();\n\n        builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();\n        builder.Services.Configure<ApiBehaviorOptions>(options =>\n        {\n            options.SuppressModelStateInvalidFilter = true;\n        });\n\n        builder.Services.AddCustomMediatR();\n        builder.Services.AddProblemDetails();\n\n        var appOptions = builder.Services.GetOptions<AppOptions>(nameof(AppOptions));\n        Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));\n\n        builder.AddCustomDbContext<FlightDbContext>(nameof(Flight));\n        builder.Services.AddScoped<IDataSeeder, FlightDataSeeder>();\n        builder.AddMongoDbContext<FlightReadDbContext>();\n        builder.AddPersistMessageProcessor(nameof(PersistMessage));\n\n        builder.Services.AddEndpointsApiExplorer();\n        builder.Services.AddJwt();\n        builder.Services.AddAspnetOpenApi();\n        builder.Services.AddCustomVersioning();\n        builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly);\n        builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly);\n        builder.Services.AddHttpContextAccessor();\n        builder.Services.AddCustomMassTransit(env, TransportType.RabbitMq, typeof(FlightRoot).Assembly);\n\n        builder.Services.AddGrpc(options =>\n        {\n            options.Interceptors.Add<GrpcExceptionInterceptor>();\n        });\n\n        builder.Services.AddEasyCaching(options => { options.UseInMemory(configuration, \"mem\"); });\n\n        return builder;\n    }\n\n\n    public static WebApplication UseInfrastructure(this WebApplication app)\n    {\n        var env = app.Environment;\n        var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));\n\n        app.UseAuthentication();\n        app.UseAuthorization();\n\n        app.UseServiceDefaults();\n\n        app.UseCustomProblemDetails();\n        app.UseCorrelationId();\n        app.UseMigration<FlightDbContext>();\n        app.MapGrpcService<FlightGrpcServices>();\n\n        app.MapGet(\"/\", x => x.Response.WriteAsync(appOptions.Name));\n\n        if (env.IsDevelopment())\n        {\n            app.UseAspnetOpenApi();\n        }\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Extensions/Infrastructure/MediatRExtensions.cs",
    "content": "using BuildingBlocks.Caching;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Logging;\nusing BuildingBlocks.Validation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Flight.Extensions.Infrastructure;\n\npublic static class MediatRExtensions\n{\n    public static IServiceCollection AddCustomMediatR(this IServiceCollection services)\n    {\n        services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(FlightRoot).Assembly));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(InvalidateCachingBehavior<,>));\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flight.csproj",
    "content": "  <Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.AspNetCore\" Version=\"2.76.0\" />\n    <PackageReference Include=\"Grpc.Net.Client\" Version=\"2.76.0\" />\n    <PackageReference Include=\"Grpc.Tools\" Version=\"2.78.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"10.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Data\\Migrations\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"GrpcServer\\Protos\\flight.proto\" GrpcServices=\"Both\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\Aspire\\src\\ServiceDefaults\\ServiceDefaults.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Flight/src/Flight/FlightEventMapper.cs",
    "content": "using BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.Event;\n\nnamespace Flight;\n\nusing Aircrafts.Features.CreatingAircraft.V1;\nusing Aircrafts.ValueObjects;\nusing Airports.Features.CreatingAirport.V1;\nusing Flights.Features.CreatingFlight.V1;\nusing Flights.Features.DeletingFlight.V1;\nusing Flights.Features.UpdatingFlight.V1;\nusing Seats.Features.CreatingSeat.V1;\nusing Seats.Features.ReservingSeat.V1;\n\n// ref: https://www.ledjonbehluli.com/posts/domain_to_integration_event/\npublic sealed class FlightEventMapper : IEventMapper\n{\n    public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            FlightCreatedDomainEvent e => new FlightCreated(e.Id),\n            FlightUpdatedDomainEvent e => new FlightUpdated(e.Id),\n            FlightDeletedDomainEvent e => new FlightDeleted(e.Id),\n            AirportCreatedDomainEvent e => new AirportCreated(e.Id),\n            AircraftCreatedDomainEvent e => new AircraftCreated(e.Id),\n            SeatCreatedDomainEvent e => new SeatCreated(e.Id),\n            SeatReservedDomainEvent e => new SeatReserved(e.Id),\n            _ => null\n        };\n    }\n\n    public IInternalCommand? MapToInternalCommand(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            FlightCreatedDomainEvent e => new CreateFlightMongo(e.Id, e.FlightNumber, e.AircraftId, e.DepartureDate, e.DepartureAirportId,\n                e.ArriveDate, e.ArriveAirportId, e.DurationMinutes, e.FlightDate, e.Status, e.Price, e.IsDeleted),\n            FlightUpdatedDomainEvent e => new UpdateFlightMongo(e.Id, e.FlightNumber, e.AircraftId, e.DepartureDate, e.DepartureAirportId,\n                e.ArriveDate, e.ArriveAirportId, e.DurationMinutes, e.FlightDate, e.Status, e.Price, e.IsDeleted),\n            FlightDeletedDomainEvent e => new DeleteFlightMongo(e.Id, e.FlightNumber, e.AircraftId, e.DepartureDate, e.DepartureAirportId,\n                e.ArriveDate, e.ArriveAirportId, e.DurationMinutes, e.FlightDate, e.Status, e.Price, e.IsDeleted),\n            AircraftCreatedDomainEvent e => new CreateAircraftMongo(e.Id, e.Name, e.Model, e.ManufacturingYear, e.IsDeleted),\n            AirportCreatedDomainEvent e => new CreateAirportMongo(e.Id, e.Name, e.Address, e.Code, e.IsDeleted),\n            SeatCreatedDomainEvent e => new CreateSeatMongo(e.Id, e.SeatNumber, e.Type, e.Class, e.FlightId, e.IsDeleted),\n            SeatReservedDomainEvent e => new ReserveSeatMongo(e.Id, e.SeatNumber, e.Type, e.Class, e.FlightId, e.IsDeleted),\n            _ => null\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/FlightRoot.cs",
    "content": "namespace Flight;\n\npublic class FlightRoot\n{\n\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Dtos/FlightDto.cs",
    "content": "using System;\n\nnamespace Flight.Flights.Dtos;\n\npublic record FlightDto(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,\n    DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,\n    Enums.FlightStatus Status, decimal Price);"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Enums/FlightStatus.cs",
    "content": "namespace Flight.Flights.Enums;\n\npublic enum FlightStatus\n{\n    Unknown = 0,\n    Flying = 1,\n    Delay = 2,\n    Canceled = 3,\n    Completed = 4\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/FlightAlreadyExistException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class FlightAlreadyExistException : AppException\n{\n    public FlightAlreadyExistException(int? code = default) : base(\"Flight already exist!\", HttpStatusCode.Conflict, code)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/FlightNotFountException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class FlightNotFountException : AppException\n{\n    public FlightNotFountException() : base(\"Flight not found!\", HttpStatusCode.NotFound)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidArriveDateException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidArriveDateException : DomainException\n{\n    public InvalidArriveDateException(DateTime arriveDate)\n        : base($\"Arrive Date: '{arriveDate}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDepartureDateException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidDepartureDateException : DomainException\n{\n    public InvalidDepartureDateException(DateTime departureDate)\n        : base($\"Departure Date: '{departureDate}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDurationException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidDurationException : DomainException\n{\n    public InvalidDurationException()\n        : base(\"Duration cannot be negative.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightDateException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidFlightDateException : DomainException\n{\n    public InvalidFlightDateException(DateTime flightDate)\n        : base($\"Flight Date: '{flightDate}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidFlightIdException : DomainException\n{\n    public InvalidFlightIdException(Guid flightId)\n        : base($\"flightId: '{flightId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightNumberException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidFlightNumberException : DomainException\n{\n    public InvalidFlightNumberException(string flightNumber)\n        : base($\"Flight Number: '{flightNumber}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Exceptions/InvalidPriceException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Flights.Exceptions;\n\npublic class InvalidPriceException : DomainException\n{\n    public InvalidPriceException()\n        : base($\"Price Cannot be negative.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlight.cs",
    "content": "namespace Flight.Flights.Features.CreatingFlight.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Aircrafts.ValueObjects;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Flight.Airports.ValueObjects;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing ValueObjects;\n\npublic record CreateFlight(string FlightNumber, Guid AircraftId, Guid DepartureAirportId,\n    DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId,\n    decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status,\n    decimal Price) : ICommand<CreateFlightResult>, IInternalCommand\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record CreateFlightResult(Guid Id);\n\npublic record FlightCreatedDomainEvent(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,\n    Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes,\n    DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted) : IDomainEvent;\n\npublic record CreateFlightRequestDto(string FlightNumber, Guid AircraftId, Guid DepartureAirportId,\n    DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId,\n    decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price);\n\npublic record CreateFlightResponseDto(Guid Id);\n\npublic class CreateFlightEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/flight\", async (CreateFlightRequestDto request,\n                IMediator mediator, IMapper mapper,\n                CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<CreateFlight>(request);\n\n                var result = await mediator.Send(command, cancellationToken);\n\n                var response = result.Adapt<CreateFlightResponseDto>();\n\n                return Results.CreatedAtRoute(\"GetFlightById\", new { id = result.Id }, response);\n            })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CreateFlight\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<CreateFlightResponseDto>(StatusCodes.Status201Created)\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Create Flight\")\n            .WithDescription(\"Create Flight\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class CreateFlightValidator : AbstractValidator<CreateFlight>\n{\n    public CreateFlightValidator()\n    {\n        RuleFor(x => x.Price).GreaterThan(0).WithMessage(\"Price must be greater than 0\");\n\n        RuleFor(x => x.Status).Must(p => (p.GetType().IsEnum &&\n                                          p == Enums.FlightStatus.Flying) ||\n                                         p == Enums.FlightStatus.Canceled ||\n                                         p == Enums.FlightStatus.Delay ||\n                                         p == Enums.FlightStatus.Completed)\n            .WithMessage(\"Status must be Flying, Delay, Canceled or Completed\");\n\n        RuleFor(x => x.AircraftId).NotEmpty().WithMessage(\"AircraftId must be not empty\");\n        RuleFor(x => x.DepartureAirportId).NotEmpty().WithMessage(\"DepartureAirportId must be not empty\");\n        RuleFor(x => x.ArriveAirportId).NotEmpty().WithMessage(\"ArriveAirportId must be not empty\");\n        RuleFor(x => x.DurationMinutes).GreaterThan(0).WithMessage(\"DurationMinutes must be greater than 0\");\n        RuleFor(x => x.FlightDate).NotEmpty().WithMessage(\"FlightDate must be not empty\");\n    }\n}\n\ninternal class CreateFlightHandler : ICommandHandler<CreateFlight, CreateFlightResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public CreateFlightHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<CreateFlightResult> Handle(CreateFlight request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == request.Id,\n            cancellationToken);\n\n        if (flight is not null)\n        {\n            throw new FlightAlreadyExistException();\n        }\n\n        var flightEntity = Models.Flight.Create(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId),\n            AirportId.Of(request.DepartureAirportId), DepartureDate.Of(request.DepartureDate),\n            ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status,\n            Price.Of(request.Price));\n\n        var newFlight = (await _flightDbContext.Flights.AddAsync(flightEntity, cancellationToken)).Entity;\n\n        return new CreateFlightResult(newFlight.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlightMongo.cs",
    "content": "namespace Flight.Flights.Features.CreatingFlight.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record CreateFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,\n    Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,\n    Enums.FlightStatus Status, decimal Price, bool IsDeleted = false) : InternalCommand;\n\ninternal class CreateFlightMongoHandler : ICommandHandler<CreateFlightMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public CreateFlightMongoHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(CreateFlightMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flightReadModel = _mapper.Map<FlightReadModel>(request);\n\n        var flight = await _flightReadDbContext.Flight.AsQueryable()\n            .FirstOrDefaultAsync(x => x.FlightId == flightReadModel.FlightId && !x.IsDeleted, cancellationToken);\n\n        if (flight is not null)\n        {\n            throw new FlightAlreadyExistException();\n        }\n\n        await _flightReadDbContext.Flight.InsertOneAsync(flightReadModel, cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlight.cs",
    "content": "using Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Flight.Data;\nusing Flight.Flights.Exceptions;\nusing FluentValidation;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Flight.Flights.Features.DeletingFlight.V1;\n\npublic record DeleteFlight(Guid Id) : ICommand<DeleteFlightResult>, IInternalCommand;\n\npublic record DeleteFlightResult(Guid Id);\n\npublic record FlightDeletedDomainEvent(\n    Guid Id,\n    string FlightNumber,\n    Guid AircraftId,\n    DateTime DepartureDate,\n    Guid DepartureAirportId,\n    DateTime ArriveDate,\n    Guid ArriveAirportId,\n    decimal DurationMinutes,\n    DateTime FlightDate,\n    Enums.FlightStatus Status,\n    decimal Price,\n    bool IsDeleted\n) : IDomainEvent;\n\npublic class DeleteFlightEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapDelete(\n                $\"{EndpointConfig.BaseApiPath}/flight/{{id}}\",\n                async (Guid id, IMediator mediator, CancellationToken cancellationToken) =>\n                {\n                    await mediator.Send(new DeleteFlight(id), cancellationToken);\n\n                    return Results.NoContent();\n                })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"DeleteFlight\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces(StatusCodes.Status204NoContent)\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Delete Flight\")\n            .WithDescription(\"Delete Flight\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class DeleteFlightValidator : AbstractValidator<DeleteFlight>\n{\n    public DeleteFlightValidator()\n    {\n        RuleFor(x => x.Id).NotEmpty();\n    }\n}\n\ninternal class DeleteFlightHandler : ICommandHandler<DeleteFlight, DeleteFlightResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public DeleteFlightHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<DeleteFlightResult> Handle(\n        DeleteFlight request,\n        CancellationToken cancellationToken\n    )\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == request.Id, cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFountException();\n        }\n\n        flight.Delete(\n            flight.Id,\n            flight.FlightNumber,\n            flight.AircraftId,\n            flight.DepartureAirportId,\n            flight.DepartureDate,\n            flight.ArriveDate,\n            flight.ArriveAirportId,\n            flight.DurationMinutes,\n            flight.FlightDate,\n            flight.Status,\n            flight.Price);\n\n        var deleteFlight = _flightDbContext.Flights.Update(flight).Entity;\n\n        return new DeleteFlightResult(deleteFlight.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlightMongo.cs",
    "content": "namespace Flight.Flights.Features.DeletingFlight.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record DeleteFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,\n    Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,\n    Enums.FlightStatus Status, decimal Price, bool IsDeleted = false) : InternalCommand;\n\ninternal class DeleteFlightMongoCommandHandler : ICommandHandler<DeleteFlightMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public DeleteFlightMongoCommandHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(DeleteFlightMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flightReadModel = _mapper.Map<FlightReadModel>(request);\n\n        var flight = await _flightReadDbContext.Flight.AsQueryable()\n            .FirstOrDefaultAsync(x => x.FlightId == flightReadModel.FlightId && !x.IsDeleted, cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFountException();\n        }\n\n        await _flightReadDbContext.Flight.UpdateOneAsync(\n            x => x.FlightId == flightReadModel.FlightId,\n            Builders<FlightReadModel>.Update\n                .Set(x => x.IsDeleted, flightReadModel.IsDeleted),\n            cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/FlightMappings.cs",
    "content": "using Mapster;\n\nnamespace Flight.Flights.Features;\n\nusing CreatingFlight.V1;\nusing DeletingFlight.V1;\nusing MassTransit;\nusing Models;\nusing UpdatingFlight.V1;\nusing FlightDto = Dtos.FlightDto;\n\npublic class FlightMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<Models.Flight, FlightDto>()\n            .ConstructUsing(x => new FlightDto(x.Id, x.FlightNumber, x.AircraftId, x.DepartureAirportId,\n                x.DepartureDate,\n                x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.Price));\n\n        config.NewConfig<CreateFlightMongo, FlightReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.FlightId, s => s.Id);\n\n        config.NewConfig<Models.Flight, FlightReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.FlightId, s => s.Id.Value);\n\n        config.NewConfig<FlightReadModel, FlightDto>()\n            .Map(d => d.Id, s => s.FlightId);\n\n        config.NewConfig<UpdateFlightMongo, FlightReadModel>()\n            .Map(d => d.FlightId, s => s.Id);\n\n        config.NewConfig<DeleteFlightMongo, FlightReadModel>()\n            .Map(d => d.FlightId, s => s.Id);\n\n        config.NewConfig<CreateFlightRequestDto, CreateFlight>()\n            .ConstructUsing(x => new CreateFlight(x.FlightNumber, x.AircraftId, x.DepartureAirportId,\n                x.DepartureDate, x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.Price));\n\n        config.NewConfig<UpdateFlightRequestDto, UpdateFlight>()\n            .ConstructUsing(x => new UpdateFlight(x.Id, x.FlightNumber, x.AircraftId, x.DepartureAirportId, x.DepartureDate,\n                x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.IsDeleted, x.Price));\n\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/GettingAvailableFlights/V1/GetAvailableFlights.cs",
    "content": "using MongoDB.Driver.Linq;\n\nnamespace Flight.Flights.Features.GettingAvailableFlights.V1;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Caching;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Web;\nusing Data;\nusing Dtos;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing MongoDB.Driver;\n\npublic record GetAvailableFlights : IQuery<GetAvailableFlightsResult>, ICacheRequest\n{\n    public string CacheKey => \"GetAvailableFlights\";\n    public DateTime? AbsoluteExpirationRelativeToNow => DateTime.Now.AddHours(1);\n}\n\npublic record GetAvailableFlightsResult(IEnumerable<FlightDto> FlightDtos);\n\npublic record GetAvailableFlightsResponseDto(IEnumerable<FlightDto> FlightDtos);\n\npublic class GetAvailableFlightsEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapGet($\"{EndpointConfig.BaseApiPath}/flight/get-available-flights\",\n                async (IMediator mediator, CancellationToken cancellationToken) =>\n                {\n                    var result = await mediator.Send(new GetAvailableFlights(), cancellationToken);\n\n                    var response = result.Adapt<GetAvailableFlightsResponseDto>();\n\n                    return Results.Ok(response);\n                })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"GetAvailableFlights\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<GetAvailableFlightsResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Get Available Flights\")\n            .WithDescription(\"Get Available Flights\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\ninternal class GetAvailableFlightsHandler : IQueryHandler<GetAvailableFlights, GetAvailableFlightsResult>\n{\n    private readonly IMapper _mapper;\n    private readonly FlightReadDbContext _flightReadDbContext;\n\n    public GetAvailableFlightsHandler(IMapper mapper, FlightReadDbContext flightReadDbContext)\n    {\n        _mapper = mapper;\n        _flightReadDbContext = flightReadDbContext;\n    }\n\n    public async Task<GetAvailableFlightsResult> Handle(GetAvailableFlights request,\n        CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flight = (await _flightReadDbContext.Flight.AsQueryable().ToListAsync(cancellationToken))\n            .Where(x => !x.IsDeleted);\n\n        if (!flight.Any())\n        {\n            throw new FlightNotFountException();\n        }\n\n        var flightDtos = _mapper.Map<IEnumerable<FlightDto>>(flight);\n\n        return new GetAvailableFlightsResult(flightDtos);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/GettingFlightById/V1/GetFlightById.cs",
    "content": "namespace Flight.Flights.Features.GettingFlightById.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Web;\nusing Data;\nusing Dtos;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record GetFlightById(Guid Id) : IQuery<GetFlightByIdResult>;\n\npublic record GetFlightByIdResult(FlightDto FlightDto);\n\npublic record GetFlightByIdResponseDto(FlightDto FlightDto);\n\npublic class GetFlightByIdEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapGet($\"{EndpointConfig.BaseApiPath}/flight/{{id}}\",\n                async (Guid id, IMediator mediator, IMapper mapper, CancellationToken cancellationToken) =>\n                {\n                    var result = await mediator.Send(new GetFlightById(id), cancellationToken);\n\n                    var response = result.Adapt<GetFlightByIdResponseDto>();\n\n                    return Results.Ok(response);\n                })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"GetFlightById\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<GetFlightByIdResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Get Flight By Id\")\n            .WithDescription(\"Get Flight By Id\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class GetFlightByIdValidator : AbstractValidator<GetFlightById>\n{\n    public GetFlightByIdValidator()\n    {\n        RuleFor(x => x.Id).NotNull().WithMessage(\"Id is required!\");\n    }\n}\n\ninternal class GetFlightByIdHandler : IQueryHandler<GetFlightById, GetFlightByIdResult>\n{\n    private readonly IMapper _mapper;\n    private readonly FlightReadDbContext _flightReadDbContext;\n\n    public GetFlightByIdHandler(IMapper mapper, FlightReadDbContext flightReadDbContext)\n    {\n        _mapper = mapper;\n        _flightReadDbContext = flightReadDbContext;\n    }\n\n    public async Task<GetFlightByIdResult> Handle(GetFlightById request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flight = await _flightReadDbContext.Flight.AsQueryable().SingleOrDefaultAsync(\n            x => x.FlightId == request.Id &&\n                             !x.IsDeleted, cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFountException();\n        }\n\n        var flightDto = _mapper.Map<FlightDto>(flight);\n\n        return new GetFlightByIdResult(flightDto);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlight.cs",
    "content": "namespace Flight.Flights.Features.UpdatingFlight.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Aircrafts.ValueObjects;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Caching;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Flight.Airports.ValueObjects;\nusing Flight.Flights.Features.CreatingFlight.V1;\nusing FluentValidation;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing ValueObjects;\n\npublic record UpdateFlight(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,\n    DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,\n    Enums.FlightStatus Status, bool IsDeleted, decimal Price) : ICommand<UpdateFlightResult>, IInternalCommand,\n    IInvalidateCacheRequest\n{\n    public string CacheKey => \"GetAvailableFlights\";\n}\n\npublic record UpdateFlightResult(Guid Id);\n\npublic record FlightUpdatedDomainEvent(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,\n    Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes,\n    DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted) : IDomainEvent;\n\npublic record UpdateFlightRequestDto(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,\n    DateTime DepartureDate, DateTime ArriveDate,\n    Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price,\n    bool IsDeleted);\n\npublic class UpdateFlightEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPut($\"{EndpointConfig.BaseApiPath}/flight\", async (UpdateFlightRequestDto request,\n                IMediator mediator,\n                IMapper mapper, CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<UpdateFlight>(request);\n\n                await mediator.Send(command, cancellationToken);\n\n                return Results.NoContent();\n            })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"UpdateFlight\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces(StatusCodes.Status204NoContent)\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Update Flight\")\n            .WithDescription(\"Update Flight\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class UpdateFlightValidator : AbstractValidator<CreateFlight>\n{\n    public UpdateFlightValidator()\n    {\n        RuleFor(x => x.Price).GreaterThan(0).WithMessage(\"Price must be greater than 0\");\n\n        RuleFor(x => x.Status).Must(p => (p.GetType().IsEnum &&\n                                          p == Enums.FlightStatus.Flying) ||\n                                         p == Enums.FlightStatus.Canceled ||\n                                         p == Enums.FlightStatus.Delay ||\n                                         p == Enums.FlightStatus.Completed)\n            .WithMessage(\"Status must be Flying, Delay, Canceled or Completed\");\n\n        RuleFor(x => x.AircraftId).NotEmpty().WithMessage(\"AircraftId must be not empty\");\n        RuleFor(x => x.DepartureAirportId).NotEmpty().WithMessage(\"DepartureAirportId must be not empty\");\n        RuleFor(x => x.ArriveAirportId).NotEmpty().WithMessage(\"ArriveAirportId must be not empty\");\n        RuleFor(x => x.DurationMinutes).GreaterThan(0).WithMessage(\"DurationMinutes must be greater than 0\");\n        RuleFor(x => x.FlightDate).NotEmpty().WithMessage(\"FlightDate must be not empty\");\n    }\n}\n\ninternal class UpdateFlightHandler : ICommandHandler<UpdateFlight, UpdateFlightResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public UpdateFlightHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<UpdateFlightResult> Handle(UpdateFlight request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == request.Id,\n            cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFountException();\n        }\n\n\n        flight.Update(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId), AirportId.Of(request.DepartureAirportId),\n            DepartureDate.Of(request.DepartureDate),\n            ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status,\n            Price.Of(request.Price), request.IsDeleted);\n\n        var updateFlight = _flightDbContext.Flights.Update(flight).Entity;\n\n        return new UpdateFlightResult(updateFlight.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlightMongo.cs",
    "content": "namespace Flight.Flights.Features.UpdatingFlight.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record UpdateFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,\n    Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,\n    Enums.FlightStatus Status, decimal Price, bool IsDeleted = false) : InternalCommand;\n\n\ninternal class UpdateFlightMongoCommandHandler : ICommandHandler<UpdateFlightMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public UpdateFlightMongoCommandHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(UpdateFlightMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var flightReadModel = _mapper.Map<FlightReadModel>(request);\n\n        var flight = await _flightReadDbContext.Flight.AsQueryable()\n            .FirstOrDefaultAsync(x => x.FlightId == flightReadModel.FlightId && !x.IsDeleted, cancellationToken);\n\n        if (flight is null)\n        {\n            throw new FlightNotFountException();\n        }\n\n        await _flightReadDbContext.Flight.UpdateOneAsync(\n            x => x.FlightId == flightReadModel.FlightId,\n            Builders<FlightReadModel>.Update\n                .Set(x => x.Price, flightReadModel.Price)\n                .Set(x => x.ArriveDate, flightReadModel.ArriveDate)\n                .Set(x => x.AircraftId, flightReadModel.AircraftId)\n                .Set(x => x.DurationMinutes, flightReadModel.DurationMinutes)\n                .Set(x => x.DepartureDate, flightReadModel.DepartureDate)\n                .Set(x => x.FlightDate, flightReadModel.FlightDate)\n                .Set(x => x.FlightNumber, flightReadModel.FlightNumber)\n                .Set(x => x.IsDeleted, flightReadModel.IsDeleted)\n                .Set(x => x.Status, flightReadModel.Status)\n                .Set(x => x.ArriveAirportId, flightReadModel.ArriveAirportId)\n                .Set(x => x.DepartureAirportId, flightReadModel.DepartureAirportId),\n            cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Models/Flight.cs",
    "content": "using BuildingBlocks.Core.Model;\n\nnamespace Flight.Flights.Models;\n\nusing Aircrafts.ValueObjects;\nusing Airports.ValueObjects;\nusing Features.CreatingFlight.V1;\nusing Features.DeletingFlight.V1;\nusing Features.UpdatingFlight.V1;\nusing ValueObjects;\n\npublic record Flight : Aggregate<FlightId>\n{\n    public FlightNumber FlightNumber { get; private set; } = default!;\n    public AircraftId AircraftId { get; private set; } = default!;\n    public AirportId DepartureAirportId { get; private set; } = default!;\n    public AirportId ArriveAirportId { get; private set; } = default!;\n    public DurationMinutes DurationMinutes { get; private set; } = default!;\n    public Enums.FlightStatus Status { get; private set; }\n    public Price Price { get; private set; } = default!;\n    public ArriveDate ArriveDate { get; private set; } = default!;\n    public DepartureDate DepartureDate { get; private set; } = default!;\n    public FlightDate FlightDate { get; private set; } = default!;\n\n    public static Flight Create(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,\n        AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,\n        AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,\n        Price price, bool isDeleted = false)\n    {\n        var flight = new Flight\n        {\n            Id = id,\n            FlightNumber = flightNumber,\n            AircraftId = aircraftId,\n            DepartureAirportId = departureAirportId,\n            DepartureDate = departureDate,\n            ArriveDate = arriveDate,\n            ArriveAirportId = arriveAirportId,\n            DurationMinutes = durationMinutes,\n            FlightDate = flightDate,\n            Status = status,\n            Price = price,\n            IsDeleted = isDeleted,\n        };\n\n        var @event = new FlightCreatedDomainEvent(flight.Id, flight.FlightNumber, flight.AircraftId,\n            flight.DepartureDate, flight.DepartureAirportId,\n            flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status,\n            flight.Price, flight.IsDeleted);\n\n        flight.AddDomainEvent(@event);\n\n        return flight;\n    }\n\n\n    public void Update(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,\n        AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,\n        AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,\n        Price price, bool isDeleted = false)\n    {\n        this.FlightNumber = flightNumber;\n        this.AircraftId = aircraftId;\n        this.DepartureAirportId = departureAirportId;\n        this.DepartureDate = departureDate;\n        this.ArriveDate = arriveDate;\n        this.ArriveAirportId = arriveAirportId;\n        this.DurationMinutes = durationMinutes;\n        this.FlightDate = flightDate;\n        this.Status = status;\n        this.Price = price;\n        this.IsDeleted = isDeleted;\n\n        var @event = new FlightUpdatedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId,\n            arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted);\n\n        AddDomainEvent(@event);\n    }\n\n    public void Delete(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,\n        AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,\n        AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,\n        Price price, bool isDeleted = true)\n    {\n        FlightNumber = flightNumber;\n        AircraftId = aircraftId;\n        DepartureAirportId = departureAirportId;\n        DepartureDate = departureDate;\n        ArriveDate = arriveDate;\n        ArriveAirportId = arriveAirportId;\n        DurationMinutes = durationMinutes;\n        FlightDate = flightDate;\n        Status = status;\n        Price = price;\n        IsDeleted = isDeleted;\n\n        var @event = new FlightDeletedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId,\n            arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted);\n\n        AddDomainEvent(@event);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/Models/FlightReadModel.cs",
    "content": "namespace Flight.Flights.Models;\n\nusing System;\n\npublic class FlightReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid FlightId { get; init; }\n    public required string FlightNumber { get; init; }\n    public required Guid AircraftId { get; init; }\n    public required DateTime DepartureDate { get; init; }\n    public required Guid DepartureAirportId { get; init; }\n    public required DateTime ArriveDate { get; init; }\n    public required Guid ArriveAirportId { get; init; }\n    public required decimal DurationMinutes { get; init; }\n    public required DateTime FlightDate { get; init; }\n    public required Enums.FlightStatus Status { get; init; }\n    public required decimal Price { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/ArriveDate.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing System;\nusing Flight.Flights.Exceptions;\n\npublic record ArriveDate\n{\n    public DateTime Value { get; }\n\n    private ArriveDate(DateTime value)\n    {\n        Value = value;\n    }\n\n    public static ArriveDate Of(DateTime value)\n    {\n        if (value == default)\n        {\n            throw new InvalidArriveDateException(value);\n        }\n\n        return new ArriveDate(value);\n    }\n\n    public static implicit operator DateTime(ArriveDate arriveDate)\n    {\n        return arriveDate.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/DepartureDate.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing System;\nusing Flight.Flights.Exceptions;\n\n\npublic record DepartureDate\n{\n    public DateTime Value { get; }\n\n    private DepartureDate(DateTime value)\n    {\n        Value = value;\n    }\n\n    public static DepartureDate Of(DateTime value)\n    {\n        if (value == default)\n        {\n            throw new InvalidDepartureDateException(value);\n        }\n\n        return new DepartureDate(value);\n    }\n\n    public static implicit operator DateTime(DepartureDate departureDate)\n    {\n        return departureDate.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/DurationMinutes.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing Exceptions;\n\npublic class DurationMinutes\n{\n    public decimal Value { get; }\n\n    private DurationMinutes(decimal value)\n    {\n        Value = value;\n    }\n\n    public static DurationMinutes Of(decimal value)\n    {\n        if (value < 0)\n        {\n            throw new InvalidDurationException();\n        }\n\n        return new DurationMinutes(value);\n    }\n\n    public static implicit operator decimal(DurationMinutes duration)\n    {\n        return duration.Value;\n    }\n\n    public static explicit operator DurationMinutes(decimal value)\n    {\n        return new DurationMinutes(value);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/FlightDate.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing System;\nusing Flight.Flights.Exceptions;\n\npublic record FlightDate\n{\n    public DateTime Value { get; }\n\n    private FlightDate(DateTime value)\n    {\n        Value = value;\n    }\n\n    public static FlightDate Of(DateTime value)\n    {\n        if (value == default)\n        {\n            throw new InvalidFlightDateException(value);\n        }\n\n        return new FlightDate(value);\n    }\n\n    public static implicit operator DateTime(FlightDate flightDate)\n    {\n        return flightDate.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/FlightId.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing System;\nusing Exceptions;\n\npublic record FlightId\n{\n    public Guid Value { get; }\n\n    private FlightId(Guid value)\n    {\n        Value = value;\n    }\n\n    public static FlightId Of(Guid value)\n    {\n        if (value == Guid.Empty)\n        {\n            throw new InvalidFlightIdException(value);\n        }\n\n        return new FlightId(value);\n    }\n\n    public static implicit operator Guid(FlightId flightId)\n    {\n        return flightId.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/FlightNumber.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing Exceptions;\n\npublic record FlightNumber\n{\n    public string Value { get; }\n\n    private FlightNumber(string value)\n    {\n        Value = value;\n    }\n\n    public static FlightNumber Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidFlightNumberException(value);\n        }\n\n        return new FlightNumber(value);\n    }\n\n    public static implicit operator string(FlightNumber flightNumber)\n    {\n        return flightNumber.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Flights/ValueObjects/Price.cs",
    "content": "namespace Flight.Flights.ValueObjects;\n\nusing Flight.Flights.Exceptions;\n\npublic class Price\n{\n    public decimal Value { get; }\n\n    private Price(decimal value)\n    {\n        Value = value;\n    }\n\n    public static Price Of(decimal value)\n    {\n        if (value < 0)\n        {\n            throw new InvalidPriceException();\n        }\n\n        return new Price(value);\n    }\n\n    public static implicit operator decimal(Price price)\n    {\n        return price.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/GrpcServer/Protos/flight.proto",
    "content": "syntax = \"proto3\";\n\npackage flight;\nimport \"google/protobuf/timestamp.proto\";\n\nservice FlightGrpcService {\n\n  rpc GetById (GetByIdRequest) returns (GetFlightByIdResult);\n  rpc GetAvailableSeats (GetAvailableSeatsRequest) returns (GetAvailableSeatsResult);\n  rpc ReserveSeat (ReserveSeatRequest) returns (ReserveSeatResult);\n}\n\nmessage GetByIdRequest {\n  string Id = 1;\n}\n\nmessage GetFlightByIdResult{\n  FlightResponse FlightDto = 1;\n}\n\nmessage GetAvailableSeatsResult{\nrepeated SeatDtoResponse SeatDtos = 1;\n}\n\nmessage ReserveSeatResult{\n    string Id = 1;\n}\n\nmessage FlightResponse {\n  string Id = 1;\n  string FlightNumber = 2;\n  string AircraftId = 3;\n  string DepartureAirportId = 4;\n  google.protobuf.Timestamp DepartureDate = 5;\n  google.protobuf.Timestamp ArriveDate = 6;\n  string ArriveAirportId = 7;\n  double DurationMinutes = 8;\n  google.protobuf.Timestamp FlightDate = 9;\n  FlightStatus Status = 10;\n  double Price = 11;\n  string FlightId = 12;\n}\n\nmessage GetAvailableSeatsRequest {\n  string FlightId = 1;\n}\n\nmessage SeatDtoResponse {\n  string Id = 1;\n  string SeatNumber = 2;\n  SeatType Type = 3;\n  SeatClass Class = 4;\n  string FlightId = 5;\n}\n\n\nmessage ReserveSeatRequest {\n  string FlightId = 1;\n  string SeatNumber = 2;\n}\n\n\n    enum FlightStatus {\n      FLIGHT_STATUS_UNKNOWN = 0;\n      FLIGHT_STATUS_FLYING = 1;\n      FLIGHT_STATUS_DELAY = 2;\n      FLIGHT_STATUS_CANCELED = 3;\n      FLIGHT_STATUS_COMPLETED = 4;\n    }\n\n\n    enum SeatType {\n        SEAT_TYPE_UNKNOWN = 0;\n        SEAT_TYPE_WINDOW = 1;\n        SEAT_TYPE_MIDDLE = 2;\n        SEAT_TYPE_AISLE = 3;\n    }\n\n\n    enum SeatClass {\n        SEAT_CLASS_UNKNOWN = 0;\n        SEAT_CLASS_FIRST_CLASS = 1;\n        SEAT_CLASS_BUSINESS = 2;\n        SEAT_CLASS_ECONOMY = 3;\n    }\n"
  },
  {
    "path": "src/Services/Flight/src/Flight/GrpcServer/Services/FlightGrpcServices.cs",
    "content": "using System.Threading.Tasks;\nusing Grpc.Core;\nusing Mapster;\nusing MediatR;\n\nnamespace Flight.GrpcServer.Services;\n\nusing System;\nusing Flights.Features.GettingFlightById.V1;\nusing Seats.Features.GettingAvailableSeats.V1;\nusing Seats.Features.ReservingSeat.V1;\nusing GetAvailableSeatsResult = GetAvailableSeatsResult;\nusing GetFlightByIdResult = GetFlightByIdResult;\nusing ReserveSeatResult = ReserveSeatResult;\n\npublic class FlightGrpcServices : FlightGrpcService.FlightGrpcServiceBase\n{\n    private readonly IMediator _mediator;\n\n    public FlightGrpcServices(IMediator mediator)\n    {\n        _mediator = mediator;\n    }\n\n    public override async Task<GetFlightByIdResult> GetById(GetByIdRequest request, ServerCallContext context)\n    {\n        var result = await _mediator.Send(new GetFlightById(new Guid(request.Id)));\n        return result.Adapt<GetFlightByIdResult>();\n    }\n\n    public override async Task<GetAvailableSeatsResult> GetAvailableSeats(GetAvailableSeatsRequest request, ServerCallContext context)\n    {\n        var result = new GetAvailableSeatsResult();\n\n        var availableSeats = await _mediator.Send(new GetAvailableSeats(new Guid(request.FlightId)));\n\n        if (availableSeats?.SeatDtos == null)\n        {\n            return result;\n        }\n\n        foreach (var availableSeat in availableSeats.SeatDtos)\n        {\n            result.SeatDtos.Add(availableSeat.Adapt<SeatDtoResponse>());\n        }\n\n        return result;\n    }\n\n    public override async Task<ReserveSeatResult> ReserveSeat(ReserveSeatRequest request, ServerCallContext context)\n    {\n        var result = await _mediator.Send(new ReserveSeat(new Guid(request.FlightId), request.SeatNumber));\n        return result.Adapt<ReserveSeatResult>();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Dtos/SeatDto.cs",
    "content": "namespace Flight.Seats.Dtos;\n\nusing System;\n\npublic record SeatDto(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId);"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Enums/SeatClass.cs",
    "content": "namespace Flight.Seats.Enums;\n\npublic enum SeatClass\n{\n    Unknown = 0,\n    FirstClass,\n    Business,\n    Economy\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Enums/SeatType.cs",
    "content": "namespace Flight.Seats.Enums;\n\npublic enum SeatType\n{\n    Unknown = 0,\n    Window,\n    Middle,\n    Aisle\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Exceptions/AllSeatsFullException.cs",
    "content": "using BuildingBlocks.Exception;\n\nnamespace Flight.Seats.Exceptions;\n\npublic class AllSeatsFullException : AppException\n{\n    public AllSeatsFullException() : base(\"All seats are full!\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Seats.Exceptions;\n\npublic class InvalidSeatIdException : DomainException\n{\n    public InvalidSeatIdException(Guid seatId)\n        : base($\"seatId: '{seatId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatNumberException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Flight.Seats.Exceptions;\n\npublic class InvalidSeatNumberException : DomainException\n{\n    public InvalidSeatNumberException() : base(\"SeatNumber Cannot be null or negative\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Exceptions/SeatAlreadyExistException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Flight.Seats.Exceptions;\n\npublic class SeatAlreadyExistException : AppException\n{\n    public SeatAlreadyExistException(int? code = default) : base(\"Seat already exist!\", HttpStatusCode.Conflict, code)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Exceptions/SeatNumberIncorrectException.cs",
    "content": "using BuildingBlocks.Exception;\n\nnamespace Flight.Seats.Exceptions;\n\npublic class SeatNumberIncorrectException : AppException\n{\n    public SeatNumberIncorrectException() : base(\"Seat number is incorrect!\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeat.cs",
    "content": "namespace Flight.Seats.Features.CreatingSeat.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing Flights.ValueObjects;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing Models;\nusing ValueObjects;\n\npublic record CreateSeat\n    (string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId) : ICommand<CreateSeatResult>,\n        IInternalCommand\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record CreateSeatResult(Guid Id);\n\npublic record SeatCreatedDomainEvent(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class,\n    Guid FlightId, bool IsDeleted) : IDomainEvent;\n\npublic record CreateSeatRequestDto(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId);\n\npublic record CreateSeatResponseDto(Guid Id);\n\npublic class CreateSeatEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/flight/seat\", CreateSeat)\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CreateSeat\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<CreateSeatResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Create Seat\")\n            .WithDescription(\"Create Seat\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n\n    private async Task<IResult> CreateSeat(CreateSeatRequestDto request, IMediator mediator, IMapper mapper,\n        CancellationToken cancellationToken)\n    {\n        var command = mapper.Map<CreateSeat>(request);\n\n        var result = await mediator.Send(command, cancellationToken);\n\n        var response = result.Adapt<CreateSeatResponseDto>();\n\n        return Results.Ok(response);\n    }\n}\n\npublic class CreateSeatValidator : AbstractValidator<CreateSeat>\n{\n    public CreateSeatValidator()\n    {\n        RuleFor(x => x.SeatNumber).NotEmpty().WithMessage(\"SeatNumber is required\");\n        RuleFor(x => x.FlightId).NotEmpty().WithMessage(\"FlightId is required\");\n        RuleFor(x => x.Class).Must(p => (p.GetType().IsEnum &&\n                                         p == Enums.SeatClass.FirstClass) ||\n                                        p == Enums.SeatClass.Business ||\n                                        p == Enums.SeatClass.Economy)\n            .WithMessage(\"Status must be FirstClass, Business or Economy\");\n    }\n}\n\ninternal class CreateSeatCommandHandler : IRequestHandler<CreateSeat, CreateSeatResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public CreateSeatCommandHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<CreateSeatResult> Handle(CreateSeat command, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(command, nameof(command));\n\n        var seat = await _flightDbContext.Seats.SingleOrDefaultAsync(x => x.Id == command.Id, cancellationToken);\n\n        if (seat is not null)\n        {\n            throw new SeatAlreadyExistException();\n        }\n\n        var seatEntity = Seat.Create(SeatId.Of(command.Id), SeatNumber.Of(command.SeatNumber), command.Type, command.Class, FlightId.Of(command.FlightId));\n\n        var newSeat = (await _flightDbContext.Seats.AddAsync(seatEntity, cancellationToken)).Entity;\n\n        return new CreateSeatResult(newSeat.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeatMongo.cs",
    "content": "namespace Flight.Seats.Features.CreatingSeat.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing Exceptions;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\npublic record CreateSeatMongo(Guid Id, string SeatNumber, Enums.SeatType Type,\n    Enums.SeatClass Class, Guid FlightId, bool IsDeleted = false) : InternalCommand;\n\ninternal class CreateSeatMongoHandler : ICommandHandler<CreateSeatMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public CreateSeatMongoHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(CreateSeatMongo request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var seatReadModel = _mapper.Map<SeatReadModel>(request);\n\n        var seat = await _flightReadDbContext.Seat.AsQueryable()\n            .FirstOrDefaultAsync(x => x.SeatId == seatReadModel.SeatId &&\n                                      !x.IsDeleted, cancellationToken);\n\n        if (seat is not null)\n        {\n            throw new SeatAlreadyExistException();\n        }\n\n        await _flightReadDbContext.Seat.InsertOneAsync(seatReadModel, cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/GettingAvailableSeats/V1/GetAvailableSeats.cs",
    "content": "using MongoDB.Driver.Linq;\n\nnamespace Flight.Seats.Features.GettingAvailableSeats.V1;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Web;\nusing Data;\nusing Dtos;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing MongoDB.Driver;\n\npublic record GetAvailableSeats(Guid FlightId) : IQuery<GetAvailableSeatsResult>;\n\npublic record GetAvailableSeatsResult(IEnumerable<SeatDto> SeatDtos);\n\npublic record GetAvailableSeatsResponseDto(IEnumerable<SeatDto> SeatDtos);\n\npublic class GetAvailableSeatsEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapGet($\"{EndpointConfig.BaseApiPath}/flight/get-available-seats/{{id}}\", GetAvailableSeats)\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"GetAvailableSeats\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<GetAvailableSeatsResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Get Available Seats\")\n            .WithDescription(\"Get Available Seats\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n\n    private async Task<IResult> GetAvailableSeats(Guid id, IMediator mediator, CancellationToken cancellationToken)\n    {\n        var result = await mediator.Send(new GetAvailableSeats(id), cancellationToken);\n\n        var response = result.Adapt<GetAvailableSeatsResponseDto>();\n\n        return Results.Ok(response);\n    }\n}\n\npublic class GetAvailableSeatsValidator : AbstractValidator<GetAvailableSeats>\n{\n    public GetAvailableSeatsValidator()\n    {\n        RuleFor(x => x.FlightId).NotNull().WithMessage(\"FlightId is required!\");\n    }\n}\n\ninternal class GetAvailableSeatsQueryHandler : IRequestHandler<GetAvailableSeats, GetAvailableSeatsResult>\n{\n    private readonly IMapper _mapper;\n    private readonly FlightReadDbContext _flightReadDbContext;\n\n    public GetAvailableSeatsQueryHandler(IMapper mapper, FlightReadDbContext flightReadDbContext)\n    {\n        _mapper = mapper;\n        _flightReadDbContext = flightReadDbContext;\n    }\n\n\n    public async Task<GetAvailableSeatsResult> Handle(GetAvailableSeats query, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(query, nameof(query));\n\n        var seats = (await _flightReadDbContext.Seat.AsQueryable().ToListAsync(cancellationToken))\n            .Where(x => x.FlightId == query.FlightId && !x.IsDeleted);\n\n        if (!seats.Any())\n        {\n            throw new AllSeatsFullException();\n        }\n\n        var seatDtos = _mapper.Map<IEnumerable<SeatDto>>(seats);\n\n        return new GetAvailableSeatsResult(seatDtos);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/V1/ReserveSeat.cs",
    "content": "namespace Flight.Seats.Features.ReservingSeat.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Flight.Data;\nusing Flight.Seats.Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\n\npublic record ReserveSeat(Guid FlightId, string SeatNumber) : ICommand<ReserveSeatResult>, IInternalCommand;\n\npublic record ReserveSeatResult(Guid Id);\n\npublic record SeatReservedDomainEvent(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class,\n    Guid FlightId, bool IsDeleted) : IDomainEvent;\n\npublic record ReserveSeatRequestDto(Guid FlightId, string SeatNumber);\n\npublic record ReserveSeatResponseDto(Guid Id);\n\npublic class ReserveSeatEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/flight/reserve-seat\", ReserveSeat)\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"ReserveSeat\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Flight\").Build())\n            .Produces<ReserveSeatResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Reserve Seat\")\n            .WithDescription(\"Reserve Seat\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n\n    private async Task<IResult> ReserveSeat(ReserveSeatRequestDto request, IMediator mediator, IMapper mapper,\n        CancellationToken cancellationToken)\n    {\n        var command = mapper.Map<ReserveSeat>(request);\n\n        var result = await mediator.Send(command, cancellationToken);\n\n        var response = result.Adapt<ReserveSeatResponseDto>();\n\n        return Results.Ok(response);\n    }\n}\n\npublic class ReserveSeatValidator : AbstractValidator<ReserveSeat>\n{\n    public ReserveSeatValidator()\n    {\n        RuleFor(x => x.FlightId).NotEmpty().WithMessage(\"FlightId must not be empty\");\n        RuleFor(x => x.SeatNumber).NotEmpty().WithMessage(\"SeatNumber must not be empty\");\n    }\n}\n\ninternal class ReserveSeatCommandHandler : IRequestHandler<ReserveSeat, ReserveSeatResult>\n{\n    private readonly FlightDbContext _flightDbContext;\n\n    public ReserveSeatCommandHandler(FlightDbContext flightDbContext)\n    {\n        _flightDbContext = flightDbContext;\n    }\n\n    public async Task<ReserveSeatResult> Handle(ReserveSeat command, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(command, nameof(command));\n\n        var seat = await _flightDbContext.Seats.SingleOrDefaultAsync(\n            x => x.SeatNumber.Value == command.SeatNumber &&\n                 x.FlightId == command.FlightId, cancellationToken);\n\n        if (seat is null)\n        {\n            throw new SeatNumberIncorrectException();\n        }\n\n        seat.ReserveSeat();\n\n        var updatedSeat = _flightDbContext.Seats.Update(seat).Entity;\n\n        return new ReserveSeatResult(updatedSeat.Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/V1/ReserveSeatMongo.cs",
    "content": "namespace Flight.Seats.Features.ReservingSeat.V1;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Flight.Data;\nusing Flight.Seats.Models;\nusing MapsterMapper;\nusing MediatR;\nusing MongoDB.Driver;\n\npublic record ReserveSeatMongo(Guid Id, string SeatNumber, Enums.SeatType Type,\n    Enums.SeatClass Class, Guid FlightId, bool IsDeleted = false) : InternalCommand;\n\ninternal class ReserveSeatMongoHandler : ICommandHandler<ReserveSeatMongo>\n{\n    private readonly FlightReadDbContext _flightReadDbContext;\n    private readonly IMapper _mapper;\n\n    public ReserveSeatMongoHandler(\n        FlightReadDbContext flightReadDbContext,\n        IMapper mapper)\n    {\n        _flightReadDbContext = flightReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(ReserveSeatMongo command, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(command, nameof(command));\n\n        var seatReadModel = _mapper.Map<SeatReadModel>(command);\n\n        await _flightReadDbContext.Seat.UpdateOneAsync(\n            x => x.SeatId == seatReadModel.SeatId,\n            Builders<SeatReadModel>.Update\n                .Set(x => x.IsDeleted, seatReadModel.IsDeleted),\n            cancellationToken: cancellationToken);\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Features/SeatMappings.cs",
    "content": "using Flight.Seats.Dtos;\nusing Flight.Seats.Models;\nusing Mapster;\n\nnamespace Flight.Seats.Features;\n\nusing CreatingSeat.V1;\nusing MassTransit;\nusing ReservingSeat.V1;\n\npublic class SeatMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<Seat, SeatDto>()\n            .ConstructUsing(x => new SeatDto(x.Id.Value, x.SeatNumber.Value, x.Type, x.Class, x.FlightId.Value));\n\n        config.NewConfig<CreateSeatMongo, SeatReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.SeatId, s => s.Id);\n\n        config.NewConfig<Seat, SeatReadModel>()\n            .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.SeatId, s => s.Id.Value);\n\n        config.NewConfig<ReserveSeatMongo, SeatReadModel>()\n            .Map(d => d.SeatId, s => s.Id);\n\n        config.NewConfig<CreateSeatRequestDto, CreateSeat>()\n            .ConstructUsing(x => new CreateSeat(x.SeatNumber, x.Type, x.Class, x.FlightId));\n\n        config.NewConfig<ReserveSeatRequestDto, ReserveSeat>()\n            .ConstructUsing(x => new ReserveSeat(x.FlightId, x.SeatNumber));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Models/Seat.cs",
    "content": "using System;\nusing BuildingBlocks.Core.Model;\n\nnamespace Flight.Seats.Models;\n\nusing Features.CreatingSeat.V1;\nusing Features.ReservingSeat.V1;\nusing Flight.Flights.ValueObjects;\nusing ValueObjects;\n\npublic record Seat : Aggregate<SeatId>\n{\n    public SeatNumber SeatNumber { get; private set; } = default!;\n    public Enums.SeatType Type { get; private set; }\n    public Enums.SeatClass Class { get; private set; }\n    public FlightId FlightId { get; private set; } = default!;\n\n    public static Seat Create(SeatId id, SeatNumber seatNumber, Enums.SeatType type, Enums.SeatClass @class,\n        FlightId flightId,\n        bool isDeleted = false)\n    {\n        var seat = new Seat()\n        {\n            Id = id,\n            Class = @class,\n            Type = type,\n            SeatNumber = seatNumber,\n            FlightId = flightId,\n            IsDeleted = isDeleted\n        };\n\n        var @event = new SeatCreatedDomainEvent(\n            seat.Id,\n            seat.SeatNumber,\n            seat.Type,\n            seat.Class,\n            seat.FlightId,\n            isDeleted);\n\n        seat.AddDomainEvent(@event);\n\n        return seat;\n    }\n\n    public void ReserveSeat()\n    {\n        this.IsDeleted = true;\n        this.LastModified = DateTime.Now;\n\n        var @event = new SeatReservedDomainEvent(\n            this.Id,\n            this.SeatNumber,\n            this.Type,\n            this.Class,\n            this.FlightId,\n            this.IsDeleted);\n\n        this.AddDomainEvent(@event);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/Models/SeatReadModel.cs",
    "content": "namespace Flight.Seats.Models;\n\nusing System;\n\npublic class SeatReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid SeatId { get; init; }\n    public required string SeatNumber { get; init; }\n    public required Enums.SeatType Type { get; init; }\n    public required Enums.SeatClass Class { get; init; }\n    public required Guid FlightId { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/ValueObjects/SeatId.cs",
    "content": "namespace Flight.Seats.ValueObjects;\n\nusing System;\nusing Exceptions;\n\npublic record SeatId\n{\n    public Guid Value { get; }\n\n    private SeatId(Guid value)\n    {\n        Value = value;\n    }\n\n    public static SeatId Of(Guid value)\n    {\n        if (value == Guid.Empty)\n        {\n            throw new InvalidSeatIdException(value);\n        }\n\n        return new SeatId(value);\n    }\n\n    public static implicit operator Guid(SeatId seatId)\n    {\n        return seatId.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight/Seats/ValueObjects/SeatNumber.cs",
    "content": "namespace Flight.Seats.ValueObjects;\n\nusing Exceptions;\n\npublic record SeatNumber\n{\n    public string Value { get; }\n\n    private SeatNumber(string value)\n    {\n        Value = value;\n    }\n\n    public static SeatNumber Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidSeatNumberException();\n        }\n\n        return new SeatNumber(value);\n    }\n\n    public static implicit operator string(SeatNumber seatNumber)\n    {\n        return seatNumber.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/Flight.Api.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Flight\\Flight.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/Program.cs",
    "content": "using BuildingBlocks.Web;\nusing Flight;\nusing Flight.Extensions.Infrastructure;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddMinimalEndpoints(assemblies: typeof(FlightRoot).Assembly);\nbuilder.AddInfrastructure();\n\nvar app = builder.Build();\n\n// ref: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-7.0#routing-basics\napp.MapMinimalEndpoints();\napp.UseInfrastructure();\n\napp.Run();\n\nnamespace Flight.Api\n{\n    public partial class Program\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/Properties/launchSettings.json",
    "content": "{\n    \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n    \"profiles\": {\n        \"Flight.Api\": {\n            \"commandName\": \"Project\",\n            \"dotnetRunMessages\": true,\n            \"launchUrl\": \"swagger\",\n            \"launchBrowser\": true,\n            \"applicationUrl\": \"http://localhost:5004;https://localhost:5003\",\n            \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/appsettings.Development.json",
    "content": "{\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/appsettings.docker.json",
    "content": "{\n    \"App\": \"Flight-Service\",\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=flight;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://identity:80\",\n        \"Audience\": \"flight-api\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"rabbitmq\",\n        \"ExchangeName\": \"flight\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://mongo:27017\",\n        \"DatabaseName\": \"flight-db\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/appsettings.json",
    "content": "{\n    \"AppOptions\": {\n        \"Name\": \"Flight-Service\"\n    },\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=flight;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://localhost:27017\",\n        \"DatabaseName\": \"flight-db\"\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://localhost:6005\",\n        \"Audience\": \"flight-api\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"flight\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"HealthOptions\": {\n        \"Enabled\": false\n    },\n    \"ObservabilityOptions\": {\n        \"InstrumentationName\": \"flight_service\",\n        \"OTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4317\"\n        },\n        \"AspireDashboardOTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4319\"\n        },\n        \"ZipkinOptions\": {\n            \"HttpExporterEndpoint\": \"http://localhost:9411/api/v2/spans\"\n        },\n        \"JaegerOptions\": {\n            \"OTLPGrpcExporterEndpoint\": \"http://localhost:14317\",\n            \"HttpExporterEndpoint\": \"http://localhost:14268/api/traces\"\n        },\n        \"UsePrometheusExporter\": true,\n        \"UseOTLPExporter\": true,\n        \"UseAspireOTLPExporter\": true,\n        \"UseGrafanaExporter\": false,\n        \"ServiceName\": \"Flight Service\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Flight/src/Flight.Api/appsettings.test.json",
    "content": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=flight_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"flight\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 2,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    }\n}\n"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/EndToEnd.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Flight.Api\\Flight.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/Fakes/FakeCreateFlightCommand.cs",
    "content": "using AutoBogus;\nusing Flight.Flights.Enums;\n\nnamespace EndToEnd.Test.Fakes;\n\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>\n{\n    public FakeCreateFlightCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightNumber, r => \"12FF\");\n        RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);\n        RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);\n        RuleFor(r => r.Status, _ => FlightStatus.Flying);\n        RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/Fakes/FakeCreateFlightMongoCommand.cs",
    "content": "namespace EndToEnd.Test.Fakes;\n\nusing AutoBogus;\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Enums;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateFlightMongoCommand : AutoFaker<CreateFlightMongo>\n{\n    public FakeCreateFlightMongoCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightNumber, r => \"12FF\");\n        RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);\n        RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);\n        RuleFor(r => r.Status, _ => FlightStatus.Flying);\n        RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);\n        RuleFor(r => r.IsDeleted, _ => false);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/Flight/Features/CreateFlightTests.cs",
    "content": "using System.Net;\nusing System.Net.Http.Json;\nusing BuildingBlocks.TestBase;\nusing EndToEnd.Test.Fakes;\nusing EndToEnd.Test.Routes;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Xunit;\n\nnamespace EndToEnd.Test.Flight.Features;\n\npublic class CreateFlightTests : FlightEndToEndTestBase\n{\n    public CreateFlightTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)\n    {\n    }\n\n\n    [Fact]\n    public async Task should_create_new_flight_to_db_and_publish_message_to_broker()\n    {\n        //Arrange\n        var command = new FakeCreateFlightCommand().Generate();\n\n        // Act\n        var route = ApiRoutes.Flight.CreateFlight;\n        var result = await Fixture.HttpClient.PostAsJsonAsync(route, command);\n\n        // Assert\n        result.StatusCode.Should().Be(HttpStatusCode.Created);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/Flight/Features/GetFlightByIdTests.cs",
    "content": "using System.Net;\nusing BuildingBlocks.TestBase;\nusing EndToEnd.Test.Fakes;\nusing EndToEnd.Test.Routes;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Xunit;\n\nnamespace EndToEnd.Test.Flight.Features;\n\npublic class GetFlightByIdTests : FlightEndToEndTestBase\n{\n    public GetFlightByIdTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)\n    {\n    }\n\n\n    [Fact]\n    public async Task should_retrive_a_flight_by_id_currectly()\n    {\n        //Arrange\n        var command = new FakeCreateFlightMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        // Act\n        var route = ApiRoutes.Flight.GetFlightById.Replace(ApiRoutes.Flight.Id, command.Id.ToString(), StringComparison.CurrentCulture);\n        var result = await Fixture.HttpClient.GetAsync(route);\n\n        // Assert\n        result.StatusCode.Should().Be(HttpStatusCode.OK);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/FlightEndToEndTestBase.cs",
    "content": "using BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing Xunit;\n\nnamespace EndToEnd.Test;\n\n[Collection(EndToEndTestCollection.Name)]\npublic class FlightEndToEndTestBase : TestBase<Program, FlightDbContext, FlightReadDbContext>\n{\n    public FlightEndToEndTestBase(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)\n    {\n    }\n}\n\n[CollectionDefinition(Name)]\npublic class EndToEndTestCollection : ICollectionFixture<TestFixture<Program, FlightDbContext, FlightReadDbContext>>\n{\n    public const string Name = \"Flight EndToEnd Test\";\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/FlightTestDataSeeder.cs",
    "content": "using BuildingBlocks.EFCore;\nusing Flight.Aircrafts.Models;\nusing Flight.Airports.Models;\nusing Flight.Data;\nusing Flight.Data.Seed;\nusing Flight.Flights.Models;\nusing Flight.Seats.Models;\nusing MapsterMapper;\nusing Microsoft.EntityFrameworkCore;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace EndToEnd.Test;\n\npublic class FlightTestDataSeeder(\n    FlightDbContext flightDbContext,\n    FlightReadDbContext flightReadDbContext,\n    IMapper mapper\n) : ITestDataSeeder\n{\n    public async Task SeedAllAsync()\n    {\n        await SeedAirportAsync();\n        await SeedAircraftAsync();\n        await SeedFlightAsync();\n        await SeedSeatAsync();\n    }\n\n    private async Task SeedAirportAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Airports))\n        {\n            await flightDbContext.Airports.AddRangeAsync(InitialData.Airports);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Airport.AsQueryable()))\n            {\n                await flightReadDbContext.Airport.InsertManyAsync(mapper.Map<List<AirportReadModel>>(InitialData.Airports));\n            }\n        }\n    }\n\n    private async Task SeedAircraftAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Aircraft))\n        {\n            await flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Aircraft.AsQueryable()))\n            {\n                await flightReadDbContext.Aircraft.InsertManyAsync(mapper.Map<List<AircraftReadModel>>(InitialData.Aircrafts));\n            }\n        }\n    }\n\n\n    private async Task SeedSeatAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Seats))\n        {\n            await flightDbContext.Seats.AddRangeAsync(InitialData.Seats);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Seat.AsQueryable()))\n            {\n                await flightReadDbContext.Seat.InsertManyAsync(mapper.Map<List<SeatReadModel>>(InitialData.Seats));\n            }\n        }\n    }\n\n    private async Task SeedFlightAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Flights))\n        {\n            await flightDbContext.Flights.AddRangeAsync(InitialData.Flights);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Flight.AsQueryable()))\n            {\n                await flightReadDbContext.Flight.InsertManyAsync(mapper.Map<List<FlightReadModel>>(InitialData.Flights));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/Routes/ApiRoutes.cs",
    "content": "namespace EndToEnd.Test.Routes;\n\npublic static class ApiRoutes\n{\n    private const string BaseApiPath = \"api/v1.0\";\n\n    public static class Flight\n    {\n        public const string Id = \"{id}\";\n        public const string GetFlightById = $\"{BaseApiPath}/flight/{Id}\";\n        public const string CreateFlight = $\"{BaseApiPath}/flight\";\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/EndToEndTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Aircraft/Features/CreateAircraftTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Aircraft.Features;\n\npublic class CreateAircraftTests : FlightIntegrationTestBase\n{\n    public CreateAircraftTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_create_new_aircraft_to_db_and_publish_message_to_broker()\n    {\n        // Arrange\n        var command = new FakeCreateAircraftCommand().Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response?.Id.Value.Should().Be(command.Id);\n\n        (await Fixture.WaitForPublishing<AircraftCreated>()).Should().Be(true);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Airport/Features/CreateAirportTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Airport.Features;\n\npublic class CreateAirportTests : FlightIntegrationTestBase\n{\n    public CreateAirportTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_create_new_airport_to_db_and_publish_message_to_broker()\n    {\n        // Arrange\n        var command = new FakeCreateAirportCommand().Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response?.Id.Should().Be(command.Id);\n\n        (await Fixture.WaitForPublishing<AirportCreated>()).Should().Be(true);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateAircraftCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Integration.Test.Fakes;\n\nusing global::Flight.Aircrafts.Features.CreatingAircraft.V1;\nusing MassTransit;\n\npublic class FakeCreateAircraftCommand : AutoFaker<CreateAircraft>\n{\n    public FakeCreateAircraftCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.ManufacturingYear, _ => 2000);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateAirportCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Integration.Test.Fakes;\n\nusing global::Flight.Airports.Features.CreatingAirport.V1;\nusing MassTransit;\n\npublic class FakeCreateAirportCommand : AutoFaker<CreateAirport>\n{\n    public FakeCreateAirportCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateFlightCommand.cs",
    "content": "using AutoBogus;\nusing Flight.Flights.Enums;\n\nnamespace Integration.Test.Fakes;\n\nusing System.Linq;\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>\n{\n    public FakeCreateFlightCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString());\n        RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);\n        RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);\n        RuleFor(r => r.Status, _ => FlightStatus.Flying);\n        RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateFlightMongoCommand.cs",
    "content": "namespace Integration.Test.Fakes;\n\nusing System.Linq;\nusing AutoBogus;\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Enums;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateFlightMongoCommand : AutoFaker<CreateFlightMongo>\n{\n    public FakeCreateFlightMongoCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightNumber, r => \"12FF\");\n        RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);\n        RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);\n        RuleFor(r => r.Status, _ => FlightStatus.Flying);\n        RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);\n        RuleFor(r => r.IsDeleted, _ => false);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateSeatCommand.cs",
    "content": "using AutoBogus;\nusing Flight.Seats.Enums;\n\nnamespace Integration.Test.Fakes;\n\nusing System;\nusing global::Flight.Seats.Features.CreatingSeat.V1;\nusing MassTransit;\n\npublic class FakeCreateSeatCommand : AutoFaker<CreateSeat>\n{\n    public FakeCreateSeatCommand(Guid flightId)\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightId, _ => flightId);\n        RuleFor(r => r.Class, _ => SeatClass.Economy);\n        RuleFor(r => r.Type, _ => SeatType.Middle);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeCreateSeatMongoCommand.cs",
    "content": "namespace Integration.Test.Fakes;\n\nusing System;\nusing AutoBogus;\nusing global::Flight.Seats.Enums;\nusing global::Flight.Seats.Features.CreatingSeat.V1;\nusing MassTransit;\n\npublic class FakeCreateSeatMongoCommand : AutoFaker<CreateSeatMongo>\n{\n    public FakeCreateSeatMongoCommand(Guid flightId)\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightId, _ => flightId);\n        RuleFor(r => r.Class, _ => SeatClass.Economy);\n        RuleFor(r => r.Type, _ => SeatType.Middle);\n        RuleFor(r => r.IsDeleted, _ => false);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Fakes/FakeUpdateFlightCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Integration.Test.Fakes;\n\nusing global::Flight.Flights.Features.UpdatingFlight.V1;\n\npublic class FakeUpdateFlightCommand : AutoFaker<UpdateFlight>\n{\n    public FakeUpdateFlightCommand(global::Flight.Flights.Models.Flight flight)\n    {\n        RuleFor(r => r.Id, _ => flight.Id);\n        RuleFor(r => r.DepartureAirportId, _ => flight.DepartureAirportId);\n        RuleFor(r => r.ArriveAirportId, _ => flight.ArriveAirportId);\n        RuleFor(r => r.AircraftId, _ => flight.AircraftId);\n        RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString());\n        RuleFor(r => r.Price, _ => 800);\n        RuleFor(r => r.Status, _ => flight.Status);\n        RuleFor(r => r.ArriveDate, _ => flight.ArriveDate);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Flight/Features/CreateFlightTests.cs",
    "content": "using BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Flight.Features;\n\npublic class CreateFlightTests : FlightIntegrationTestBase\n{\n    public CreateFlightTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_create_new_flight_to_db_and_publish_message_to_broker()\n    {\n        //Arrange\n        var command = new FakeCreateFlightCommand().Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response.Should().NotBeNull();\n        response?.Id.Should().Be(command.Id);\n\n        (await Fixture.WaitForPublishing<FlightCreated>()).Should().Be(true);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Flight/Features/DeleteFlightTests.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Microsoft.EntityFrameworkCore;\nusing Xunit;\n\nnamespace Integration.Test.Flight.Features;\n\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Features.DeletingFlight.V1;\nusing global::Flight.Flights.Models;\nusing global::Flight.Flights.ValueObjects;\n\npublic class DeleteFlightTests : FlightIntegrationTestBase\n{\n    public DeleteFlightTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_delete_flight_from_db()\n    {\n        // Arrange\n        var flightEntity = await Fixture.FindAsync<Flight, FlightId>(InitialData.Flights.First().Id);\n        var command = new DeleteFlight(flightEntity.Id.Value);\n\n        // Act\n        await Fixture.SendAsync(command);\n        var deletedFlight = (await Fixture.ExecuteDbContextAsync(db => db.Flights\n                .Where(x => x.Id == FlightId.Of(command.Id))\n                .IgnoreQueryFilters()\n                .ToListAsync())\n            ).FirstOrDefault();\n\n        // Assert\n        deletedFlight?.IsDeleted.Should().BeTrue();\n\n        (await Fixture.WaitForPublishing<FlightDeleted>()).Should().Be(true);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Flight/Features/GetAvailableFlightsTests.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Flight.Features;\n\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing global::Flight.Flights.Features.GettingAvailableFlights.V1;\n\npublic class GetAvailableFlightsTests : FlightIntegrationTestBase\n{\n    public GetAvailableFlightsTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_return_available_flights()\n    {\n        // Arrange\n        var command = new FakeCreateFlightMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        var query = new GetAvailableFlights();\n\n        // Act\n        var response = (await Fixture.SendAsync(query))?.FlightDtos?.ToList();\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.Count.Should().BeGreaterThanOrEqualTo(2);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Flight/Features/GetFlightByIdTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.TestBase;\nusing Flight;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Flight.Features;\n\nusing global::Flight.Flights.Features.GettingFlightById.V1;\n\npublic class GetFlightByIdTests : FlightIntegrationTestBase\n{\n    public GetFlightByIdTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_retrive_a_flight_by_id_currectly()\n    {\n        //Arrange\n        var command = new FakeCreateFlightMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        var query = new GetFlightById(command.Id);\n\n        // Act\n        var response = await Fixture.SendAsync(query);\n\n        // Assert\n        response.Should().NotBeNull();\n        response?.FlightDto?.Id.Should().Be(command.Id);\n    }\n\n    [Fact]\n    public async Task should_retrive_a_flight_by_id_from_grpc_service()\n    {\n        //Arrange\n        var command = new FakeCreateFlightMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);\n\n        // Act\n        var response = await flightGrpcClient.GetByIdAsync(new GetByIdRequest { Id = command.Id.ToString() }).ResponseAsync;\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.FlightDto.Id.Should().Be(command.Id.ToString());\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Flight/Features/UpdateFlightTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Flight.Features;\n\nusing System.Linq;\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Models;\nusing global::Flight.Flights.ValueObjects;\n\npublic class UpdateFlightTests : FlightIntegrationTestBase\n{\n    public UpdateFlightTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_update_flight_to_db_and_publish_message_to_broker()\n    {\n        // Arrange\n        var flightEntity = await Fixture.FindAsync<Flight, FlightId>(InitialData.Flights.First().Id);\n        var command = new FakeUpdateFlightCommand(flightEntity).Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response.Should().NotBeNull();\n        response?.Id.Should().Be(flightEntity.Id);\n\n        (await Fixture.WaitForPublishing<FlightUpdated>()).Should().Be(true);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/FlightIntegrationTestBase.cs",
    "content": "using BuildingBlocks.TestBase;\nusing Flight.Api;\nusing Flight.Data;\nusing Xunit;\n\nnamespace Integration.Test;\n\n[Collection(IntegrationTestCollection.Name)]\npublic class FlightIntegrationTestBase : TestBase<Program, FlightDbContext, FlightReadDbContext>\n{\n    public FlightIntegrationTestBase(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)\n    {\n    }\n}\n\n[CollectionDefinition(Name)]\npublic class IntegrationTestCollection : ICollectionFixture<TestFixture<Program, FlightDbContext, FlightReadDbContext>>\n{\n    public const string Name = \"Flight Integration Test\";\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/FlightTestDataSeeder.cs",
    "content": "using BuildingBlocks.EFCore;\nusing Flight.Aircrafts.Models;\nusing Flight.Airports.Models;\nusing Flight.Data;\nusing Flight.Data.Seed;\nusing Flight.Flights.Models;\nusing Flight.Seats.Models;\nusing MapsterMapper;\nusing Microsoft.EntityFrameworkCore;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace Integration.Test;\n\npublic class FlightTestDataSeeder(\n    FlightDbContext flightDbContext,\n    FlightReadDbContext flightReadDbContext,\n    IMapper mapper\n) : ITestDataSeeder\n{\n    public async Task SeedAllAsync()\n    {\n        await SeedAirportAsync();\n        await SeedAircraftAsync();\n        await SeedFlightAsync();\n        await SeedSeatAsync();\n    }\n\n    private async Task SeedAirportAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Airports))\n        {\n            await flightDbContext.Airports.AddRangeAsync(InitialData.Airports);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Airport.AsQueryable()))\n            {\n                await flightReadDbContext.Airport.InsertManyAsync(mapper.Map<List<AirportReadModel>>(InitialData.Airports));\n            }\n        }\n    }\n\n    private async Task SeedAircraftAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Aircraft))\n        {\n            await flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Aircraft.AsQueryable()))\n            {\n                await flightReadDbContext.Aircraft.InsertManyAsync(mapper.Map<List<AircraftReadModel>>(InitialData.Aircrafts));\n            }\n        }\n    }\n\n\n    private async Task SeedSeatAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Seats))\n        {\n            await flightDbContext.Seats.AddRangeAsync(InitialData.Seats);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Seat.AsQueryable()))\n            {\n                await flightReadDbContext.Seat.InsertManyAsync(mapper.Map<List<SeatReadModel>>(InitialData.Seats));\n            }\n        }\n    }\n\n    private async Task SeedFlightAsync()\n    {\n        if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Flights))\n        {\n            await flightDbContext.Flights.AddRangeAsync(InitialData.Flights);\n            await flightDbContext.SaveChangesAsync();\n\n            if (!await MongoQueryable.AnyAsync(flightReadDbContext.Flight.AsQueryable()))\n            {\n                await flightReadDbContext.Flight.InsertManyAsync(mapper.Map<List<FlightReadModel>>(InitialData.Flights));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Integration.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Flight.Api\\Flight.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Seat/Features/GetAvailableSeatsTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.TestBase;\nusing Flight;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Seat.Features;\n\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing global::Flight.Seats.Features.CreatingSeat.V1;\n\npublic class GetAvailableSeatsTests : FlightIntegrationTestBase\n{\n    public GetAvailableSeatsTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_return_available_seats_from_grpc_service()\n    {\n        // Arrange\n        var flightCommand = new FakeCreateFlightMongoCommand().Generate();\n\n        await Fixture.SendAsync(flightCommand);\n\n        var seatCommand = new FakeCreateSeatMongoCommand(flightCommand.Id).Generate();\n\n        await Fixture.SendAsync(seatCommand);\n\n        var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);\n\n        // Act\n        var response = await flightGrpcClient.GetAvailableSeatsAsync(new GetAvailableSeatsRequest { FlightId = flightCommand.Id.ToString() });\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.SeatDtos?.Count.Should().BeGreaterThanOrEqualTo(1);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/Seat/Features/ReserveSeatTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.TestBase;\nusing Flight;\nusing Flight.Api;\nusing Flight.Data;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Seat.Features;\n\npublic class ReserveSeatTests : FlightIntegrationTestBase\n{\n    public ReserveSeatTests(\n        TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_return_valid_reserve_seat_from_grpc_service()\n    {\n        // Arrange\n        var flightCommand = new FakeCreateFlightCommand().Generate();\n\n        await Fixture.SendAsync(flightCommand);\n\n        var seatCommand = new FakeCreateSeatCommand(flightCommand.Id).Generate();\n\n        await Fixture.SendAsync(seatCommand);\n\n        var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);\n\n        // Act\n        var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest()\n        {\n            FlightId = seatCommand.FlightId.ToString(),\n            SeatNumber = seatCommand.SeatNumber\n        });\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.Id.Should().Be(seatCommand?.Id.ToString());\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/IntegrationTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Flight/tests/PerformanceTest/.openapi-generator/FILES",
    "content": "README.md\nscript.js\n"
  },
  {
    "path": "src/Services/Flight/tests/PerformanceTest/.openapi-generator/VERSION",
    "content": "6.6.0-SNAPSHOT\n"
  },
  {
    "path": "src/Services/Flight/tests/PerformanceTest/.openapi-generator-ignore",
    "content": "# OpenAPI Generator Ignore\n# Generated by openapi-generator https://github.com/openapitools/openapi-generator\n\n# Use this file to prevent files from being overwritten by the generator.\n# The patterns follow closely to .gitignore or .dockerignore.\n\n# As an example, the C# client generator defines ApiClient.cs.\n# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:\n#ApiClient.cs\n\n# You can match any string of characters against a directory, file or extension with a single asterisk (*):\n#foo/*/qux\n# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux\n\n# You can recursively match patterns against a directory, file or extension with a double asterisk (**):\n#foo/**/qux\n# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux\n\n# You can also negate patterns with an exclamation (!).\n# For example, you can ignore all files in a docs folder with the file extension .md:\n#docs/*.md\n# Then explicitly reverse the ignore rule for a single file:\n#!docs/README.md\n"
  },
  {
    "path": "src/Services/Flight/tests/PerformanceTest/README.md",
    "content": "# Generated k6 script\n\nThe `script.js` file contains most of the Swagger/OpenAPI specification and you can customize it to your needs.\n\nGlobal header variables are defined at the top of the file, like `api_key`. Each path in the specification is converted into a [group](https://docs.k6.io/docs/tags-and-groups) in k6 and each group contains all the request methods related to that path. Path and query parameters are extracted from the specification and put at the start of the group. The URL is constructed from the base URL plus path and query.\n\nIf the Swagger/OpenAPI specification used as the input spec contains examples at parameter level, those will be extracted and utilized as parameter values. The `handleParamValue` custom Mustache lambda registered for use in the K6 `script.mustache` template handles the conditional checks, formatting, and outputting of parameter values. If a given parameter has value specified – either in `example` or `examples` field, defined at the parameter level – that value will be used. For list (`examples`), entire list will be output in the generated script and the first element from that list will be assigned as parameter value. If a given parameter does not have an example defined, a placeholder value with `TODO_EDIT_THE_` prefix will be generated for that parameter, and you will have to assign a value before you can run the script. In other words, you can now generate K6 test scripts which are ready to run, provided the Swagger/OpenAPI specification used as the input spec contains examples for all of the path/query parameters; see `modules/openapi-generator/src/test/resources/3_0/examples.yaml` for an example of such specification, and https://swagger.io/docs/specification/adding-examples/ for more information about adding examples.\n\nk6 specific parameters are in the [`params`](https://docs.k6.io/docs/params-k6http) object, and `body` contains the [request](https://docs.k6.io/docs/http-requests) body which is in the form of `identifier: type`, which the `type` should be substituted by a proper value. Then goes the request and the check.\n\n[Check](https://docs.k6.io/docs/checks) are like asserts but differ in that they don't halt execution, instead they just store the result of the check, pass or fail, and let the script execution continue.\n\nEach request is always followed by a 0.1 second [sleep](https://docs.k6.io/docs/sleep-t-1) to prevent the script execution from flooding the system with too many requests simultaneously.\n\nNote that the default iteration count and VU count is 1. So each request in each group will be executed once. For more information, see the [k6 options](https://docs.k6.io/docs/options).\n"
  },
  {
    "path": "src/Services/Flight/tests/PerformanceTest/script.js",
    "content": "/*\n * APIs\n * An example application with OpenAPI, Swashbuckle, and API versioning.\n *\n * OpenAPI spec version: 1.0\n * Contact:\n *\n * NOTE: This class is auto generated by OpenAPI Generator.\n * https://github.com/OpenAPITools/openapi-generator\n *\n * OpenAPI generator version: 6.6.0-SNAPSHOT\n */\n\n\nimport http from \"k6/http\";\nimport { group, check, sleep } from \"k6\";\n\nconst BASE_URL = \"/\";\n// Sleep duration between successive requests.\n// You might want to edit the value of this variable or remove calls to the sleep function on the script.\nconst SLEEP_DURATION = 0.1;\n// Global variables should be initialized.\n\nexport default function() {\n    group(\"/api/v1/flight/seat\", () => {\n\n        // Request No. 1: CreateSeat\n        {\n            let url = BASE_URL + `/api/v1/flight/seat`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"seatNumber\": \"string\", \"type\": \"seattype\", \"class\": \"seatclass\", \"flightId\": \"uuid\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/get-available-flights\", () => {\n\n        // Request No. 1: GetAvailableFlights\n        {\n            let url = BASE_URL + `/api/v1/flight/get-available-flights`;\n            let request = http.get(url);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/airport\", () => {\n\n        // Request No. 1: CreateAirport\n        {\n            let url = BASE_URL + `/api/v1/flight/airport`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"name\": \"string\", \"address\": \"string\", \"code\": \"string\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/get-available-seats/{id}\", () => {\n        let id = 'TODO_EDIT_THE_ID'; // specify value as there is no example value for this parameter in OpenAPI spec\n\n        // Request No. 1: GetAvailableSeats\n        {\n            let url = BASE_URL + `/api/v1/flight/get-available-seats/${id}`;\n            let request = http.get(url);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/flight\", () => {\n\n        // Request No. 1: UpdateFlight\n        {\n            let url = BASE_URL + `/api/v1/flight`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"id\": \"uuid\", \"flightNumber\": \"string\", \"aircraftId\": \"uuid\", \"departureAirportId\": \"uuid\", \"departureDate\": \"date\", \"arriveDate\": \"date\", \"arriveAirportId\": \"uuid\", \"durationMinutes\": \"double\", \"flightDate\": \"date\", \"status\": \"flightstatus\", \"price\": \"double\", \"isDeleted\": \"boolean\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/problem+json\"}};\n            let request = http.put(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 204\n            });\n\n            sleep(SLEEP_DURATION);\n        }\n\n        // Request No. 2: CreateFlight\n        {\n            let url = BASE_URL + `/api/v1/flight`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"flightNumber\": \"string\", \"aircraftId\": \"uuid\", \"departureAirportId\": \"uuid\", \"departureDate\": \"date\", \"arriveDate\": \"date\", \"arriveAirportId\": \"uuid\", \"durationMinutes\": \"double\", \"flightDate\": \"date\", \"status\": \"flightstatus\", \"price\": \"double\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 201\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/{id}\", () => {\n        let id = 'TODO_EDIT_THE_ID'; // specify value as there is no example value for this parameter in OpenAPI spec\n\n        // Request No. 1: GetFlightById\n        {\n            let url = BASE_URL + `/api/v1/flight/${id}`;\n            let request = http.get(url);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n\n            sleep(SLEEP_DURATION);\n        }\n\n        // Request No. 2: DeleteFlight\n        {\n            let url = BASE_URL + `/api/v1/flight/${id}`;\n            let request = http.del(url);\n\n            check(request, {\n                \"Success\": (r) => r.status === 204\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/reserve-seat\", () => {\n\n        // Request No. 1: ReserveSeat\n        {\n            let url = BASE_URL + `/api/v1/flight/reserve-seat`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"flightId\": \"uuid\", \"seatNumber\": \"string\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/flight/aircraft\", () => {\n\n        // Request No. 1: CreateAircraft\n        {\n            let url = BASE_URL + `/api/v1/flight/aircraft`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"name\": \"string\", \"model\": \"string\", \"manufacturingYear\": \"integer\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n}\n"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandHandlerTests.cs",
    "content": "using FluentAssertions;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Aircraft.Features.CreateAircraftTests;\n\nusing global::Flight.Aircrafts.Features.CreatingAircraft.V1;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateAircraftCommandHandlerTests\n{\n    private readonly UnitTestFixture _fixture;\n    private readonly CreateAircraftHandler _handler;\n\n    public Task<CreateAircraftResult> Act(CreateAircraft command, CancellationToken cancellationToken) =>\n    _handler.Handle(command, cancellationToken);\n\n    public CreateAircraftCommandHandlerTests(UnitTestFixture fixture)\n    {\n        _fixture = fixture;\n        _handler = new CreateAircraftHandler(_fixture.DbContext);\n    }\n\n    [Fact]\n    public async Task handler_with_valid_command_should_create_new_aircraft_and_return_currect_aircraft_dto()\n    {\n        // Arrange\n        var command = new FakeCreateAircraftCommand().Generate();\n\n        // Act\n        var response = await Act(command, CancellationToken.None);\n\n        // Assert\n        var entity = await _fixture.DbContext.Aircraft.FindAsync(response?.Id);\n\n        entity?.Should().NotBeNull();\n        response?.Id.Should().Be(entity.Id);\n    }\n\n    [Fact]\n    public async Task handler_with_null_command_should_throw_argument_exception()\n    {\n        // Arrange\n        CreateAircraft command = null;\n\n        // Act\n        Func<Task> act = async () => { await Act(command, CancellationToken.None); };\n\n        // Assert\n        await act.Should().ThrowAsync<ArgumentNullException>();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandValidatorTests.cs",
    "content": "using FluentAssertions;\nusing FluentValidation.TestHelper;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Aircraft.Features.CreateAircraftTests;\n\nusing global::Flight.Aircrafts.Features.CreatingAircraft.V1;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateAircraftCommandValidatorTests\n{\n    [Fact]\n    public void is_valid_should_be_false_when_have_invalid_parameter()\n    {\n        // Arrange\n        var command = new FakeValidateCreateAircraftCommand().Generate();\n        var validator = new CreateAircraftValidator();\n\n        // Act\n        var result = validator.TestValidate(command);\n\n        // Assert\n        result.IsValid.Should().BeFalse();\n        result.ShouldHaveValidationErrorFor(x => x.Model);\n        result.ShouldHaveValidationErrorFor(x => x.ManufacturingYear);\n        result.ShouldHaveValidationErrorFor(x => x.Name);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs",
    "content": "using FluentAssertions;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Airport.Features.CreateAirportTests;\n\nusing global::Flight.Airports.Features.CreatingAirport.V1;\nusing global::Flight.Airports.ValueObjects;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateAirportCommandHandlerTests\n{\n    private readonly UnitTestFixture _fixture;\n    private readonly CreateAirportHandler _handler;\n\n\n    public CreateAirportCommandHandlerTests(UnitTestFixture fixture)\n    {\n        _fixture = fixture;\n        _handler = new CreateAirportHandler(_fixture.DbContext);\n    }\n\n    public Task<CreateAirportResult> Act(CreateAirport command, CancellationToken cancellationToken) =>\n        _handler.Handle(command, cancellationToken);\n\n    [Fact]\n    public async Task handler_with_valid_command_should_create_new_airport_and_return_currect_airport_dto()\n    {\n        // Arrange\n        var command = new FakeCreateAirportCommand().Generate();\n\n        // Act\n        var response = await Act(command, CancellationToken.None);\n\n        // Assert\n        var entity = await _fixture.DbContext.Airports.FindAsync(AirportId.Of(response.Id));\n\n        entity?.Should().NotBeNull();\n        response?.Id.Should().Be(entity.Id);\n    }\n\n    [Fact]\n    public async Task handler_with_null_command_should_throw_argument_exception()\n    {\n        // Arrange\n        CreateAirport command = null;\n\n        // Act\n        var act = async () => { await Act(command, CancellationToken.None); };\n\n        // Assert\n        await act.Should().ThrowAsync<ArgumentNullException>();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandValidatorTests.cs",
    "content": "using FluentAssertions;\nusing FluentValidation.TestHelper;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Airport.Features.CreateAirportTests;\n\nusing global::Flight.Airports.Features.CreatingAirport.V1;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateAirportCommandValidatorTests\n{\n    [Fact]\n    public void is_valid_should_be_false_when_have_invalid_parameter()\n    {\n        // Arrange\n        var command = new FakeValidateCreateAirportCommand().Generate();\n        var validator = new CreateAirportValidator();\n\n        // Act\n        var result = validator.TestValidate(command);\n\n        // Assert\n        result.IsValid.Should().BeFalse();\n        result.ShouldHaveValidationErrorFor(x => x.Code);\n        result.ShouldHaveValidationErrorFor(x => x.Address);\n        result.ShouldHaveValidationErrorFor(x => x.Name);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs",
    "content": "using Flight.Data;\nusing Flight.Flights.Enums;\nusing Flight.Seats.Enums;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Unit.Test.Common;\n\nusing global::Flight.Aircrafts.ValueObjects;\nusing global::Flight.Airports.ValueObjects;\nusing global::Flight.Flights.ValueObjects;\nusing global::Flight.Seats.ValueObjects;\nusing MassTransit;\nusing AirportName = global::Flight.Airports.ValueObjects.Name;\nusing Name = global::Flight.Aircrafts.ValueObjects.Name;\n\npublic static class DbContextFactory\n{\n    private static readonly Guid _airportId1 = NewId.NextGuid();\n    private static readonly Guid _airportId2 = NewId.NextGuid();\n    private static readonly Guid _aircraft1 = NewId.NextGuid();\n    private static readonly Guid _aircraft2 = NewId.NextGuid();\n    private static readonly Guid _aircraft3 = NewId.NextGuid();\n    private static readonly Guid _flightId1 = NewId.NextGuid();\n\n    public static FlightDbContext Create()\n    {\n        var options = new DbContextOptionsBuilder<FlightDbContext>()\n            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options;\n\n        var context = new FlightDbContext(options, currentUserProvider: null, null);\n\n        // Seed our data\n        FlightDataSeeder(context);\n\n        return context;\n    }\n\n    private static void FlightDataSeeder(FlightDbContext context)\n    {\n        var airports = new List<global::Flight.Airports.Models.Airport>\n        {\n            global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId1), AirportName.Of(\"Lisbon International Airport\"), Address.Of(\"LIS\"),\n                Code.Of(\"12988\")),\n            global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId2), AirportName.Of(\"Sao Paulo International Airport\"), Address.Of(\"BRZ\"),\n                Code.Of(\"11200\"))\n        };\n\n        context.Airports.AddRange(airports);\n\n        var aircrafts = new List<global::Flight.Aircrafts.Models.Aircraft>\n        {\n            global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft1), Name.Of(\"Boeing 737\"), Model.Of(\"B737\"), ManufacturingYear.Of(2005)),\n            global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft2), Name.Of(\"Airbus 300\"), Model.Of(\"A300\"), ManufacturingYear.Of(2000)),\n            global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft3), Name.Of(\"Airbus 320\"), Model.Of(\"A320\"), ManufacturingYear.Of(2003))\n        };\n\n        context.Aircraft.AddRange(aircrafts);\n\n        var flights = new List<global::Flight.Flights.Models.Flight>\n        {\n            global::Flight.Flights.Models.Flight.Create(FlightId.Of(_flightId1), FlightNumber.Of( \"BD467\"), AircraftId.Of(_aircraft1), AirportId.Of( _airportId1),\n                DepartureDate.Of( new DateTime(2022, 1, 31, 12, 0, 0)),\n                ArriveDate.Of( new DateTime(2022, 1, 31, 14, 0, 0)),\n                AirportId.Of( _airportId2), DurationMinutes.Of(120m),\n                FlightDate.Of( new DateTime(2022, 1, 31)), FlightStatus.Completed,\n                Price.Of(8000))\n        };\n        context.Flights.AddRange(flights);\n\n        var seats = new List<global::Flight.Seats.Models.Seat>\n        {\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of( NewId.NextGuid()), SeatNumber.Of(\"12A\"), SeatType.Window, SeatClass.Economy,\n                FlightId.Of(_flightId1)),\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12B\"), SeatType.Window, SeatClass.Economy,\n                FlightId.Of(_flightId1)),\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12C\"), SeatType.Middle, SeatClass.Economy,\n                FlightId.Of(_flightId1)),\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12D\"), SeatType.Middle, SeatClass.Economy,\n                FlightId.Of(_flightId1)),\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12E\"), SeatType.Aisle, SeatClass.Economy,\n                FlightId.Of(_flightId1)),\n            global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of(\"12F\"), SeatType.Aisle, SeatClass.Economy,\n                FlightId.Of(_flightId1))\n        };\n\n        context.Seats.AddRange(seats);\n\n        context.SaveChanges();\n    }\n\n    public static void Destroy(FlightDbContext context)\n    {\n        context.Database.EnsureDeleted();\n        context.Dispose();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Common/MapperFactory.cs",
    "content": "using Flight;\nusing Mapster;\nusing MapsterMapper;\n\nnamespace Unit.Test.Common\n{\n    public static class MapperFactory\n    {\n        public static IMapper Create()\n        {\n            var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;\n            typeAdapterConfig.Scan(typeof(FlightRoot).Assembly);\n            IMapper instance = new Mapper(typeAdapterConfig);\n\n            return instance;\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Common/UnitTestFixture.cs",
    "content": "using Flight.Data;\nusing MapsterMapper;\nusing Xunit;\n\nnamespace Unit.Test.Common\n{\n    [CollectionDefinition(nameof(UnitTestFixture))]\n    public class FixtureCollection : ICollectionFixture<UnitTestFixture> { }\n\n    public class UnitTestFixture : IDisposable\n    {\n        public UnitTestFixture()\n        {\n            Mapper = MapperFactory.Create();\n            DbContext = DbContextFactory.Create();\n        }\n\n        public IMapper Mapper { get; }\n        public FlightDbContext DbContext { get; }\n\n        public void Dispose()\n        {\n            DbContextFactory.Destroy(DbContext);\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAircraftCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Unit.Test.Fakes;\n\nusing global::Flight.Aircrafts.Features.CreatingAircraft.V1;\nusing MassTransit;\n\npublic class FakeCreateAircraftCommand : AutoFaker<CreateAircraft>\n{\n    public FakeCreateAircraftCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.ManufacturingYear, _ => 2000);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAirportCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Unit.Test.Fakes;\n\nusing global::Flight.Airports.Features.CreatingAirport.V1;\nusing MassTransit;\n\npublic class FakeCreateAirportCommand : AutoFaker<CreateAirport>\n{\n    public FakeCreateAirportCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeCreateFlightCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Unit.Test.Fakes;\n\nusing System.Linq;\nusing global::Flight.Data.Seed;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing MassTransit;\n\npublic sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>\n{\n    public FakeCreateFlightCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString());\n        RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);\n        RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);\n        RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeCreateSeatCommand.cs",
    "content": "using AutoBogus;\nusing Flight.Seats.Enums;\n\nnamespace Unit.Test.Fakes;\n\nusing System.Linq;\nusing global::Flight.Data.Seed;\nusing global::Flight.Seats.Features.CreatingSeat.V1;\nusing MassTransit;\n\npublic class FakeCreateSeatCommand : AutoFaker<CreateSeat>\n{\n    public FakeCreateSeatCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.FlightId, _ => InitialData.Flights.First().Id);\n        RuleFor(r => r.SeatNumber, _ => \"F99\");\n        RuleFor(r => r.Type, _ => SeatType.Window);\n        RuleFor(r => r.Class, _ => SeatClass.Economy);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs",
    "content": "namespace Unit.Test.Fakes;\n\nusing global::Flight.Aircrafts.ValueObjects;\nusing global::Flight.Airports.ValueObjects;\nusing global::Flight.Flights.ValueObjects;\n\npublic static class FakeFlightCreate\n{\n    public static global::Flight.Flights.Models.Flight Generate()\n    {\n        var command = new FakeCreateFlightCommand().Generate();\n\n        return global::Flight.Flights.Models.Flight.Create(FlightId.Of(command.Id), FlightNumber.Of(command.FlightNumber),\n            AircraftId.Of(command.AircraftId), AirportId.Of(command.DepartureAirportId), DepartureDate.Of(command.DepartureDate),\n            ArriveDate.Of(command.ArriveDate), AirportId.Of(command.ArriveAirportId), DurationMinutes.Of(command.DurationMinutes),\n            FlightDate.Of(command.FlightDate), command.Status, Price.Of(command.Price));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeFlightUpdate.cs",
    "content": "namespace Unit.Test.Fakes;\n\nusing global::Flight.Flights.Models;\nusing global::Flight.Flights.ValueObjects;\n\npublic static class FakeFlightUpdate\n{\n    public static void Generate(Flight flight)\n    {\n        flight.Update(flight.Id, flight.FlightNumber, flight.AircraftId, flight.DepartureAirportId, flight.DepartureDate,\n            flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, Price.Of(1000), flight.IsDeleted);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeValidateCreateAircraftCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Unit.Test.Fakes;\n\nusing global::Flight.Aircrafts.Features.CreatingAircraft.V1;\n\npublic class FakeValidateCreateAircraftCommand : AutoFaker<CreateAircraft>\n{\n    public FakeValidateCreateAircraftCommand()\n    {\n        RuleFor(r => r.ManufacturingYear, _ => 0);\n        RuleFor(r => r.Name, _ => null);\n        RuleFor(r => r.Model, _ => null);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeValidateCreateAirportCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Unit.Test.Fakes;\n\nusing global::Flight.Airports.Features.CreatingAirport.V1;\n\npublic class FakeValidateCreateAirportCommand : AutoFaker<CreateAirport>\n{\n    public FakeValidateCreateAirportCommand()\n    {\n        RuleFor(r => r.Code, _ => null);\n        RuleFor(r => r.Name, _ => null);\n        RuleFor(r => r.Address, _ => null);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeValidateCreateFlightCommand.cs",
    "content": "using System;\nusing AutoBogus;\nusing Flight.Flights.Enums;\n\nnamespace Unit.Test.Fakes;\n\nusing global::Flight.Flights.Features.CreatingFlight.V1;\n\npublic class FakeValidateCreateFlightCommand : AutoFaker<CreateFlight>\n{\n    public FakeValidateCreateFlightCommand()\n    {\n        RuleFor(r => r.Price, _ => -10);\n        RuleFor(r => r.Status, _ => (FlightStatus)10);\n        RuleFor(r => r.AircraftId, _ => Guid.Empty);\n        RuleFor(r => r.DepartureAirportId, _ => Guid.Empty);\n        RuleFor(r => r.ArriveAirportId, _ => Guid.Empty);\n        RuleFor(r => r.DurationMinutes, _ => 0);\n        RuleFor(r => r.FlightDate, _ => new DateTime());\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Fakes/FakeValidateCreateSeatCommand.cs",
    "content": "using AutoBogus;\nusing Flight.Seats.Enums;\n\nnamespace Unit.Test.Fakes;\n\nusing System;\nusing global::Flight.Seats.Features.CreatingSeat.V1;\n\npublic class FakeValidateCreateSeatCommand : AutoFaker<CreateSeat>\n{\n    public FakeValidateCreateSeatCommand()\n    {\n        RuleFor(r => r.SeatNumber, _ => null);\n        RuleFor(r => r.FlightId, _ => Guid.Empty);\n        RuleFor(r => r.Class, _ => (SeatClass)10);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Flight/Features/Domains/CreateFlightTests.cs",
    "content": "namespace Unit.Test.Flight.Features.Domains\n{\n    using System.Linq;\n    using FluentAssertions;\n    using global::Flight.Flights.Features.CreatingFlight.V1;\n    using Unit.Test.Common;\n    using Unit.Test.Fakes;\n    using Xunit;\n\n    [Collection(nameof(UnitTestFixture))]\n    public class CreateFlightTests\n    {\n        [Fact]\n        public void can_create_valid_flight()\n        {\n            // Arrange + Act\n            var fakeFlight = FakeFlightCreate.Generate();\n\n            // Assert\n            fakeFlight.Should().NotBeNull();\n        }\n\n        [Fact]\n        public void queue_domain_event_on_create()\n        {\n            // Arrange + Act\n            var fakeFlight = FakeFlightCreate.Generate();\n\n            // Assert\n            fakeFlight.DomainEvents.Count.Should().Be(1);\n            fakeFlight.DomainEvents.FirstOrDefault().Should().BeOfType(typeof(FlightCreatedDomainEvent));\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Flight/Features/Domains/UpdateFlightTests.cs",
    "content": "namespace Unit.Test.Flight.Features.Domains;\n\nusing System.Linq;\nusing FluentAssertions;\nusing global::Flight.Flights.Features.UpdatingFlight.V1;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\n[Collection(nameof(UnitTestFixture))]\npublic class UpdateFlightTests\n{\n    [Fact]\n    public void can_update_valid_flight()\n    {\n        // Arrange\n        var fakeFlight = FakeFlightCreate.Generate();\n\n        // Act\n        FakeFlightUpdate.Generate(fakeFlight);\n\n        // Assert\n        fakeFlight.Price.Value.Should().Be(1000);\n    }\n\n    [Fact]\n    public void queue_domain_event_on_update()\n    {\n        // Arrange\n        var fakeFlight = FakeFlightCreate.Generate();\n        fakeFlight.ClearDomainEvents();\n\n        // Act\n        FakeFlightUpdate.Generate(fakeFlight);\n\n        // Assert\n        fakeFlight.DomainEvents.Count.Should().Be(1);\n        fakeFlight.DomainEvents.FirstOrDefault().Should().BeOfType(typeof(FlightUpdatedDomainEvent));\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs",
    "content": "namespace Unit.Test.Flight.Features.Handlers.CreateFlight;\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing FluentAssertions;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing global::Flight.Flights.ValueObjects;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateFlightCommandHandlerTests\n{\n    private readonly UnitTestFixture _fixture;\n    private readonly CreateFlightHandler _handler;\n\n    public Task<CreateFlightResult> Act(CreateFlight command, CancellationToken cancellationToken) =>\n        _handler.Handle(command, cancellationToken);\n\n    public CreateFlightCommandHandlerTests(UnitTestFixture fixture)\n    {\n        _fixture = fixture;\n        _handler = new CreateFlightHandler(fixture.DbContext);\n    }\n\n    [Fact]\n    public async Task handler_with_valid_command_should_create_new_flight_and_return_currect_flight_dto()\n    {\n        // Arrange\n        var command = new FakeCreateFlightCommand().Generate();\n\n        // Act\n        var response = await Act(command, CancellationToken.None);\n\n        // Assert\n        var entity = await _fixture.DbContext.Flights.FindAsync(FlightId.Of(response.Id));\n\n        entity?.Should().NotBeNull();\n        response?.Id.Should().Be(entity.Id);\n    }\n\n    [Fact]\n    public async Task handler_with_null_command_should_throw_argument_exception()\n    {\n        // Arrange\n        CreateFlight command = null;\n\n        // Act\n        Func<Task> act = async () => { await Act(command, CancellationToken.None); };\n\n        // Assert\n        await act.Should().ThrowAsync<ArgumentNullException>();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandValidatorTests.cs",
    "content": "namespace Unit.Test.Flight.Features.Handlers.CreateFlight;\n\nusing FluentAssertions;\nusing FluentValidation.TestHelper;\nusing global::Flight.Flights.Features.CreatingFlight.V1;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateFlightCommandValidatorTests\n{\n    [Fact]\n    public void is_valid_should_be_false_when_have_invalid_parameter()\n    {\n        // Arrange\n        var command = new FakeValidateCreateFlightCommand().Generate();\n        var validator = new CreateFlightValidator();\n\n        // Act\n        var result = validator.TestValidate(command);\n\n        // Assert\n        result.IsValid.Should().BeFalse();\n        result.ShouldHaveValidationErrorFor(x => x.Price);\n        result.ShouldHaveValidationErrorFor(x => x.Status);\n        result.ShouldHaveValidationErrorFor(x => x.AircraftId);\n        result.ShouldHaveValidationErrorFor(x => x.DepartureAirportId);\n        result.ShouldHaveValidationErrorFor(x => x.ArriveAirportId);\n        result.ShouldHaveValidationErrorFor(x => x.DurationMinutes);\n        result.ShouldHaveValidationErrorFor(x => x.FlightDate);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Flight/FlightMappingTests.cs",
    "content": "using Flight.Flights.Dtos;\nusing MapsterMapper;\nusing Unit.Test.Common;\nusing Xunit;\n\nnamespace Unit.Test.Flight;\n\n[Collection(nameof(UnitTestFixture))]\npublic class FlightMappingTests\n{\n    private readonly IMapper _mapper;\n\n    public FlightMappingTests(UnitTestFixture fixture)\n    {\n        _mapper = fixture.Mapper;\n    }\n\n    public static IEnumerable<object[]> Data\n    {\n        get\n        {\n            yield return new object[]\n            {\n                // these types will instantiate with reflection in the future\n                typeof(global::Flight.Flights.Models.FlightReadModel), typeof(FlightDto)\n            };\n        }\n    }\n\n    [Theory]\n    [MemberData(nameof(Data))]\n    public void should_support_mapping_from_source_to_destination(Type source, Type destination,\n        params object[] parameters)\n    {\n        var instance = Activator.CreateInstance(source, parameters);\n\n        _mapper.Map(instance, source, destination);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandHandlerTests.cs",
    "content": "using FluentAssertions;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Seat.Features;\n\nusing global::Flight.Seats.Features.CreatingSeat.V1;\nusing global::Flight.Seats.ValueObjects;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateSeatCommandHandlerTests\n{\n    private readonly UnitTestFixture _fixture;\n    private readonly CreateSeatCommandHandler _handler;\n\n\n    public CreateSeatCommandHandlerTests(UnitTestFixture fixture)\n    {\n        _fixture = fixture;\n        _handler = new CreateSeatCommandHandler(_fixture.DbContext);\n    }\n\n    public Task<CreateSeatResult> Act(CreateSeat command, CancellationToken cancellationToken)\n    {\n        return _handler.Handle(command, cancellationToken);\n    }\n\n    [Fact]\n    public async Task handler_with_valid_command_should_create_new_seat_and_return_currect_seat_dto()\n    {\n        // Arrange\n        var command = new FakeCreateSeatCommand().Generate();\n\n        // Act\n        var response = await Act(command, CancellationToken.None);\n\n        // Assert\n        var entity = await _fixture.DbContext.Seats.FindAsync(SeatId.Of(response.Id));\n\n        entity?.Should().NotBeNull();\n        response?.Id.Should().Be(entity.Id);\n    }\n\n    [Fact]\n    public async Task handler_with_null_command_should_throw_argument_exception()\n    {\n        // Arrange\n        CreateSeat command = null;\n\n        // Act\n        var act = async () => { await Act(command, CancellationToken.None); };\n\n        // Assert\n        await act.Should().ThrowAsync<ArgumentNullException>();\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandValidatorTests.cs",
    "content": "using FluentAssertions;\nusing FluentValidation.TestHelper;\nusing Unit.Test.Common;\nusing Unit.Test.Fakes;\nusing Xunit;\n\nnamespace Unit.Test.Seat.Features;\n\nusing global::Flight.Seats.Features.CreatingSeat.V1;\n\n[Collection(nameof(UnitTestFixture))]\npublic class CreateSeatCommandValidatorTests\n{\n    [Fact]\n    public void is_valid_should_be_false_when_have_invalid_parameter()\n    {\n        // Arrange\n        var command = new FakeValidateCreateSeatCommand().Generate();\n        var validator = new CreateSeatValidator();\n\n        // Act\n        var result = validator.TestValidate(command);\n\n        // Assert\n        result.IsValid.Should().BeFalse();\n        result.ShouldHaveValidationErrorFor(x => x.SeatNumber);\n        result.ShouldHaveValidationErrorFor(x => x.FlightId);\n        result.ShouldHaveValidationErrorFor(x => x.Class);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs",
    "content": "using Flight.Seats.Dtos;\nusing MapsterMapper;\nusing Unit.Test.Common;\nusing Xunit;\n\nnamespace Unit.Test.Seat;\n\n[Collection(nameof(UnitTestFixture))]\npublic class SeatMappingTests\n{\n    private readonly UnitTestFixture _fixture;\n    private readonly IMapper _mapper;\n\n    public SeatMappingTests(UnitTestFixture fixture)\n    {\n        _mapper = fixture.Mapper;\n    }\n\n    public static IEnumerable<object[]> Data\n    {\n        get\n        {\n            yield return new object[]\n            {\n                // these types will instantiate with reflection in the future\n                typeof(global::Flight.Seats.Models.SeatReadModel), typeof(SeatDto)\n            };\n        }\n    }\n\n\n    [Theory]\n    [MemberData(nameof(Data))]\n    public void should_support_mapping_from_source_to_destination(Type source, Type destination, params object[] parameters)\n    {\n        var instance = Activator.CreateInstance(source, parameters);\n\n        _mapper.Map(instance, source, destination);\n    }\n}"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/Unit.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Flight.Api\\Flight.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Flight/tests/UnitTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Flight/tests/tests.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"EndToEnd.Test\", \"EndToEndTest\\EndToEnd.Test.csproj\", \"{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"IntegrationTest\\Integration.Test.csproj\", \"{815ED633-1B3E-4F1A-B5FB-A674AB326150}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Unit.Test\", \"UnitTest\\Unit.Test.csproj\", \"{7472C957-FA4A-48E1-87DE-474216B35F87}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{815ED633-1B3E-4F1A-B5FB-A674AB326150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{815ED633-1B3E-4F1A-B5FB-A674AB326150}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{815ED633-1B3E-4F1A-B5FB-A674AB326150}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{815ED633-1B3E-4F1A-B5FB-A674AB326150}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{7472C957-FA4A-48E1-87DE-474216B35F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7472C957-FA4A-48E1-87DE-474216B35F87}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7472C957-FA4A-48E1-87DE-474216B35F87}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7472C957-FA4A-48E1-87DE-474216B35F87}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Services/Identity/Dockerfile",
    "content": "# ---------- Build Stage ----------\nFROM mcr.microsoft.com/dotnet/sdk:10.0 AS build\nWORKDIR /src\n\n# Copy solution-level files\nCOPY .editorconfig .\nCOPY global.json .\nCOPY Directory.Build.props .\n\n# Copy project files first (for better Docker layer caching)\nCOPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/\nCOPY src/Services/Identity/src/Identity/Identity.csproj src/Services/Identity/src/Identity/\nCOPY src/Services/Identity/src/Identity.Api/Identity.Api.csproj src/Services/Identity/src/Identity.Api/\nCOPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/\n\n# Restore dependencies\nRUN dotnet restore src/Services/Identity/src/Identity.Api/Identity.Api.csproj\n\n# Copy remaining source code\nCOPY src ./src\n\n# Publish (build included, no separate build step needed)\nRUN dotnet publish src/Services/Identity/src/Identity.Api/Identity.Api.csproj \\\n    -c Release \\\n    -o /app/publish \\\n    --no-restore\n\n# ---------- Runtime Stage ----------\nFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime\nWORKDIR /app\n\nCOPY --from=build /app/publish .\n\nENV ASPNETCORE_URLS=http://+:80\nENV ASPNETCORE_ENVIRONMENT=docker\n\nEXPOSE 80\n\nENTRYPOINT [\"dotnet\", \"Identity.Api.dll\"]"
  },
  {
    "path": "src/Services/Identity/src/Identity/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Unit.Test\")]\n[assembly: InternalsVisibleTo(\"Integration.Test\")]\n[assembly: InternalsVisibleTo(\"EndToEnd.Test\")]"
  },
  {
    "path": "src/Services/Identity/src/Identity/Configurations/AuthOptions.cs",
    "content": "namespace Identity.Configurations;\n\npublic class AuthOptions\n{\n    public string IssuerUri { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Configurations/Config.cs",
    "content": "using Duende.IdentityServer;\nusing Duende.IdentityServer.Models;\nusing Identity.Identity.Constants;\nusing IdentityModel;\n\nnamespace Identity.Configurations;\n\npublic static class Config\n{\n    public static IEnumerable<IdentityResource> IdentityResources =>\n        new List<IdentityResource>\n        {\n            new IdentityResources.OpenId(),\n            new IdentityResources.Profile(),\n            new IdentityResources.Email()\n        };\n\n\n    public static IEnumerable<ApiScope> ApiScopes =>\n        new List<ApiScope>\n        {\n            new(Constants.StandardScopes.FlightApi),\n            new(Constants.StandardScopes.PassengerApi),\n            new(Constants.StandardScopes.BookingApi),\n            new(Constants.StandardScopes.IdentityApi),\n            new(JwtClaimTypes.Role, new List<string> {\"role\"})\n        };\n\n\n    public static IList<ApiResource> ApiResources =>\n        new List<ApiResource>\n        {\n            new(Constants.StandardScopes.FlightApi)\n            {\n                Scopes = { Constants.StandardScopes.FlightApi }\n            },\n            new(Constants.StandardScopes.PassengerApi)\n            {\n                Scopes = { Constants.StandardScopes.PassengerApi }\n            },\n            new(Constants.StandardScopes.BookingApi)\n            {\n                Scopes = { Constants.StandardScopes.BookingApi }\n            },\n            new(Constants.StandardScopes.IdentityApi)\n            {\n                Scopes = { Constants.StandardScopes.IdentityApi }\n            },\n        };\n\n    public static IEnumerable<Client> Clients =>\n        new List<Client>\n        {\n            new()\n            {\n                ClientId = \"client\",\n                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,\n                ClientSecrets =\n                {\n                    new Secret(\"secret\".Sha256())\n                },\n                AllowedScopes =\n                {\n                    IdentityServerConstants.StandardScopes.OpenId,\n                    IdentityServerConstants.StandardScopes.Profile,\n                    JwtClaimTypes.Role, // Include roles scope\n                    Constants.StandardScopes.FlightApi,\n                    Constants.StandardScopes.PassengerApi,\n                    Constants.StandardScopes.BookingApi,\n                    Constants.StandardScopes.IdentityApi,\n                },\n                AccessTokenLifetime = 3600,  // authorize the client to access protected resources\n                IdentityTokenLifetime = 3600, // authenticate the user,\n                AlwaysIncludeUserClaimsInIdToken = true // Include claims in ID token\n            }\n        };\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Configurations/UserValidator.cs",
    "content": "namespace Identity.Configurations;\n\nusing System.Security.Claims;\nusing System.Threading.Tasks;\nusing Duende.IdentityServer.Models;\nusing Duende.IdentityServer.Validation;\nusing Identity.Models;\nusing Microsoft.AspNetCore.Identity;\n\npublic class UserValidator : IResourceOwnerPasswordValidator\n{\n    private readonly SignInManager<User> _signInManager;\n    private readonly UserManager<User> _userManager;\n\n    public UserValidator(SignInManager<User> signInManager,\n        UserManager<User> userManager)\n    {\n        _signInManager = signInManager;\n        _userManager = userManager;\n    }\n\n    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)\n    {\n        var user = await _userManager.FindByNameAsync(context.UserName);\n\n        var signIn = await _signInManager.PasswordSignInAsync(\n            user,\n            context.Password,\n            isPersistent: true,\n            lockoutOnFailure: true);\n\n        if (signIn.Succeeded)\n        {\n            var userId = user!.Id.ToString();\n\n            // context set to success\n            context.Result = new GrantValidationResult(\n                subject: userId,\n                authenticationMethod: \"custom\",\n                claims: new Claim[]\n                {\n                    new Claim(ClaimTypes.NameIdentifier, userId),\n                    new Claim(ClaimTypes.Name, user.UserName)\n                }\n            );\n\n            return;\n        }\n\n        // context set to Failure\n        context.Result = new GrantValidationResult(\n            TokenRequestErrors.UnauthorizedClient, \"Invalid Credentials\");\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/RoleClaimConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class RoleClaimConfiguration : IEntityTypeConfiguration<RoleClaim>\n{\n    public void Configure(EntityTypeBuilder<RoleClaim> builder)\n    {\n        builder.ToTable(nameof(RoleClaim));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/RoleConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class RoleConfiguration : IEntityTypeConfiguration<Role>\n{\n    public void Configure(EntityTypeBuilder<Role> builder)\n    {\n        builder.ToTable(nameof(Role));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/UserClaimConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class UserClaimConfiguration : IEntityTypeConfiguration<UserClaim>\n{\n    public void Configure(EntityTypeBuilder<UserClaim> builder)\n    {\n        builder.ToTable(nameof(UserClaim));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/UserConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class UserConfiguration : IEntityTypeConfiguration<User>\n{\n    public void Configure(EntityTypeBuilder<User> builder)\n    {\n        builder.ToTable(nameof(User));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/UserLoginConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class UserLoginConfiguration : IEntityTypeConfiguration<UserLogin>\n{\n    public void Configure(EntityTypeBuilder<UserLogin> builder)\n    {\n        builder.ToTable(nameof(UserLogin));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/UserRoleConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>\n{\n    public void Configure(EntityTypeBuilder<UserRole> builder)\n    {\n        builder.ToTable(nameof(UserRole));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Configurations/UserTokenConfiguration.cs",
    "content": "namespace Identity.Data.Configurations;\n\nusing Identity.Models;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\npublic class UserTokenConfiguration : IEntityTypeConfiguration<UserToken>\n{\n    public void Configure(EntityTypeBuilder<UserToken> builder)\n    {\n        builder.ToTable(nameof(UserToken));\n\n        // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api\n        builder.Property(r => r.Version).IsConcurrencyToken();\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/DesignTimeDbContextFactory.cs",
    "content": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Design;\n\nnamespace Identity.Data;\n\npublic class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<IdentityContext>\n{\n    public IdentityContext CreateDbContext(string[] args)\n    {\n        var builder = new DbContextOptionsBuilder<IdentityContext>();\n\n        builder.UseNpgsql(\"Server=localhost;Port=5432;Database=identity;User Id=postgres;Password=postgres;Include Error Detail=true\")\n            .UseSnakeCaseNamingConvention();\n        return new IdentityContext(builder.Options);\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/IdentityContext.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Data;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Core.Model;\nusing BuildingBlocks.EFCore;\nusing Identity.Identity.Models;\nusing Microsoft.AspNetCore.Identity.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Identity.Data;\n\nusing System;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.Logging;\n\npublic sealed class IdentityContext : IdentityDbContext<User, Role, Guid,\n    UserClaim, UserRole, UserLogin, RoleClaim, UserToken>, IDbContext\n{\n    private readonly ILogger<IdentityContext>? _logger;\n    private IDbContextTransaction _currentTransaction;\n\n    public IdentityContext(DbContextOptions<IdentityContext> options, ILogger<IdentityContext>? logger = null) : base(options)\n    {\n        _logger = logger;\n    }\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());\n        base.OnModelCreating(builder);\n        builder.FilterSoftDeletedProperties();\n        builder.ToSnakeCaseTables();\n    }\n\n    public IExecutionStrategy CreateExecutionStrategy() => Database.CreateExecutionStrategy();\n\n    public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        if (_currentTransaction != null)\n            return;\n\n        _currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken);\n    }\n\n    public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            await SaveChangesAsync(cancellationToken);\n            await _currentTransaction?.CommitAsync(cancellationToken)!;\n        }\n        catch\n        {\n            await RollbackTransactionAsync(cancellationToken);\n            throw;\n        }\n        finally\n        {\n            _currentTransaction?.Dispose();\n            _currentTransaction = null;\n        }\n    }\n\n    public async Task RollbackTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            await _currentTransaction?.RollbackAsync(cancellationToken)!;\n        }\n        finally\n        {\n            _currentTransaction?.Dispose();\n            _currentTransaction = null;\n        }\n    }\n\n    //ref: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency#execution-strategies-and-transactions\n    public Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default)\n    {\n        var strategy = CreateExecutionStrategy();\n        return strategy.ExecuteAsync(async () =>\n        {\n            await using var transaction =\n                await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken);\n            try\n            {\n                await SaveChangesAsync(cancellationToken);\n                await transaction.CommitAsync(cancellationToken);\n            }\n            catch\n            {\n                await transaction.RollbackAsync(cancellationToken);\n                throw;\n            }\n        });\n    }\n\n    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)\n    {\n        OnBeforeSaving();\n        try\n        {\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n        //ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=data-annotations#resolving-concurrency-conflicts\n        catch (DbUpdateConcurrencyException ex)\n        {\n            foreach (var entry in ex.Entries)\n            {\n                var databaseValues = await entry.GetDatabaseValuesAsync(cancellationToken);\n\n                if (databaseValues == null)\n                {\n                    _logger.LogError(\"The record no longer exists in the database, The record has been deleted by another user.\");\n                    throw;\n                }\n\n                // Refresh the original values to bypass next concurrency check\n                entry.OriginalValues.SetValues(databaseValues);\n            }\n\n            return await base.SaveChangesAsync(cancellationToken);\n        }\n    }\n\n    public IReadOnlyList<IDomainEvent> GetDomainEvents()\n    {\n        var domainEntities = ChangeTracker\n            .Entries<IAggregate>()\n            .Where(x => x.Entity.DomainEvents.Any())\n            .Select(x => x.Entity)\n            .ToList();\n\n        var domainEvents = domainEntities\n            .SelectMany(x => x.DomainEvents)\n            .ToImmutableList();\n\n        domainEntities.ForEach(entity => entity.ClearDomainEvents());\n\n        return domainEvents.ToImmutableList();\n    }\n\n    private void OnBeforeSaving()\n    {\n        try\n        {\n            foreach (var entry in ChangeTracker.Entries<IVersion>())\n            {\n                switch (entry.State)\n                {\n                    case EntityState.Modified:\n                        entry.Entity.Version++;\n                        break;\n\n                    case EntityState.Deleted:\n                        entry.Entity.Version++;\n                        break;\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new Exception(\"try for find IVersion\", ex);\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Migrations/20230331193410_initial.Designer.cs",
    "content": "// <auto-generated />\nusing System;\nusing Identity.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Migrations;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\n\n#nullable disable\n\nnamespace Identity.Data.Migrations\n{\n    [DbContext(typeof(IdentityContext))]\n    [Migration(\"20230331193410_initial\")]\n    partial class initial\n    {\n        /// <inheritdoc />\n        protected override void BuildTargetModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"7.0.2\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Identity.Identity.Models.Role\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<string>(\"ConcurrencyStamp\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"concurrency_stamp\");\n\n                    b.Property<string>(\"Name\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"name\");\n\n                    b.Property<string>(\"NormalizedName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_name\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_roles\");\n\n                    b.HasIndex(\"NormalizedName\")\n                        .IsUnique()\n                        .HasDatabaseName(\"RoleNameIndex\");\n\n                    b.ToTable(\"asp_net_roles\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.RoleClaim\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"id\");\n\n                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>(\"Id\"));\n\n                    b.Property<string>(\"ClaimType\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_type\");\n\n                    b.Property<string>(\"ClaimValue\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_value\");\n\n                    b.Property<Guid>(\"RoleId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"role_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_role_claims\");\n\n                    b.HasIndex(\"RoleId\")\n                        .HasDatabaseName(\"ix_asp_net_role_claims_role_id\");\n\n                    b.ToTable(\"asp_net_role_claims\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.User\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<int>(\"AccessFailedCount\")\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"access_failed_count\");\n\n                    b.Property<string>(\"ConcurrencyStamp\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"concurrency_stamp\");\n\n                    b.Property<string>(\"Email\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"email\");\n\n                    b.Property<bool>(\"EmailConfirmed\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"email_confirmed\");\n\n                    b.Property<string>(\"FirstName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"first_name\");\n\n                    b.Property<string>(\"LastName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"last_name\");\n\n                    b.Property<bool>(\"LockoutEnabled\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"lockout_enabled\");\n\n                    b.Property<DateTimeOffset?>(\"LockoutEnd\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"lockout_end\");\n\n                    b.Property<string>(\"NormalizedEmail\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_email\");\n\n                    b.Property<string>(\"NormalizedUserName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_user_name\");\n\n                    b.Property<string>(\"PassPortNumber\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"pass_port_number\");\n\n                    b.Property<string>(\"PasswordHash\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"password_hash\");\n\n                    b.Property<string>(\"PhoneNumber\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"phone_number\");\n\n                    b.Property<bool>(\"PhoneNumberConfirmed\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"phone_number_confirmed\");\n\n                    b.Property<string>(\"SecurityStamp\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"security_stamp\");\n\n                    b.Property<bool>(\"TwoFactorEnabled\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"two_factor_enabled\");\n\n                    b.Property<string>(\"UserName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"user_name\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_users\");\n\n                    b.HasIndex(\"NormalizedEmail\")\n                        .HasDatabaseName(\"EmailIndex\");\n\n                    b.HasIndex(\"NormalizedUserName\")\n                        .IsUnique()\n                        .HasDatabaseName(\"UserNameIndex\");\n\n                    b.ToTable(\"asp_net_users\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserClaim\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"id\");\n\n                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>(\"Id\"));\n\n                    b.Property<string>(\"ClaimType\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_type\");\n\n                    b.Property<string>(\"ClaimValue\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_value\");\n\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_user_claims\");\n\n                    b.HasIndex(\"UserId\")\n                        .HasDatabaseName(\"ix_asp_net_user_claims_user_id\");\n\n                    b.ToTable(\"asp_net_user_claims\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserLogin\", b =>\n                {\n                    b.Property<string>(\"LoginProvider\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"login_provider\");\n\n                    b.Property<string>(\"ProviderKey\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"provider_key\");\n\n                    b.Property<string>(\"ProviderDisplayName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"provider_display_name\");\n\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"LoginProvider\", \"ProviderKey\")\n                        .HasName(\"pk_asp_net_user_logins\");\n\n                    b.HasIndex(\"UserId\")\n                        .HasDatabaseName(\"ix_asp_net_user_logins_user_id\");\n\n                    b.ToTable(\"asp_net_user_logins\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserRole\", b =>\n                {\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<Guid>(\"RoleId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"role_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"UserId\", \"RoleId\")\n                        .HasName(\"pk_asp_net_user_roles\");\n\n                    b.HasIndex(\"RoleId\")\n                        .HasDatabaseName(\"ix_asp_net_user_roles_role_id\");\n\n                    b.ToTable(\"asp_net_user_roles\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserToken\", b =>\n                {\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<string>(\"LoginProvider\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"login_provider\");\n\n                    b.Property<string>(\"Name\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"name\");\n\n                    b.Property<string>(\"Value\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"value\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"UserId\", \"LoginProvider\", \"Name\")\n                        .HasName(\"pk_asp_net_user_tokens\");\n\n                    b.ToTable(\"asp_net_user_tokens\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.RoleClaim\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.Role\", null)\n                        .WithMany()\n                        .HasForeignKey(\"RoleId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_role_claims_asp_net_roles_role_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserClaim\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_claims_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserLogin\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_logins_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserRole\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.Role\", null)\n                        .WithMany()\n                        .HasForeignKey(\"RoleId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_roles_asp_net_roles_role_id\");\n\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_roles_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserToken\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_tokens_asp_net_users_user_id\");\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Migrations/20230331193410_initial.cs",
    "content": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\n\n#nullable disable\n\nnamespace Identity.Data.Migrations\n{\n    /// <inheritdoc />\n    public partial class initial : Migration\n    {\n        /// <inheritdoc />\n        protected override void Up(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.CreateTable(\n                name: \"asp_net_roles\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    name = table.Column<string>(type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    normalizedname = table.Column<string>(name: \"normalized_name\", type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    concurrencystamp = table.Column<string>(name: \"concurrency_stamp\", type: \"text\", nullable: true)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_roles\", x => x.id);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_users\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    firstname = table.Column<string>(name: \"first_name\", type: \"text\", nullable: true),\n                    lastname = table.Column<string>(name: \"last_name\", type: \"text\", nullable: true),\n                    passportnumber = table.Column<string>(name: \"pass_port_number\", type: \"text\", nullable: true),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    username = table.Column<string>(name: \"user_name\", type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    normalizedusername = table.Column<string>(name: \"normalized_user_name\", type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    email = table.Column<string>(type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    normalizedemail = table.Column<string>(name: \"normalized_email\", type: \"character varying(256)\", maxLength: 256, nullable: true),\n                    emailconfirmed = table.Column<bool>(name: \"email_confirmed\", type: \"boolean\", nullable: false),\n                    passwordhash = table.Column<string>(name: \"password_hash\", type: \"text\", nullable: true),\n                    securitystamp = table.Column<string>(name: \"security_stamp\", type: \"text\", nullable: true),\n                    concurrencystamp = table.Column<string>(name: \"concurrency_stamp\", type: \"text\", nullable: true),\n                    phonenumber = table.Column<string>(name: \"phone_number\", type: \"text\", nullable: true),\n                    phonenumberconfirmed = table.Column<bool>(name: \"phone_number_confirmed\", type: \"boolean\", nullable: false),\n                    twofactorenabled = table.Column<bool>(name: \"two_factor_enabled\", type: \"boolean\", nullable: false),\n                    lockoutend = table.Column<DateTimeOffset>(name: \"lockout_end\", type: \"timestamp with time zone\", nullable: true),\n                    lockoutenabled = table.Column<bool>(name: \"lockout_enabled\", type: \"boolean\", nullable: false),\n                    accessfailedcount = table.Column<int>(name: \"access_failed_count\", type: \"integer\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_users\", x => x.id);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_role_claims\",\n                columns: table => new\n                {\n                    id = table.Column<int>(type: \"integer\", nullable: false)\n                        .Annotation(\"Npgsql:ValueGenerationStrategy\", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    roleid = table.Column<Guid>(name: \"role_id\", type: \"uuid\", nullable: false),\n                    claimtype = table.Column<string>(name: \"claim_type\", type: \"text\", nullable: true),\n                    claimvalue = table.Column<string>(name: \"claim_value\", type: \"text\", nullable: true)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_role_claims\", x => x.id);\n                    table.ForeignKey(\n                        name: \"fk_asp_net_role_claims_asp_net_roles_role_id\",\n                        column: x => x.roleid,\n                        principalTable: \"asp_net_roles\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_user_claims\",\n                columns: table => new\n                {\n                    id = table.Column<int>(type: \"integer\", nullable: false)\n                        .Annotation(\"Npgsql:ValueGenerationStrategy\", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    userid = table.Column<Guid>(name: \"user_id\", type: \"uuid\", nullable: false),\n                    claimtype = table.Column<string>(name: \"claim_type\", type: \"text\", nullable: true),\n                    claimvalue = table.Column<string>(name: \"claim_value\", type: \"text\", nullable: true)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_user_claims\", x => x.id);\n                    table.ForeignKey(\n                        name: \"fk_asp_net_user_claims_asp_net_users_user_id\",\n                        column: x => x.userid,\n                        principalTable: \"asp_net_users\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_user_logins\",\n                columns: table => new\n                {\n                    loginprovider = table.Column<string>(name: \"login_provider\", type: \"text\", nullable: false),\n                    providerkey = table.Column<string>(name: \"provider_key\", type: \"text\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    providerdisplayname = table.Column<string>(name: \"provider_display_name\", type: \"text\", nullable: true),\n                    userid = table.Column<Guid>(name: \"user_id\", type: \"uuid\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_user_logins\", x => new { x.loginprovider, x.providerkey });\n                    table.ForeignKey(\n                        name: \"fk_asp_net_user_logins_asp_net_users_user_id\",\n                        column: x => x.userid,\n                        principalTable: \"asp_net_users\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_user_roles\",\n                columns: table => new\n                {\n                    userid = table.Column<Guid>(name: \"user_id\", type: \"uuid\", nullable: false),\n                    roleid = table.Column<Guid>(name: \"role_id\", type: \"uuid\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_user_roles\", x => new { x.userid, x.roleid });\n                    table.ForeignKey(\n                        name: \"fk_asp_net_user_roles_asp_net_roles_role_id\",\n                        column: x => x.roleid,\n                        principalTable: \"asp_net_roles\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                    table.ForeignKey(\n                        name: \"fk_asp_net_user_roles_asp_net_users_user_id\",\n                        column: x => x.userid,\n                        principalTable: \"asp_net_users\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateTable(\n                name: \"asp_net_user_tokens\",\n                columns: table => new\n                {\n                    userid = table.Column<Guid>(name: \"user_id\", type: \"uuid\", nullable: false),\n                    loginprovider = table.Column<string>(name: \"login_provider\", type: \"text\", nullable: false),\n                    name = table.Column<string>(type: \"text\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false),\n                    value = table.Column<string>(type: \"text\", nullable: true)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_asp_net_user_tokens\", x => new { x.userid, x.loginprovider, x.name });\n                    table.ForeignKey(\n                        name: \"fk_asp_net_user_tokens_asp_net_users_user_id\",\n                        column: x => x.userid,\n                        principalTable: \"asp_net_users\",\n                        principalColumn: \"id\",\n                        onDelete: ReferentialAction.Cascade);\n                });\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_asp_net_role_claims_role_id\",\n                table: \"asp_net_role_claims\",\n                column: \"role_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"RoleNameIndex\",\n                table: \"asp_net_roles\",\n                column: \"normalized_name\",\n                unique: true);\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_asp_net_user_claims_user_id\",\n                table: \"asp_net_user_claims\",\n                column: \"user_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_asp_net_user_logins_user_id\",\n                table: \"asp_net_user_logins\",\n                column: \"user_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"ix_asp_net_user_roles_role_id\",\n                table: \"asp_net_user_roles\",\n                column: \"role_id\");\n\n            migrationBuilder.CreateIndex(\n                name: \"EmailIndex\",\n                table: \"asp_net_users\",\n                column: \"normalized_email\");\n\n            migrationBuilder.CreateIndex(\n                name: \"UserNameIndex\",\n                table: \"asp_net_users\",\n                column: \"normalized_user_name\",\n                unique: true);\n        }\n\n        /// <inheritdoc />\n        protected override void Down(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.DropTable(\n                name: \"asp_net_role_claims\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_user_claims\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_user_logins\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_user_roles\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_user_tokens\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_roles\");\n\n            migrationBuilder.DropTable(\n                name: \"asp_net_users\");\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Migrations/IdentityContextModelSnapshot.cs",
    "content": "// <auto-generated />\nusing System;\nusing Identity.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\n\n#nullable disable\n\nnamespace Identity.Data.Migrations\n{\n    [DbContext(typeof(IdentityContext))]\n    partial class IdentityContextModelSnapshot : ModelSnapshot\n    {\n        protected override void BuildModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"7.0.2\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Identity.Identity.Models.Role\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<string>(\"ConcurrencyStamp\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"concurrency_stamp\");\n\n                    b.Property<string>(\"Name\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"name\");\n\n                    b.Property<string>(\"NormalizedName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_name\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_roles\");\n\n                    b.HasIndex(\"NormalizedName\")\n                        .IsUnique()\n                        .HasDatabaseName(\"RoleNameIndex\");\n\n                    b.ToTable(\"asp_net_roles\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.RoleClaim\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"id\");\n\n                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>(\"Id\"));\n\n                    b.Property<string>(\"ClaimType\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_type\");\n\n                    b.Property<string>(\"ClaimValue\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_value\");\n\n                    b.Property<Guid>(\"RoleId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"role_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_role_claims\");\n\n                    b.HasIndex(\"RoleId\")\n                        .HasDatabaseName(\"ix_asp_net_role_claims_role_id\");\n\n                    b.ToTable(\"asp_net_role_claims\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.User\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<int>(\"AccessFailedCount\")\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"access_failed_count\");\n\n                    b.Property<string>(\"ConcurrencyStamp\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"concurrency_stamp\");\n\n                    b.Property<string>(\"Email\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"email\");\n\n                    b.Property<bool>(\"EmailConfirmed\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"email_confirmed\");\n\n                    b.Property<string>(\"FirstName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"first_name\");\n\n                    b.Property<string>(\"LastName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"last_name\");\n\n                    b.Property<bool>(\"LockoutEnabled\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"lockout_enabled\");\n\n                    b.Property<DateTimeOffset?>(\"LockoutEnd\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"lockout_end\");\n\n                    b.Property<string>(\"NormalizedEmail\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_email\");\n\n                    b.Property<string>(\"NormalizedUserName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"normalized_user_name\");\n\n                    b.Property<string>(\"PassPortNumber\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"pass_port_number\");\n\n                    b.Property<string>(\"PasswordHash\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"password_hash\");\n\n                    b.Property<string>(\"PhoneNumber\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"phone_number\");\n\n                    b.Property<bool>(\"PhoneNumberConfirmed\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"phone_number_confirmed\");\n\n                    b.Property<string>(\"SecurityStamp\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"security_stamp\");\n\n                    b.Property<bool>(\"TwoFactorEnabled\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"two_factor_enabled\");\n\n                    b.Property<string>(\"UserName\")\n                        .HasMaxLength(256)\n                        .HasColumnType(\"character varying(256)\")\n                        .HasColumnName(\"user_name\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_users\");\n\n                    b.HasIndex(\"NormalizedEmail\")\n                        .HasDatabaseName(\"EmailIndex\");\n\n                    b.HasIndex(\"NormalizedUserName\")\n                        .IsUnique()\n                        .HasDatabaseName(\"UserNameIndex\");\n\n                    b.ToTable(\"asp_net_users\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserClaim\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"integer\")\n                        .HasColumnName(\"id\");\n\n                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>(\"Id\"));\n\n                    b.Property<string>(\"ClaimType\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_type\");\n\n                    b.Property<string>(\"ClaimValue\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"claim_value\");\n\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_asp_net_user_claims\");\n\n                    b.HasIndex(\"UserId\")\n                        .HasDatabaseName(\"ix_asp_net_user_claims_user_id\");\n\n                    b.ToTable(\"asp_net_user_claims\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserLogin\", b =>\n                {\n                    b.Property<string>(\"LoginProvider\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"login_provider\");\n\n                    b.Property<string>(\"ProviderKey\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"provider_key\");\n\n                    b.Property<string>(\"ProviderDisplayName\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"provider_display_name\");\n\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"LoginProvider\", \"ProviderKey\")\n                        .HasName(\"pk_asp_net_user_logins\");\n\n                    b.HasIndex(\"UserId\")\n                        .HasDatabaseName(\"ix_asp_net_user_logins_user_id\");\n\n                    b.ToTable(\"asp_net_user_logins\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserRole\", b =>\n                {\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<Guid>(\"RoleId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"role_id\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"UserId\", \"RoleId\")\n                        .HasName(\"pk_asp_net_user_roles\");\n\n                    b.HasIndex(\"RoleId\")\n                        .HasDatabaseName(\"ix_asp_net_user_roles_role_id\");\n\n                    b.ToTable(\"asp_net_user_roles\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserToken\", b =>\n                {\n                    b.Property<Guid>(\"UserId\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"user_id\");\n\n                    b.Property<string>(\"LoginProvider\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"login_provider\");\n\n                    b.Property<string>(\"Name\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"name\");\n\n                    b.Property<string>(\"Value\")\n                        .HasColumnType(\"text\")\n                        .HasColumnName(\"value\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"UserId\", \"LoginProvider\", \"Name\")\n                        .HasName(\"pk_asp_net_user_tokens\");\n\n                    b.ToTable(\"asp_net_user_tokens\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.RoleClaim\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.Role\", null)\n                        .WithMany()\n                        .HasForeignKey(\"RoleId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_role_claims_asp_net_roles_role_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserClaim\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_claims_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserLogin\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_logins_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserRole\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.Role\", null)\n                        .WithMany()\n                        .HasForeignKey(\"RoleId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_roles_asp_net_roles_role_id\");\n\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_roles_asp_net_users_user_id\");\n                });\n\n            modelBuilder.Entity(\"Identity.Identity.Models.UserToken\", b =>\n                {\n                    b.HasOne(\"Identity.Identity.Models.User\", null)\n                        .WithMany()\n                        .HasForeignKey(\"UserId\")\n                        .OnDelete(DeleteBehavior.Cascade)\n                        .IsRequired()\n                        .HasConstraintName(\"fk_asp_net_user_tokens_asp_net_users_user_id\");\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Seed/IdentityDataSeeder.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing BuildingBlocks.Constants;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.EFCore;\nusing Identity.Identity.Constants;\nusing Identity.Identity.Models;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Identity.Data.Seed;\n\nusing System.Linq;\n\npublic class IdentityDataSeeder : IDataSeeder\n{\n    private readonly UserManager<User> _userManager;\n    private readonly RoleManager<Role> _roleManager;\n    private readonly IEventDispatcher _eventDispatcher;\n    private readonly IdentityContext _identityContext;\n\n    public IdentityDataSeeder(UserManager<User> userManager,\n                              RoleManager<Role> roleManager,\n                              IEventDispatcher eventDispatcher,\n                              IdentityContext identityContext)\n    {\n        _userManager = userManager;\n        _roleManager = roleManager;\n        _eventDispatcher = eventDispatcher;\n        _identityContext = identityContext;\n    }\n\n    public async Task SeedAllAsync()\n    {\n        var pendingMigrations = await _identityContext.Database.GetPendingMigrationsAsync();\n\n        if (!pendingMigrations.Any())\n        {\n            await SeedRoles();\n            await SeedUsers();\n        }\n    }\n\n    private async Task SeedRoles()\n    {\n        if (await _roleManager.RoleExistsAsync(IdentityConstant.Role.Admin) == false)\n        {\n            await _roleManager.CreateAsync(new Role { Name = IdentityConstant.Role.Admin });\n        }\n\n        if (await _roleManager.RoleExistsAsync(IdentityConstant.Role.User) == false)\n        {\n            await _roleManager.CreateAsync(new Role { Name = IdentityConstant.Role.User });\n        }\n    }\n\n    private async Task SeedUsers()\n    {\n        if (await _userManager.FindByNameAsync(\"samh\") == null)\n        {\n            var result = await _userManager.CreateAsync(InitialData.Users.First(), \"Admin@123456\");\n\n            if (result.Succeeded)\n            {\n                await _userManager.AddToRoleAsync(InitialData.Users.First(), IdentityConstant.Role.Admin);\n\n                await _eventDispatcher.SendAsync(new UserCreated(InitialData.Users.First().Id, InitialData.Users.First().FirstName + \" \" + InitialData.Users.First().LastName, InitialData.Users.First().PassPortNumber));\n            }\n        }\n\n        if (await _userManager.FindByNameAsync(\"meysamh2\") == null)\n        {\n            var result = await _userManager.CreateAsync(InitialData.Users.Last(), \"User@123456\");\n\n            if (result.Succeeded)\n            {\n                await _userManager.AddToRoleAsync(InitialData.Users.Last(), IdentityConstant.Role.User);\n\n                await _eventDispatcher.SendAsync(new UserCreated(InitialData.Users.Last().Id, InitialData.Users.Last().FirstName + \" \" + InitialData.Users.Last().LastName, InitialData.Users.Last().PassPortNumber));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/Seed/InitialData.cs",
    "content": "namespace Identity.Data.Seed;\n\nusing System;\nusing System.Collections.Generic;\nusing Identity.Models;\nusing MassTransit;\n\npublic static class InitialData\n{\n    public static List<User> Users { get; }\n\n    static InitialData()\n    {\n        Users = new List<User>\n        {\n            new User\n            {\n                Id = NewId.NextGuid(),\n                FirstName = \"Sam\",\n                LastName = \"H\",\n                UserName = \"samh\",\n                PassPortNumber = \"12345678\",\n                Email = \"sam@test.com\",\n                SecurityStamp = Guid.NewGuid().ToString()\n            },\n            new User\n            {\n                Id = NewId.NextGuid(),\n                FirstName = \"Sam2\",\n                LastName = \"H2\",\n                UserName = \"samh2\",\n                PassPortNumber = \"87654321\",\n                Email = \"sam2@test.com\",\n                SecurityStamp = Guid.NewGuid().ToString()\n            }\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Data/readme.md",
    "content": "dotnet ef migrations add initial --context IdentityContext -o \"Data\\Migrations\"\ndotnet ef database update --context IdentityContext\n"
  },
  {
    "path": "src/Services/Identity/src/Identity/Extensions/Infrastructure/IdentityServerExtensions.cs",
    "content": "using BuildingBlocks.Web;\nusing Identity.Data;\nusing Identity.Identity.Models;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Identity.Extensions.Infrastructure;\n\nusing Configurations;\n\npublic static class IdentityServerExtensions\n{\n    public static WebApplicationBuilder AddCustomIdentityServer(this WebApplicationBuilder builder)\n    {\n        builder.Services.AddValidateOptions<AuthOptions>();\n        var authOptions = builder.Services.GetOptions<AuthOptions>(nameof(AuthOptions));\n\n        builder.Services.AddIdentity<User, Role>(config =>\n            {\n                config.Password.RequiredLength = 6;\n                config.Password.RequireDigit = false;\n                config.Password.RequireNonAlphanumeric = false;\n                config.Password.RequireUppercase = false;\n            })\n            .AddEntityFrameworkStores<IdentityContext>()\n            .AddDefaultTokenProviders();\n\n        var identityServerBuilder = builder.Services.AddIdentityServer(options =>\n            {\n                options.Events.RaiseErrorEvents = true;\n                options.Events.RaiseInformationEvents = true;\n                options.Events.RaiseFailureEvents = true;\n                options.Events.RaiseSuccessEvents = true;\n                options.IssuerUri = authOptions.IssuerUri;\n            })\n            .AddInMemoryIdentityResources(Config.IdentityResources)\n            .AddInMemoryApiResources(Config.ApiResources)\n            .AddInMemoryApiScopes(Config.ApiScopes)\n            .AddInMemoryClients(Config.Clients)\n            .AddAspNetIdentity<User>()\n            .AddResourceOwnerValidator<UserValidator>();\n\n        //ref: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html\n        identityServerBuilder.AddDeveloperSigningCredential();\n\n        builder.Services.ConfigureApplicationCookie(options =>\n                                                    {\n                                                        options.Events.OnRedirectToLogin = context =>\n                                                        {\n                                                            context.Response.StatusCode = StatusCodes.Status401Unauthorized;\n                                                            return Task.CompletedTask;\n                                                        };\n\n                                                        options.Events.OnRedirectToAccessDenied = context =>\n                                                        {\n                                                            context.Response.StatusCode = StatusCodes.Status403Forbidden;\n                                                            return Task.CompletedTask;\n                                                        };\n                                                    });\n\n        return builder;\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Extensions/Infrastructure/InfrastructureExtensions.cs",
    "content": "using BuildingBlocks.Core;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Mapster;\nusing BuildingBlocks.MassTransit;\nusing BuildingBlocks.OpenApi;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.ProblemDetails;\nusing BuildingBlocks.Web;\nusing Figgle;\nusing Figgle.Fonts;\nusing FluentValidation;\nusing Identity.Data;\nusing Identity.Data.Seed;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.HttpOverrides;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing ServiceDefaults;\n\nnamespace Identity.Extensions.Infrastructure;\n\npublic static class InfrastructureExtensions\n{\n    public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder)\n    {\n        var configuration = builder.Configuration;\n        var env = builder.Environment;\n\n        builder.AddServiceDefaults();\n\n        builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();\n        builder.Services.AddScoped<IEventMapper, IdentityEventMapper>();\n        builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();\n\n        builder.Services.Configure<ApiBehaviorOptions>(options =>\n        {\n            options.SuppressModelStateInvalidFilter = true;\n        });\n\n        var appOptions = builder.Services.GetOptions<AppOptions>(nameof(AppOptions));\n        Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));\n\n        builder.Services.AddEndpointsApiExplorer();\n        builder.Services.AddControllers();\n        builder.AddPersistMessageProcessor();\n        builder.AddCustomDbContext<IdentityContext>(nameof(Identity));\n        builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>();\n        builder.Services.AddAspnetOpenApi();\n        builder.Services.AddCustomVersioning();\n        builder.Services.AddCustomMediatR();\n        builder.Services.AddValidatorsFromAssembly(typeof(IdentityRoot).Assembly);\n        builder.Services.AddProblemDetails();\n        builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly);\n\n        builder.Services.AddCustomMassTransit(env, TransportType.RabbitMq, typeof(IdentityRoot).Assembly);\n\n        builder.AddCustomIdentityServer();\n\n        builder.Services.Configure<ForwardedHeadersOptions>(options =>\n        {\n            options.ForwardedHeaders =\n                ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;\n        });\n\n        return builder;\n    }\n\n\n    public static WebApplication UseInfrastructure(this WebApplication app)\n    {\n        var env = app.Environment;\n        var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));\n\n        app.UseAuthentication();\n        app.UseAuthorization();\n\n        app.UseServiceDefaults();\n\n        app.UseForwardedHeaders();\n\n        app.UseCustomProblemDetails();\n        app.UseCorrelationId();\n        app.UseMigration<IdentityContext>();\n        app.UseIdentityServer();\n\n        app.MapGet(\"/\", x => x.Response.WriteAsync(appOptions.Name));\n\n        if (env.IsDevelopment())\n        {\n            app.UseAspnetOpenApi();\n        }\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Extensions/Infrastructure/MediatRExtensions.cs",
    "content": "using BuildingBlocks.Logging;\nusing BuildingBlocks.Validation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Identity.Extensions.Infrastructure;\n\nusing Configurations;\n\npublic static class MediatRExtensions\n{\n    public static IServiceCollection AddCustomMediatR(this IServiceCollection services)\n    {\n        services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(IdentityRoot).Assembly));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Constants/Constants.cs",
    "content": "namespace Identity.Identity.Constants;\n\npublic static class Constants\n{\n    public static class StandardScopes\n    {\n        public const string Roles = \"roles\";\n        public const string FlightApi = \"flight-api\";\n        public const string PassengerApi = \"passenger-api\";\n        public const string BookingApi = \"booking-api\";\n        public const string IdentityApi = \"identity-api\";\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Exceptions/RegisterIdentityUserException.cs",
    "content": "using BuildingBlocks.Exception;\n\nnamespace Identity.Identity.Exceptions;\n\npublic class RegisterIdentityUserException : AppException\n{\n    public RegisterIdentityUserException(string message) : base(message)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Features/IdentityMappings.cs",
    "content": "using Mapster;\n\nnamespace Identity.Identity.Features;\n\nusing RegisteringNewUser.V1;\n\npublic class IdentityMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<RegisterNewUserRequestDto, RegisterNewUser>()\n            .ConstructUsing(x => new RegisterNewUser(x.FirstName, x.LastName, x.Username, x.Email,\n                x.Password, x.ConfirmPassword, x.PassportNumber));\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Features/RegisteringNewUser/V1/RegisterNewUser.cs",
    "content": "using BuildingBlocks.Constants;\n\nnamespace Identity.Identity.Features.RegisteringNewUser.V1;\n\nusing System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Routing;\nusing Models;\n\npublic record RegisterNewUser(string FirstName, string LastName, string Username, string Email,\n    string Password, string ConfirmPassword, string PassportNumber) : ICommand<RegisterNewUserResult>;\n\npublic record RegisterNewUserResult(Guid Id, string FirstName, string LastName, string Username, string PassportNumber);\n\npublic record RegisterNewUserRequestDto(string FirstName, string LastName, string Username, string Email,\n    string Password, string ConfirmPassword, string PassportNumber);\n\npublic record RegisterNewUserResponseDto(Guid Id, string FirstName, string LastName, string Username,\n    string PassportNumber);\n\npublic class RegisterNewUserEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapPost($\"{EndpointConfig.BaseApiPath}/identity/register-user\", async (\n                RegisterNewUserRequestDto request, IMediator mediator, IMapper mapper,\n                CancellationToken cancellationToken) =>\n            {\n                var command = mapper.Map<RegisterNewUser>(request);\n\n                var result = await mediator.Send(command, cancellationToken);\n\n                var response = result.Adapt<RegisterNewUserResponseDto>();\n\n                return Results.Ok(response);\n            })\n            .RequireAuthorization()\n            .WithName(\"RegisterUser\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Identity\").Build())\n            .Produces<RegisterNewUserResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Register User\")\n            .WithDescription(\"Register User\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class RegisterNewUserValidator : AbstractValidator<RegisterNewUser>\n{\n    public RegisterNewUserValidator()\n    {\n        RuleFor(x => x.Password).NotEmpty().WithMessage(\"Please enter the password\");\n        RuleFor(x => x.ConfirmPassword).NotEmpty().WithMessage(\"Please enter the confirmation password\");\n\n        RuleFor(x => x).Custom((x, context) =>\n        {\n            if (x.Password != x.ConfirmPassword)\n            {\n                context.AddFailure(nameof(x.Password), \"Passwords should match\");\n            }\n        });\n\n        RuleFor(x => x.Username).NotEmpty().WithMessage(\"Please enter the username\");\n        RuleFor(x => x.FirstName).NotEmpty().WithMessage(\"Please enter the first name\");\n        RuleFor(x => x.LastName).NotEmpty().WithMessage(\"Please enter the last name\");\n        RuleFor(x => x.Email).NotEmpty().WithMessage(\"Please enter the last email\")\n            .EmailAddress().WithMessage(\"A valid email is required\");\n    }\n}\n\ninternal class RegisterNewUserHandler : ICommandHandler<RegisterNewUser, RegisterNewUserResult>\n{\n    private readonly IEventDispatcher _eventDispatcher;\n    private readonly UserManager<User> _userManager;\n\n    public RegisterNewUserHandler(UserManager<User> userManager,\n        IEventDispatcher eventDispatcher)\n    {\n        _userManager = userManager;\n        _eventDispatcher = eventDispatcher;\n    }\n\n    public async Task<RegisterNewUserResult> Handle(RegisterNewUser request,\n        CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var applicationUser = new User()\n        {\n            FirstName = request.FirstName,\n            LastName = request.LastName,\n            UserName = request.Username,\n            Email = request.Email,\n            PasswordHash = request.Password,\n            PassPortNumber = request.PassportNumber\n        };\n\n        var identityResult = await _userManager.CreateAsync(applicationUser, request.Password);\n        var roleResult = await _userManager.AddToRoleAsync(applicationUser, IdentityConstant.Role.User);\n\n        if (identityResult.Succeeded == false)\n        {\n            throw new RegisterIdentityUserException(string.Join(',', identityResult.Errors.Select(e => e.Description)));\n        }\n\n        if (roleResult.Succeeded == false)\n        {\n            throw new RegisterIdentityUserException(string.Join(',', roleResult.Errors.Select(e => e.Description)));\n        }\n\n        await _eventDispatcher.SendAsync(new UserCreated(applicationUser.Id,\n            applicationUser.FirstName + \" \" + applicationUser.LastName,\n            applicationUser.PassPortNumber), cancellationToken: cancellationToken);\n\n        return new RegisterNewUserResult(applicationUser.Id, applicationUser.FirstName, applicationUser.LastName,\n            applicationUser.UserName, applicationUser.PassPortNumber);\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/Role.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class Role : IdentityRole<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/RoleClaim.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class RoleClaim : IdentityRoleClaim<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/User.cs",
    "content": "using Microsoft.AspNetCore.Identity;\n\nnamespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\n\npublic class User : IdentityUser<Guid>, IVersion\n{\n    public required string FirstName { get; init; }\n    public required string LastName { get; init; }\n    public required string PassPortNumber { get; init; }\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/UserClaim.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class UserClaim : IdentityUserClaim<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/UserLogin.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class UserLogin : IdentityUserLogin<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/UserRole.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class UserRole : IdentityUserRole<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity/Models/UserToken.cs",
    "content": "namespace Identity.Identity.Models;\n\nusing System;\nusing BuildingBlocks.Core.Model;\nusing Microsoft.AspNetCore.Identity;\n\npublic class UserToken : IdentityUserToken<Guid>, IVersion\n{\n    public long Version { get; set; }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/Identity.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"10.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\Aspire\\src\\ServiceDefaults\\ServiceDefaults.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Identity/src/Identity/IdentityEventMapper.cs",
    "content": "using BuildingBlocks.Core;\nusing BuildingBlocks.Core.Event;\n\nnamespace Identity;\n\npublic sealed class IdentityEventMapper : IEventMapper\n{\n    public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            _ => null\n        };\n    }\n\n    public IInternalCommand? MapToInternalCommand(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            _ => null\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity/IdentityRoot.cs",
    "content": "namespace Identity;\n\npublic class IdentityRoot\n{\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/Identity.Api.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Identity\\Identity.csproj\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/Program.cs",
    "content": "using BuildingBlocks.Web;\nusing Identity;\nusing Identity.Extensions.Infrastructure;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddMinimalEndpoints(assemblies: typeof(IdentityRoot).Assembly);\nbuilder.AddInfrastructure();\n\nvar app = builder.Build();\n\napp.MapMinimalEndpoints();\napp.UseInfrastructure();\n\napp.Run();\n\nnamespace Identity.Api\n{\n    public partial class Program { }\n}"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/Properties/launchSettings.json",
    "content": "{\n    \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n    \"profiles\": {\n        \"Identity.Api\": {\n            \"commandName\": \"Project\",\n            \"dotnetRunMessages\": true,\n            \"launchUrl\": \"swagger\",\n            \"launchBrowser\": true,\n            \"applicationUrl\": \"http://localhost:6005;https://localhost:5005\",\n            \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/appsettings.Development.json",
    "content": "{\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/appsettings.docker.json",
    "content": "{\n    \"App\": \"Identity-Service\",\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=identity;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"AuthOptions\": {\n        \"IssuerUri\": \"http://identity:80\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"rabbitmq\",\n        \"ExchangeName\": \"identity\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/appsettings.json",
    "content": "{\n    \"AppOptions\": {\n        \"Name\": \"Identity-Service\"\n    },\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=identity;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"AuthOptions\": {\n        \"IssuerUri\": \"http://localhost:6005\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"identity\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"HealthOptions\": {\n        \"Enabled\": false\n    },\n    \"ObservabilityOptions\": {\n        \"InstrumentationName\": \"identity_service\",\n        \"OTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4317\"\n        },\n        \"AspireDashboardOTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4319\"\n        },\n        \"ZipkinOptions\": {\n            \"HttpExporterEndpoint\": \"http://localhost:9411/api/v2/spans\"\n        },\n        \"JaegerOptions\": {\n            \"OTLPGrpcExporterEndpoint\": \"http://localhost:14317\",\n            \"HttpExporterEndpoint\": \"http://localhost:14268/api/traces\"\n        },\n        \"UsePrometheusExporter\": true,\n        \"UseOTLPExporter\": true,\n        \"UseAspireOTLPExporter\": true,\n        \"UseGrafanaExporter\": false,\n        \"ServiceName\": \"Identity Service\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/appsettings.test.json",
    "content": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=identity_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"AuthOptions\": {\n        \"IssuerUri\": \"http://localhost:6005\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"identity\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    }\n}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/keys/is-signing-key-0AC3347A09AA5E44E947F3E30ED54871.json",
    "content": "{\"Version\":1,\"Id\":\"0AC3347A09AA5E44E947F3E30ED54871\",\"Created\":\"2023-02-22T21:06:15.7901014Z\",\"Algorithm\":\"RS256\",\"IsX509Certificate\":false,\"Data\":\"CfDJ8Pno3caweVxDrMdMtoqjLU9W7bGGdPAEm8VDpWIg5fNfBATZdniIo9r5lhBSMZ3OFJya6SlNGIFe9JkbzJBa5fwNa-omLt15Kjlu3QNX4bAWI3V87P70NAfKDKe4xBVF12B3ooXFXKJ2U5QzFBY8U_1tBXkeUTQKfioQ1lTPxIbQtmSyD-uSc5anbDjtqIWhDq1OlujSJpVHRJV9EzRCms4yZdUc506aWg_KrkpVITZyywj1X1cz-SaUGUqy01wJSXgEj70OdVo2DoPIEYTDAlymi40-R2jQsnseFEG3W7XQlYX29joTygtkumnVED2WF9y9Boy80Kj5XN5XZvL1opV-qtxA8aekkp3XuwMJtBmnMeslHK8TyvBl5JjdZwULdYJFo-rGSDEuI4bswDzMWUgv6oAxgqE6e7SQiFlHuLgWHkmEis4-r-EphCl7B_lNOMQViifon6L8t0lUGdPFhFfN5Fo7cj_lZPx5uqymwVUwIEPrEisZtkwsPYZeKuVdSaRnl5xDlU6AgbQvcNeTtg9_kyB6Z43rEPTvtwMkoBjVe5iTQ5ZtubByEGKVIugxNMfHzPc1E9FNTT3uW928Uq6RQiNah17cNBQsVmYAq_iRggDJwAeFnUgqnh0hFuve2_9T4Nt6XFSV-0OQ7aM8C8VPpEzROYhs_MMrzYuJAnV7VuvgUm4Zk9A2OFx9nGQXjL8WZ1-CcNV-TGESRUc9tfFizHPnd417h_qBYb8rJ-znet07KYs0Hwo_S8nbc4fAeG7OEj8cgn0nwgnDMa0_ROzvfFhmeWkkY5LdwtF0pgbO-_xdQwrx3mD2u6Nq5kABizd8ixH1urwvlfY5Z-MGwohf4HDjebiP49PsT96PAaj9ZFxz1HPfz4lOSCob7CBapIEt2exK0-OIhxkkU6i5_7iRvI_oFshzTvg2mSmR0zDWYfhiLZFoWGIlPi_B-pJvMEYgsyXW294yiAdVIJHXxs1nJRzgGBblY_FXM7IOzzwzpBtXH0odO8OPK6m8VBumDs9Q6iGiArFHwO5jKfvTxWYCM-PnTqW3ZselPIjZHSXbpGEU3o-HYg4rAGSIP9P_GoEJvSrQXqpYvhvPPbLh70OTwTtc8qG9GNW7XMoLpi6c8wUsapvrrYUBStlUWQ11UgvYSX1Nu4uCqTNTy6O1QHerbOHxWxfIOHzZyYfYnqQaF3bZZcMVJK3pOorcJKiMRCUp-hu5ismZ6T5Q2zfq93uqI3DpG2Wuov53o2s0QFmC4c5K6CCQVgLYBcib69twXjrWkVmGeM2CswLukOf8flUpGp_923M1TA4E89xkHxVhYESPfLB8FAULwNHOAW60U0tUksX-bcaAG1NUo3UEmaku2YfVbDJ7t5PJv8gc4zcPC0iXdBEL00G4FtSE2-r1TUhqK64iASEaAv3UTwefOMUR3qzxZC3HB7wH4iiUESH70s1RXvNIQoKz_ZirEa9WoR0tgk0MFyr4VDow-q-embX06vesnwyHhCdZBr8el_KT_yGWwlkR_xx18fR6mHT5G_BYuW-cK8ADvJe-Y_vns2yQprfGGgeVUQ5t4IKacpqnNNB9J2lLMisQ9fjYJCRhMP41CB7vk7oUXu49PgvJ_LkqtM5LAngo5f5DVdrzgX1-9I_KtyamJ9ic8nLqVsI5Z9iof9u9cRyDKhwQ4KPpD3uovwGnK7if25F9UaHFLvAJk2iOQjkA1rQyjCIJzi8dqpdw3W_L3Gc2m9Gr7HS1D0ZtWIk8z-TMNtR2PQcmlWiTJ9ZhLyMs67LWnLZri0jchEw4TJ46EAAUHE1hGhbs8xsmtta1yiu9VaZwCjDb5OJwnnl_2tA1ZkCE5Mh9NGSAZSCYLJCSRaCE53KypCYZBtJhR7Jcl1cz0OY9nNNUpzpPrcmCEz1cLw4z2H1OtujncZHDiyKqh57zQOTs--q9Nx8ytyhg7hBYIcqJFP8Gb0xQPjSkN1oO5ScAPIyPNY54VdIR7sk-99995Y-U6pnLQ_1JdIJZRYYnaYa4c5cqQaRE1n_G-L4_g20aBCX65SKkck5bwsAMJL371t4CqCBfPjzFugoNxR37DWicLUd9sJGBUMjj_lhWsk709om6shSJAy4loiz1qViwPi1K5XcFI7oyH735wg8X05Qxe1tby83X9FSd1FlTpVPRe1btEHddVubt9oeaZ0kOiN5BagaEF4wjIiQttnnzBfjKqcpuyd0zMhDTL_CqlmrTE09HH01VSnZ6lVllzCXGYI2hZKJFeOL7quHV4cDSoEVHOBL7SbChhm62iWOVTe2ho8V1NGnGFMmMfeplVWKorv-k2-L0H-K8rtg9d2vUdt-s5bxKkesUjxJhScBVOlFVcX6GdDa0o2R1W6qszC7D-_UILhIEtkQwnEg9SR-dDMulOotrHp5_LrsMCJLCgqGfzrjVymq7vkHbkh-8XIUzopyXgS4yr__N1MT2lI-7sFBG8fTa-GbN\",\"DataProtected\":true}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/keys/is-signing-key-A57781A0405849BDE786A79636460E49.json",
    "content": "{\"Version\":1,\"Id\":\"A57781A0405849BDE786A79636460E49\",\"Created\":\"2023-05-11T21:58:42.4707649Z\",\"Algorithm\":\"RS256\",\"IsX509Certificate\":false,\"Data\":\"CfDJ8Hnjqxp4tLpCov-J-Y0BVs7wR0CVu4eqUuKwsY0rf0WJyME4aNzhKfD2Z2K08hK8_8svrjSptVpC1ttyCPtXtPVMsQQRukJef7SjEUNlC-US2KuwQGOLMYIDNHkTHrnXN7GYHoFtZ1SQWdL61GJ43LYCyFY7_L_Sn9SFepnDcT9H3aA9-M3ZjDJNU8_qknPTEUhSjV1i7AMkYnCHHow0ttlYhcQGwXoiuMMI9oqu26yr79i7sG6m_BAK1f1eg_1cBGozNe4yRPHsRk4qCLKgG-JRaNfV8sXHM-3SpEeFx7iUYHLHl7SiQwsqrODIujk7sz_vJaDbiFqwSVxUTDBEBLPpmPULLGKzjGoPrGtpmvgHkghEsHtvXY6aTzWwDLBmOT4ao8IjImv8D3_ub_KgNC5rg5pBzYA-gKAhtE_RznEKP_DVR836v5Xpw7zMVxbYVNwLrJ5-QtD503G5QhywFUHO9pRiL-dtDHJTpSmq5esy-OKBl2QJ12WxfeeMUQ7tIkTSsj0ALMyJS-a7uVUkITxOkXxrBI5rF6OIK8GZwnmsxJK5L3Urbn76EgiFKVoqgyhBRs0GvRl5-WJyc69m3ltuhp1z7hYOh0BYjlecDd9WOqNbFE68BCYUi7O--mSE0Bv94K4eUs81ccSb3lwC0AtPWPWjG31E9cg8Sd-A1gXhAcYuLmeWSoAP2Issoi5blxeafWUadjbjdCtGI_lA1trpg9LpClEDZZt5uJ5DQa5yUVzdz7l-RnlF7C8ReBtM8qBxJYnaCnc4WC7WE5cKMYG6mGJY55o_EAR4urjsxy2Bdjh34cFIIEQwfh-tnex3uBvYFUzoCPp8KJY-eRhUXEjtZzeds51OVeLKkeyFtSVEZsFTCnmc3tTsOAtkpa7sjsU0Xe0sgMG_E1XS8P_BqfIm9RR8rPblmA6JytNt_Gs2f00ND28PAnj_UuLeOaFpl2sipa228-1JimzFxKnVN7ZtU_ztZtUCGCSELoNbana8ZyLuFRGjFxQnkVZarwEFVyl7w_4scMujShb3ttaJDul51tsSJJTY43nC-Vlo1UBtYUjjNKuexpmOKGXaYRPygy_g4EXsqiN4FTc3mcG7jRoHmd5mUcvXfI66WbDmpXn4DB4x1VrWs2MVrLJw1ioON42IgjhoUCklrYJx4cxEWrIC3EURILE_jTy2ThAhGF24Z6jdTM8iVN9W7wwrnUxoFJCflr_-jiWwCToUWxPfolVu4mpQDhWJ1K9vuTVhQNrbMbc95TH7-Z_HFKiZkw23U0Xvjd4dqBJol2POIdQkDDg_L2omPtlMdNwo8eJ9rLEycbqQzcFzbyZBr__BU7J16wpu2lwZZVGgYfiofb6E01Iq_2_VQw8WH7d6onBJNCRq6QIDfZ3VdEMjdlm3kGrcY-_kzsfM9x9H_a-EpzT0_PwZO6gWUvfEfI84fNgPhM0Gq4vkv4l0NSpvIpivmgU9g3J2yQpO4QXVyQGOcXSUvUGKDIBRMKch1IOIEB6qYi34muu8Et0pbHsDsXECCnkfs5FAnKlG-zuf6W2cNRsF7QyaoUpDSpRD8u_R_mcQEVA2VJb4NWPSV1zgJ6-ne7HO_DL1mW7F-0jl2yHqOJ5z8GMTNdl7Nh4LfvHEB7xs0M2fgPByq3JImX1M-KUZDyIxfqxUM8L44zPyjiHvpMgXDvaA21aytu7G4r3vlgFyuMnSPKJ-fV8LBYDUKZ7TSOtTL2yCV2D5Z_VE3uZzBrpmJzzPG1_OXgmqV57KsPnDdwVefeu9UbCaDzG0R_xGReJveQcf5be8iJtTRDwqB2qlYm01VuIUSxabFTb_MypnKoIFaOxonW1faOgZ0zV8ocbgDfKO-8T21BBAJryw76yHxEVm59_X7Oa1VS_TM7i2sB67DWQadn4i4VMrF34LQyyhwPguKPSey1k7DcsHMxJ9zwUbC22HURwqVRn9zzxz9vHHiCUskytu3bItRkSpwDD2z_ngL9hVUF3C4QM3d4vgoL4sWS7X1One8z-vyZpZH_BDUg4nwEx95KClv2XieWXTHep8_3rdSIyTPrLLqErhCur6U69boZlvoCmoYtgbYN7dA1VkdTzdnzU-zSRLRkOY_hsa2gEElHqdtjHHTdt9g3kNhnvBMmgTQcEsAKZFjnwSbC-BogTSYNiZYCUu9eYOmenwlF4X4Yti-bVpMCEn6_6H8dWjumdBb7hgsvm47Sbuna5vAnlfnPKZBgji-38Y5lPE3NRF0ImhrsaURNUFktoNhp2gwFh8R0nLRzoLr3jWF2pBMMbvKGGzEBxOGN0_3nodoSyjFJFyAHgTwNcxB0AeYImM_-mxFtjiCDESqZoZGWtg6MvXmXPnat_uaI-jwl6TFBUChTjWujfil5doh32BtImNFO8VQakhrpTCaVm6yBKH77eF6aCX50iTuVVBuMec3IJZNPdnsc_65R4VGpqLwdscWiJqtmaRt_Umj-eJ\",\"DataProtected\":true}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/keys/is-signing-key-B3C31EEE2718D3C5004C6E85AD74F26C.json",
    "content": "{\"Version\":1,\"Id\":\"B3C31EEE2718D3C5004C6E85AD74F26C\",\"Created\":\"2025-04-08T16:45:11.9802139Z\",\"Algorithm\":\"RS256\",\"IsX509Certificate\":false,\"Data\":\"CfDJ8KNpFTgHKl5Nl-o13RQ8rse7iqNX7fzIuFQawPXYLwTCbj1HOrmv2WHbV51cOwFkSjECACMh5ad32vYQMXHgU7-l9gMNU0QwhV5gdoDScJLFzFf-_gBCqNPsUWJxNebIFDHwSn12y9Kg56DzaRq9o4XO_wGEc3KsQjDjHuh0p-3n8qiliIxl_sBXTs8UCXhWMBqU5srioHUKwFu6nyAlhkDlsA9J6Syb9w6_WESzli6DpR9UphBKbjoV85ajrkuZzjd9GItRJ6C-OICEKUUoFXh5meVGuV-JmWhE1_nzASToml0vI6GZt8kxrJQkICt1MI7K2ZIQtHcoKhC09rWu7RpuOvKY8sLm0b8gbJQ1dVMNuZEnOczi-E3b6kKrYFwV_I3TFK4UZP7I90-cojBGpaWwX3IzkB8-Uwf-5qU2KXUZanO0tXEqw187ZVPDuvKkAUeAtphWFbV2ZNH12DGcXTvnvJfRxV5lRAuzH3N-Dhgz10F3VOQZtgoQyQ4wJE-B-04j3pqN_76NIh4Yx7GvArlWYMQTNBePMaLW33ycLlCrjov1nKK2BIhk4wykUeFT_rorXcf01PHJd3uqbtBDrP7ZoUqz8qWdY9-on3dvNi6cruyJ5rbmmE4hLAsWHLOqYLcceBF7LaZUthglcMtLlufU5C3wpXjoqpJZb1KiC7QR5sQE_KPfEiQsCO_hyXnFUvavOaGIiWWAhqADfGdD3wNma3qCAMwmV5T-_4_yW3wvYbrM8YFrHmQty6ks4W6qKJow1uwfAziDoobdV7bSLSxddWiO5zOuCeFNxIzsmMkk8PfxUyb-JySYFh_tA8D3Tn5kvTbFIRibfiBJXtB8Kk4ouvQxd6ydHCHOAHzuPgxs_nP6s3u0Xa12fmPpiCLaUjeNFHNP_wzh4l5Tn7GN4S07nOiFE1PyQUjT7xnYxcUuzySpiqLl2k9Bu98MMagGg6gqWnl5zV_Adxkq_aIvuvZF25JlE9SzAJkuJFBNqnXJ_ep-BCFogdHPgtjL_Y250A5DsiFnKrlJLuBIz88V_oLEj54iSi4hiJ66YT0H8lagPUIrL4h6cPCVWFeMiCf8yNeQVHCnRkIyXtID4CrSOr8KN5Qv_nKeAUxw_5BOgs5yEGxj4OGLLYViAobOCFOA1uCurA3OqyoI65CCyoPERAXm7dyKcIN8l0ChIHhCX2VBtwEoSG2QXlEjKLxmmMmHQrTuMMRNkd2_GlY6XNRw6MELf7W4SrxyZ-eWNY9nfye7z9Q-hv_dDkf5FGmd8qGpVUenIjH0GUz4JqWOQ6GmHb7b_9u5g5vNIqi5YHf59SuNGAUbE3PFpDGpIeh5YVrCV-msoaUEkYxXvsBcUsOIiC32kQy-u-fDPxYSg-aNCgBrKDnTK4IFFBNYjT1IIApIiz-Xq8mjTsJvgaYKOLsVfqPlWX_Fr63Fnnygt9zO1tNZjW6JSj34nZJ_6120mGZcNueXtUy66QJeF8DqVdt4DbXMWYk-rQcHvqk3lQ_r7u7r88hIwzXgE3YtFFlesUK_7DVcblSuTxNxDXO5M7U_2EO4KIJbDfQ6BYxovJrWwtPcSXb_Nq25St_X3wSMk3eSGO7GNHL89t_muN5tE97As0s89h8OM5cISROR72zLWyvki2aB4L5WFWpBg1xylymZBzWGF-VKbDpoIb09PsyuuWy502OONDxmsheeadUZCNZYlxiSkmGLXrjSgsAhQHmLr7BwZ2FmVJGHtWD-nUPMj32NljxYQ1Bzv0aYXmJhHT8lcmTcWxb8yQKhOk-S6oP7m3ftq-gzsmE4lATEAHFGtO9a_xJlNYivB0zMsOYfY7YJzRSYEgLCSxS4HiUysv3WYXYjAQaGJNoSJX1YMMvCDu1rt29oV17Td58wHWvnnsCFlckVah6y_DCfez9ucTpQPHsQMsW1Hwl-3xgndEyTuynTHZNgqCcxQWBFlo1Ay9HHl68ppFpxm7FvSScyTdjtMPD89qZ84P_V38Qlz9ye0J2LXWoH1np7jAnaRiEzc-_Dcra3Yv792ks_ZlLS3Tu9-m-iZiGILHxIaccR53BSbjjgKS7LXMPsWZ_kf4pBNspcIbnn1dm_L47sEKCeA_2J0BVQeG_x7ZXG38M100wreTadW_PE5WysYyFIbHy5_wvfVVIEPZ3cMFt66LjoFfAmn52kQUG2w65Nnr95bavMBNdKk9oo22QpRy3YJsrABp9DtUqh4CwCqZCu7KvD2yx5u6UKAOK-XWlU1UJ-dPxxcuoPsjeuG1ER8ySYexec7iXzg-tbKjeGGSnyj2z1fnTihIiQIw_CAiZwXuyD4e0zowAmjEF2RWRsWvacoU7n_TCFwx4dX5bEG41-J2KHGJVX1X9D2tBX7R963ICgP8xeoE5wxWEiQLrsED68PKsnMasLGW2oOtLR8DwERbydMYHRH2f63mexVE5gbdf_4UXpaYMC8bNUc3HWY3-Sb_Fbc46r\",\"DataProtected\":true}\n"
  },
  {
    "path": "src/Services/Identity/src/Identity.Api/keys/is-signing-key-E1668D5B7CCDD18C610506FCA7C5D194.json",
    "content": "﻿{\"Version\":1,\"Id\":\"E1668D5B7CCDD18C610506FCA7C5D194\",\"Created\":\"2025-07-21T17:14:15.7672364Z\",\"Algorithm\":\"RS256\",\"IsX509Certificate\":false,\"Data\":\"CfDJ8Ai8D9hfDhJIplL3Rv2bStBd2WatjNqn9OUgTfnOqxduEkXmsnrgWiHbuP-AYTE2ZeIxoDSDbZWBD8dJbAMe5PfH-FC7E5njE18xMIRyRxxvLHBcINyJ3fAP7lk5-uTl_F2DhoY6S_DCtbgbXCoB57FPr8DJzMPN0q37yuC34ZQYhfgLbkfydesVGqW1DF2_a5pd2KAFK_m8_FVy1GfHvTFnLjuURASp8eKEDJrtii4683uplUkycVJRHfHHQta1PuJW3KOLcX9jSePWDEBnQkjsiHm2O3BQFDdsMHbr8F2cLGW9uMIYNd96QyiH7nUgVZ0i5R-sHpbnGzUZFnZvpWLJFZrT3269nBLL2-t-7Sh99laIIT54cdZsW_uGFZ7r1MqyEPt9MoHqXXuOuhrn22QQeQURGmyUt4YyxdKCozsEPs7MR4IR_1iY93Rv4ThEn24vq1-guK-58pu3DurgigbTB7hFToOtqBHEhiVyXKgoNGOXH7UW5bJLFj4JtOIN_2SaTohhw9pSf8yH7gf6Chp2aVGUQt0OnVLbLu__EbB9XzJblQHLi6Ddm8uXdrJYXW17iBdEUHL8xD4hOiE4SR-bhD_d8c9yD7ydSyIwdistrVFRYpeDc6n-kQLWC6r1Z1oxIQte7ph6n3ygAWSwyCzSkI1GKJoh6QdR6rrs4EN9jUdFN4NgjQqftlLaE6xKq3f82wbCTk5-Iy8jJlr-xdDue_myN6Z_XOJ01pyjDkX9u3Aa0UuNFlvGYde9bJa6R7VxE5ggVozjpB_3FNUc91_3merwjq3K5-3S3EnhU8Nxi44Yjsw6-pVLbyF0Tgbh3uGUWI4EVv_nUC94cLaftuutq6rApSs1lF1jq_RK2P9YBQyCNl23JYMWEkPscMGIrx0306eLpWelYu_TpLk2lj5JfM7ep4uQ714bQXMLAdNX9GttAOOKlTrb4--uz8kjHaOSaJ01tvutQpog-RrudUVHX46_EA43U0jazAVQJXX7uDC5CEiSfCXozk7Gvw56gk72Ha1Ygz_qfaSn1hv6Q4cHhuhHzRV_aGui5oztal-oSh-zd_6BobstL1iZHhukHrUq_gVcFhYnqNDgzKT1L21AV9d0LbqONkFZ6kBGZ7ZIE2ymIqRx4DgBCdkmgZZUAZRqK3wkYW3oKI18l1aF7dGrrUnRSFVg5Jr0BYSmVPBVpfGLUHb3VHpjPVxPMV2W-ak0JG01jL7OQBuKXUW115Qd89GE2rj_SnInDg6ljW94zDHbqb_8gH3WOSWawM6021yQlRpMe7xqv6bYVeAS6WZBphKPxLV3BtG0_23IOiEbvsreT6UvIn9hx-VkJ_CADmlKQ8uNFxUIDvop6vGq5zjPgQz2-kJ529MUrp-ayn-oXTOrRgrYzLsUAH-gzf_osIMKsGPQakQMmnL7jsyX0z7Ci2wKuZ7pgxw8DQk8PKrk_yNuTMRQN0etUvv-nSCtPbcHALqMN9VgcHgCEEZTTP4A0pUUNAWewd2hJoh12H4_JlyJirHFDK5ZyM_uWKjAfVbh4RFLnxPaEEdQsew-WgXXE4Ne965OG283Q7TCv2MUCh-UynOz2ySw1FKD5XeqkOYmIXlrGf7DuhXQcam1SW9_8N5k9_lIdG_QPW6cM7HR3amBiHXnR7I-MBmTf3CLirEu_CrP6fdcGjrWBtbpfHCOPXNUseltmEWc0Ph3FoIYSR7F8o7cuYHWm0cuK3yC_73OXSDuDWmkl79qhyy3FJHV-6RTlsiyIZiOZ6Sxg24NKr5lp8FoqEZ2iQIKPfIPIYuD4YGmRKkk4WTV_slY68upm06xojpzQLs_resmmSc-WmkkRMgmuXaOxQr5oqZEFFqC3XLU3LAQkmOjMfJk4DWYWBrT-WzkfRJLmXhi3_DH7xh4IQ6t6Patumr-DT70FLySntRsvGS-wcI9U_w39gfGupOU6ytZFN_0lcNrYWR_0K_IjD_lmEUPdywFNs1_EbrIFSPo9pKZRveo1HLcSEatZju_JGqIT0lUQ0nZDIximnODr7w217fA_Vq9pLoMZw3AvT42vQqeg3jqoROF_fkz43fMmCNdZlhLuRUQ_IjZ5qmgKEaodtM8ZtgvB0qJNn_5NzX7ArreV-XQpOf8TxOvIWwmM4C9Ra3-Uo0CDrgIwxxtW9QjnlLx__Nb_Pcvf63dTtvt8y6FLFki3eeA_Q0IC4v0oKRQAVd1BtybbTMYMojXsrc1WElijhfDvybG04y6oWvh0GWx97FYk2bx3bTTi5EB-tXmnD12V2Jigw1e1x4rWpFh28A5eO6o5ymX1KRFdgG2nV45__NmJoZxmgWFFmTkNQSpHgl05NRRzhbcIrAzfAFnMQxdzrOCg4omRzf3yygQEBvuzpfThoZr3eaDdMCtaUuS_eUABIFXAYsRQpI33nhK4ac11S_m7k_vUCc1OWZ7mVLodyVqF3b3vqDIHw-EFNppSUUlpUzeLN2Q\",\"DataProtected\":true}"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/Fakes/FakeRegisterNewUserCommand.cs",
    "content": "using AutoBogus;\n\nnamespace Integration.Test.Fakes;\n\nusing global::Identity.Identity.Features.RegisteringNewUser.V1;\n\npublic class FakeRegisterNewUserCommand : AutoFaker<RegisterNewUser>\n{\n    public FakeRegisterNewUserCommand()\n    {\n        RuleFor(r => r.Username, x => \"TestMyUser\");\n        RuleFor(r => r.Password, _ => \"Password@123\");\n        RuleFor(r => r.ConfirmPassword, _ => \"Password@123\");\n        RuleFor(r => r.Email, _ => \"test@test.com\");\n    }\n}"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/Identity/Features/RegisterNewUserTests.cs",
    "content": "using BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.TestBase;\nusing FluentAssertions;\nusing Identity.Api;\nusing Identity.Data;\nusing Integration.Test.Fakes;\nusing Xunit;\n\nnamespace Integration.Test.Identity.Features;\n\npublic class RegisterNewUserTests : IdentityIntegrationTestBase\n{\n    public RegisterNewUserTests(TestWriteFixture<Program, IdentityContext> integrationTestFactory)\n        : base(integrationTestFactory) { }\n\n    [Fact]\n    public async Task should_create_new_user_to_db_and_publish_message_to_broker()\n    {\n        // Arrange\n        var command = new FakeRegisterNewUserCommand().Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.Username.Should().Be(command.Username);\n\n        (await Fixture.WaitForPublishing<UserCreated>()).Should().Be(true);\n    }\n}\n"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/IdentityIntegrationTestBase.cs",
    "content": "using BuildingBlocks.TestBase;\nusing Identity.Api;\nusing Identity.Data;\nusing Xunit;\n\nnamespace Integration.Test;\n\n[Collection(IntegrationTestCollection.Name)]\npublic class IdentityIntegrationTestBase : TestWriteBase<Program, IdentityContext>\n{\n    public IdentityIntegrationTestBase(TestWriteFixture<Program, IdentityContext> integrationTestFactory)\n        : base(integrationTestFactory)\n    {\n    }\n}\n\n[CollectionDefinition(Name)]\npublic class IntegrationTestCollection : ICollectionFixture<TestWriteFixture<Program, IdentityContext>>\n{\n    public const string Name = \"Identity Integration Test\";\n}"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/IdentityTestDataSeeder.cs",
    "content": "using BuildingBlocks.Constants;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.EFCore;\nusing Identity.Data.Seed;\nusing Identity.Identity.Constants;\nusing Identity.Identity.Models;\nusing Microsoft.AspNetCore.Identity;\n\nnamespace Integration.Test;\n\npublic class IdentityTestDataSeeder(\n    UserManager<User> userManager,\n    RoleManager<Role> roleManager,\n    IEventDispatcher eventDispatcher\n)\n    : ITestDataSeeder\n{\n    public async Task SeedAllAsync()\n    {\n        await SeedRoles();\n        await SeedUsers();\n    }\n\n    private async Task SeedRoles()\n    {\n        if (await roleManager.RoleExistsAsync(IdentityConstant.Role.Admin) == false)\n        {\n            await roleManager.CreateAsync(new Role { Name = IdentityConstant.Role.Admin });\n        }\n\n        if (await roleManager.RoleExistsAsync(IdentityConstant.Role.User) == false)\n        {\n            await roleManager.CreateAsync(new Role { Name = IdentityConstant.Role.User });\n        }\n    }\n\n    private async Task SeedUsers()\n    {\n        if (await userManager.FindByNameAsync(\"samh\") == null)\n        {\n            var result = await userManager.CreateAsync(InitialData.Users.First(), \"Admin@123456\");\n\n            if (result.Succeeded)\n            {\n                await userManager.AddToRoleAsync(InitialData.Users.First(), IdentityConstant.Role.Admin);\n\n                await eventDispatcher.SendAsync(new UserCreated(InitialData.Users.First().Id, InitialData.Users.First().FirstName + \" \" + InitialData.Users.First().LastName, InitialData.Users.First().PassPortNumber));\n            }\n        }\n\n        if (await userManager.FindByNameAsync(\"meysamh2\") == null)\n        {\n            var result = await userManager.CreateAsync(InitialData.Users.Last(), \"User@123456\");\n\n            if (result.Succeeded)\n            {\n                await userManager.AddToRoleAsync(InitialData.Users.Last(), IdentityConstant.Role.User);\n\n                await eventDispatcher.SendAsync(new UserCreated(InitialData.Users.Last().Id, InitialData.Users.Last().FirstName + \" \" + InitialData.Users.Last().LastName, InitialData.Users.Last().PassPortNumber));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/Integration.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Identity.Api\\Identity.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Identity/tests/IntegrationTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Identity/tests/PerformanceTest/.openapi-generator/FILES",
    "content": ".openapi-generator-ignore\nREADME.md\nscript.js\n"
  },
  {
    "path": "src/Services/Identity/tests/PerformanceTest/.openapi-generator/VERSION",
    "content": "6.6.0-SNAPSHOT\n"
  },
  {
    "path": "src/Services/Identity/tests/PerformanceTest/.openapi-generator-ignore",
    "content": "# OpenAPI Generator Ignore\n# Generated by openapi-generator https://github.com/openapitools/openapi-generator\n\n# Use this file to prevent files from being overwritten by the generator.\n# The patterns follow closely to .gitignore or .dockerignore.\n\n# As an example, the C# client generator defines ApiClient.cs.\n# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:\n#ApiClient.cs\n\n# You can match any string of characters against a directory, file or extension with a single asterisk (*):\n#foo/*/qux\n# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux\n\n# You can recursively match patterns against a directory, file or extension with a double asterisk (**):\n#foo/**/qux\n# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux\n\n# You can also negate patterns with an exclamation (!).\n# For example, you can ignore all files in a docs folder with the file extension .md:\n#docs/*.md\n# Then explicitly reverse the ignore rule for a single file:\n#!docs/README.md\n"
  },
  {
    "path": "src/Services/Identity/tests/PerformanceTest/README.md",
    "content": "# Generated k6 script\n\nThe `script.js` file contains most of the Swagger/OpenAPI specification and you can customize it to your needs.\n\nGlobal header variables are defined at the top of the file, like `api_key`. Each path in the specification is converted into a [group](https://docs.k6.io/docs/tags-and-groups) in k6 and each group contains all the request methods related to that path. Path and query parameters are extracted from the specification and put at the start of the group. The URL is constructed from the base URL plus path and query.\n\nIf the Swagger/OpenAPI specification used as the input spec contains examples at parameter level, those will be extracted and utilized as parameter values. The `handleParamValue` custom Mustache lambda registered for use in the K6 `script.mustache` template handles the conditional checks, formatting, and outputting of parameter values. If a given parameter has value specified – either in `example` or `examples` field, defined at the parameter level – that value will be used. For list (`examples`), entire list will be output in the generated script and the first element from that list will be assigned as parameter value. If a given parameter does not have an example defined, a placeholder value with `TODO_EDIT_THE_` prefix will be generated for that parameter, and you will have to assign a value before you can run the script. In other words, you can now generate K6 test scripts which are ready to run, provided the Swagger/OpenAPI specification used as the input spec contains examples for all of the path/query parameters; see `modules/openapi-generator/src/test/resources/3_0/examples.yaml` for an example of such specification, and https://swagger.io/docs/specification/adding-examples/ for more information about adding examples.\n\nk6 specific parameters are in the [`params`](https://docs.k6.io/docs/params-k6http) object, and `body` contains the [request](https://docs.k6.io/docs/http-requests) body which is in the form of `identifier: type`, which the `type` should be substituted by a proper value. Then goes the request and the check.\n\n[Check](https://docs.k6.io/docs/checks) are like asserts but differ in that they don't halt execution, instead they just store the result of the check, pass or fail, and let the script execution continue.\n\nEach request is always followed by a 0.1 second [sleep](https://docs.k6.io/docs/sleep-t-1) to prevent the script execution from flooding the system with too many requests simultaneously.\n\nNote that the default iteration count and VU count is 1. So each request in each group will be executed once. For more information, see the [k6 options](https://docs.k6.io/docs/options).\n"
  },
  {
    "path": "src/Services/Identity/tests/PerformanceTest/script.js",
    "content": "/*\n * APIs\n * An example application with OpenAPI, Swashbuckle, and API versioning.\n *\n * OpenAPI spec version: 1.0\n * Contact:\n *\n * NOTE: This class is auto generated by OpenAPI Generator.\n * https://github.com/OpenAPITools/openapi-generator\n *\n * OpenAPI generator version: 6.6.0-SNAPSHOT\n */\n\n\nimport http from \"k6/http\";\nimport { group, check, sleep } from \"k6\";\n\nconst BASE_URL = \"/\";\n// Sleep duration between successive requests.\n// You might want to edit the value of this variable or remove calls to the sleep function on the script.\nconst SLEEP_DURATION = 0.1;\n// Global variables should be initialized.\n\nexport default function() {\n    group(\"/api/v1/identity/register-user\", () => {\n\n        // Request No. 1: RegisterUser\n        {\n            let url = BASE_URL + `/api/v1/identity/register-user`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"firstName\": \"string\", \"lastName\": \"string\", \"username\": \"string\", \"email\": \"string\", \"password\": \"string\", \"confirmPassword\": \"string\", \"passportNumber\": \"string\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n}\n"
  },
  {
    "path": "src/Services/Identity/tests/tests.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"IntegrationTest\\Integration.Test.csproj\", \"{76FE2BD0-B242-45DC-8361-084920CDEBB4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{76FE2BD0-B242-45DC-8361-084920CDEBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{76FE2BD0-B242-45DC-8361-084920CDEBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{76FE2BD0-B242-45DC-8361-084920CDEBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{76FE2BD0-B242-45DC-8361-084920CDEBB4}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Services/Passenger/Dockerfile",
    "content": "# ---------- Build Stage ----------\nFROM mcr.microsoft.com/dotnet/sdk:10.0 AS build\nWORKDIR /src\n\n# Copy solution-level files\nCOPY .editorconfig .\nCOPY global.json .\nCOPY Directory.Build.props .\n\n# Copy project files first (better Docker layer caching)\nCOPY src/BuildingBlocks/BuildingBlocks.csproj src/BuildingBlocks/\nCOPY src/Services/Passenger/src/Passenger/Passenger.csproj src/Services/Passenger/src/Passenger/\nCOPY src/Services/Passenger/src/Passenger.Api/Passenger.Api.csproj src/Services/Passenger/src/Passenger.Api/\nCOPY src/Aspire/src/ServiceDefaults/ServiceDefaults.csproj src/Aspire/src/ServiceDefaults/\n\n# Restore dependencies\nRUN dotnet restore src/Services/Passenger/src/Passenger.Api/Passenger.Api.csproj\n\n# Copy remaining source code\nCOPY src ./src\n\n# Publish (build included)\nRUN dotnet publish src/Services/Passenger/src/Passenger.Api/Passenger.Api.csproj \\\n    -c Release \\\n    -o /app/publish \\\n    --no-restore\n\n# ---------- Runtime Stage ----------\nFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime\nWORKDIR /app\n\nCOPY --from=build /app/publish .\n\nENV ASPNETCORE_URLS=http://+:80\nENV ASPNETCORE_ENVIRONMENT=docker\n\nEXPOSE 80\n\nENTRYPOINT [\"dotnet\", \"Passenger.Api.dll\"]"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Unit.Test\")]\n[assembly: InternalsVisibleTo(\"Integration.Test\")]\n[assembly: InternalsVisibleTo(\"EndToEnd.Test\")]"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/Configurations/PassengerConfiguration.cs",
    "content": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace Passenger.Data.Configurations;\n\nusing Passengers.ValueObjects;\n\npublic class PassengerConfiguration : IEntityTypeConfiguration<Passengers.Models.Passenger>\n{\n    public void Configure(EntityTypeBuilder<Passengers.Models.Passenger> builder)\n    {\n        builder.ToTable(nameof(Passengers.Models.Passenger));\n\n        builder.HasKey(r => r.Id);\n        builder.Property(r => r.Id).ValueGeneratedNever()\n            .HasConversion<Guid>(passengerId => passengerId.Value, dbId => PassengerId.Of(dbId));\n\n        builder.Property(r => r.Version).IsConcurrencyToken();\n\n        builder.OwnsOne(\n            x => x.Name,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Passengers.Models.Passenger.Name))\n                    .HasMaxLength(50)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.PassportNumber,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Passengers.Models.Passenger.PassportNumber))\n                    .HasMaxLength(10)\n                    .IsRequired();\n            }\n        );\n\n        builder.OwnsOne(\n            x => x.Age,\n            a =>\n            {\n                a.Property(p => p.Value)\n                    .HasColumnName(nameof(Passengers.Models.Passenger.Age))\n                    .HasMaxLength(3)\n                    .IsRequired();\n            }\n        );\n\n        builder.Property(x => x.PassengerType)\n            .IsRequired()\n            .HasDefaultValue(Passengers.Enums.PassengerType.Unknown)\n            .HasConversion(\n                x => x.ToString(),\n                x => (Passengers.Enums.PassengerType)Enum.Parse(typeof(Passengers.Enums.PassengerType), x));\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/DesignTimeDbContextFactory.cs",
    "content": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Design;\n\nnamespace Passenger.Data;\n\npublic class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<PassengerDbContext>\n{\n    public PassengerDbContext CreateDbContext(string[] args)\n    {\n        var builder = new DbContextOptionsBuilder<PassengerDbContext>();\n\n        builder.UseNpgsql(\"Server=localhost;Port=5432;Database=passenger;User Id=postgres;Password=postgres;Include Error Detail=true\")\n            .UseSnakeCaseNamingConvention();\n        return new PassengerDbContext(builder.Options);\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/Migrations/20230611213031_initial.Designer.cs",
    "content": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Migrations;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\nusing Passenger.Data;\n\n#nullable disable\n\nnamespace Passenger.Data.Migrations\n{\n    [DbContext(typeof(PassengerDbContext))]\n    [Migration(\"20230611213031_initial\")]\n    partial class initial\n    {\n        /// <inheritdoc />\n        protected override void BuildTargetModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"7.0.2\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Passenger.Passengers.Models.Passenger\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"PassengerType\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"passenger_type\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_passenger\");\n\n                    b.ToTable(\"passenger\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Passenger.Passengers.Models.Passenger\", b =>\n                {\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.Age\", \"Age\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<int>(\"Value\")\n                                .HasMaxLength(3)\n                                .HasColumnType(\"integer\")\n                                .HasColumnName(\"age\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.PassportNumber\", \"PassportNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(10)\n                                .HasColumnType(\"character varying(10)\")\n                                .HasColumnName(\"passport_number\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.Navigation(\"Age\");\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n\n                    b.Navigation(\"PassportNumber\")\n                        .IsRequired();\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/Migrations/20230611213031_initial.cs",
    "content": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Passenger.Data.Migrations\n{\n    /// <inheritdoc />\n    public partial class initial : Migration\n    {\n        /// <inheritdoc />\n        protected override void Up(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.CreateTable(\n                name: \"passenger\",\n                columns: table => new\n                {\n                    id = table.Column<Guid>(type: \"uuid\", nullable: false),\n                    passportnumber = table.Column<string>(name: \"passport_number\", type: \"character varying(10)\", maxLength: 10, nullable: false),\n                    name = table.Column<string>(type: \"character varying(50)\", maxLength: 50, nullable: false),\n                    passengertype = table.Column<string>(name: \"passenger_type\", type: \"text\", nullable: false, defaultValue: \"Unknown\"),\n                    age = table.Column<int>(type: \"integer\", maxLength: 3, nullable: true),\n                    createdat = table.Column<DateTime>(name: \"created_at\", type: \"timestamp with time zone\", nullable: true),\n                    createdby = table.Column<long>(name: \"created_by\", type: \"bigint\", nullable: true),\n                    lastmodified = table.Column<DateTime>(name: \"last_modified\", type: \"timestamp with time zone\", nullable: true),\n                    lastmodifiedby = table.Column<long>(name: \"last_modified_by\", type: \"bigint\", nullable: true),\n                    isdeleted = table.Column<bool>(name: \"is_deleted\", type: \"boolean\", nullable: false),\n                    version = table.Column<long>(type: \"bigint\", nullable: false)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"pk_passenger\", x => x.id);\n                });\n        }\n\n        /// <inheritdoc />\n        protected override void Down(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.DropTable(\n                name: \"passenger\");\n        }\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/Migrations/PassengerDbContextModelSnapshot.cs",
    "content": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;\nusing Passenger.Data;\n\n#nullable disable\n\nnamespace Passenger.Data.Migrations\n{\n    [DbContext(typeof(PassengerDbContext))]\n    partial class PassengerDbContextModelSnapshot : ModelSnapshot\n    {\n        protected override void BuildModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"7.0.2\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 63);\n\n            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);\n\n            modelBuilder.Entity(\"Passenger.Passengers.Models.Passenger\", b =>\n                {\n                    b.Property<Guid>(\"Id\")\n                        .HasColumnType(\"uuid\")\n                        .HasColumnName(\"id\");\n\n                    b.Property<DateTime?>(\"CreatedAt\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"created_at\");\n\n                    b.Property<long?>(\"CreatedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"created_by\");\n\n                    b.Property<bool>(\"IsDeleted\")\n                        .HasColumnType(\"boolean\")\n                        .HasColumnName(\"is_deleted\");\n\n                    b.Property<DateTime?>(\"LastModified\")\n                        .HasColumnType(\"timestamp with time zone\")\n                        .HasColumnName(\"last_modified\");\n\n                    b.Property<long?>(\"LastModifiedBy\")\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"last_modified_by\");\n\n                    b.Property<string>(\"PassengerType\")\n                        .IsRequired()\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"text\")\n                        .HasDefaultValue(\"Unknown\")\n                        .HasColumnName(\"passenger_type\");\n\n                    b.Property<long>(\"Version\")\n                        .IsConcurrencyToken()\n                        .HasColumnType(\"bigint\")\n                        .HasColumnName(\"version\");\n\n                    b.HasKey(\"Id\")\n                        .HasName(\"pk_passenger\");\n\n                    b.ToTable(\"passenger\", (string)null);\n                });\n\n            modelBuilder.Entity(\"Passenger.Passengers.Models.Passenger\", b =>\n                {\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.Age\", \"Age\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<int>(\"Value\")\n                                .HasMaxLength(3)\n                                .HasColumnType(\"integer\")\n                                .HasColumnName(\"age\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.Name\", \"Name\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(50)\n                                .HasColumnType(\"character varying(50)\")\n                                .HasColumnName(\"name\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.OwnsOne(\"Passenger.Passengers.ValueObjects.PassportNumber\", \"PassportNumber\", b1 =>\n                        {\n                            b1.Property<Guid>(\"PassengerId\")\n                                .HasColumnType(\"uuid\")\n                                .HasColumnName(\"id\");\n\n                            b1.Property<string>(\"Value\")\n                                .IsRequired()\n                                .HasMaxLength(10)\n                                .HasColumnType(\"character varying(10)\")\n                                .HasColumnName(\"passport_number\");\n\n                            b1.HasKey(\"PassengerId\")\n                                .HasName(\"pk_passenger\");\n\n                            b1.ToTable(\"passenger\");\n\n                            b1.WithOwner()\n                                .HasForeignKey(\"PassengerId\")\n                                .HasConstraintName(\"fk_passenger_passenger_id\");\n                        });\n\n                    b.Navigation(\"Age\");\n\n                    b.Navigation(\"Name\")\n                        .IsRequired();\n\n                    b.Navigation(\"PassportNumber\")\n                        .IsRequired();\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/PassengerDbContext.cs",
    "content": "using System.Reflection;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Web;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Passenger.Data;\n\nusing Microsoft.Extensions.Logging;\n\npublic sealed class PassengerDbContext : AppDbContextBase\n{\n    public PassengerDbContext(DbContextOptions<PassengerDbContext> options,\n        ICurrentUserProvider? currentUserProvider = null, ILogger<PassengerDbContext>? logger = null) :\n        base(options, currentUserProvider, logger)\n    {\n    }\n\n    public DbSet<Passengers.Models.Passenger> Passengers => Set<Passengers.Models.Passenger>();\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());\n        base.OnModelCreating(builder);\n        builder.FilterSoftDeletedProperties();\n        builder.ToSnakeCaseTables();\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/PassengerReadDbContext.cs",
    "content": "using BuildingBlocks.Mongo;\nusing Humanizer;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace Passenger.Data;\n\nusing Passengers.Models;\n\npublic class PassengerReadDbContext : MongoDbContext\n{\n    public PassengerReadDbContext(IOptions<MongoOptions> options) : base(options)\n    {\n        Passenger = GetCollection<PassengerReadModel>(nameof(Passenger).Underscore());\n    }\n\n    public IMongoCollection<PassengerReadModel> Passenger { get; }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Data/readme.md",
    "content": "dotnet ef migrations add initial --context PassengerDbContext -o \"Data\\Migrations\"\ndotnet ef database update --context PassengerDbContext\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/InvalidAgeException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Passenger.Exceptions;\n\npublic class InvalidAgeException : DomainException\n{\n    public InvalidAgeException() : base(\"Age Cannot be null or negative\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/InvalidNameException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Passenger.Exceptions;\n\npublic class InvalidNameException : DomainException\n{\n    public InvalidNameException() : base(\"Name cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/InvalidPassengerIdException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Passenger.Exceptions;\n\nusing System;\n\npublic class InvalidPassengerIdException : DomainException\n{\n    public InvalidPassengerIdException(Guid passengerId)\n        : base($\"PassengerId: '{passengerId}' is invalid.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/InvalidPassportNumberException.cs",
    "content": "using SmartCharging.Infrastructure.Exceptions;\n\nnamespace Passenger.Exceptions;\n\npublic class InvalidPassportNumberException : DomainException\n{\n    public InvalidPassportNumberException() : base(\"Passport number cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/PassengerAlreadyExist.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Passenger.Exceptions;\n\npublic class PassengerNotExist : AppException\n{\n    public PassengerNotExist() : base(\"Please register before!\", HttpStatusCode.NotFound)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Exceptions/PassengerNotFoundException.cs",
    "content": "using System.Net;\nusing BuildingBlocks.Exception;\n\nnamespace Passenger.Exceptions;\n\npublic class PassengerNotFoundException : AppException\n{\n    public PassengerNotFoundException() : base(\"Passenger not found!\", HttpStatusCode.NotFound)\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Extensions/Infrastructure/InfrastructureExtensions.cs",
    "content": "using BuildingBlocks.Core;\nusing BuildingBlocks.EFCore;\nusing BuildingBlocks.Exception;\nusing BuildingBlocks.HealthCheck;\nusing BuildingBlocks.Jwt;\nusing BuildingBlocks.Mapster;\nusing BuildingBlocks.MassTransit;\nusing BuildingBlocks.Mongo;\nusing BuildingBlocks.OpenApi;\nusing BuildingBlocks.OpenTelemetryCollector;\nusing BuildingBlocks.PersistMessageProcessor;\nusing BuildingBlocks.ProblemDetails;\nusing BuildingBlocks.Web;\nusing Figgle;\nusing Figgle.Fonts;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Passenger.Data;\nusing Passenger.GrpcServer.Services;\nusing ServiceDefaults;\n\nnamespace Passenger.Extensions.Infrastructure;\n\npublic static class InfrastructureExtensions\n{\n    public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder)\n    {\n        var configuration = builder.Configuration;\n        var env = builder.Environment;\n\n        builder.AddServiceDefaults();\n\n        builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();\n        builder.Services.AddScoped<IEventMapper, PassengerEventMapper>();\n        builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();\n\n        builder.Services.Configure<ApiBehaviorOptions>(\n            options =>\n            {\n                options.SuppressModelStateInvalidFilter = true;\n            });\n\n        var appOptions = builder.Services.GetOptions<AppOptions>(nameof(AppOptions));\n        Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));\n\n        builder.AddPersistMessageProcessor(nameof(PersistMessage));\n        builder.AddCustomDbContext<PassengerDbContext>(nameof(Passenger));\n        builder.AddMongoDbContext<PassengerReadDbContext>();\n\n        builder.Services.AddJwt();\n        builder.Services.AddEndpointsApiExplorer();\n        builder.Services.AddAspnetOpenApi();\n        builder.Services.AddCustomVersioning();\n        builder.Services.AddCustomMediatR();\n        builder.Services.AddValidatorsFromAssembly(typeof(PassengerRoot).Assembly);\n        builder.Services.AddProblemDetails();\n        builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly);\n        builder.Services.AddHttpContextAccessor();\n        builder.Services.AddCustomMassTransit(env, TransportType.RabbitMq, typeof(PassengerRoot).Assembly);\n\n        builder.Services.AddGrpc(\n            options =>\n            {\n                options.Interceptors.Add<GrpcExceptionInterceptor>();\n            });\n\n        return builder;\n    }\n\n\n    public static WebApplication UseInfrastructure(this WebApplication app)\n    {\n        var env = app.Environment;\n        var appOptions = app.GetOptions<AppOptions>(nameof(AppOptions));\n\n        app.UseAuthentication();\n        app.UseAuthorization();\n\n        app.UseServiceDefaults();\n\n        app.UseCustomProblemDetails();\n\n        app.UseCorrelationId();\n        app.UseMigration<PassengerDbContext>();\n        app.MapGrpcService<PassengerGrpcServices>();\n        app.MapGet(\"/\", x => x.Response.WriteAsync(appOptions.Name));\n\n        if (env.IsDevelopment())\n        {\n            app.UseAspnetOpenApi();\n        }\n\n        return app;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Extensions/Infrastructure/MediatRExtensions.cs",
    "content": "using BuildingBlocks.EFCore;\nusing BuildingBlocks.Logging;\nusing BuildingBlocks.Validation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Passenger.Extensions.Infrastructure;\n\npublic static class MediatRExtensions\n{\n    public static IServiceCollection AddCustomMediatR(this IServiceCollection services)\n    {\n        services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(PassengerRoot).Assembly));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));\n        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/GrpcServer/Protos/passenger.proto",
    "content": "syntax = \"proto3\";\n\npackage passenger;\n\nservice PassengerGrpcService {\n\n  rpc GetById (GetByIdRequest) returns (GetPassengerByIdResult);\n}\n\nmessage GetByIdRequest {\n  string Id = 1;\n}\n\nmessage GetPassengerByIdResult {\n   PassengerResponse PassengerDto = 1;\n}\n\nmessage PassengerResponse {\n  string Id = 1;\n  string Name = 2;\n  string PassportNumber = 3;\n  PassengerType PassengerType = 4;\n  int32 Age = 5;\n  string Email = 6;\n}\n\n\n    enum PassengerType {\n        PASSENGER_TYPE_UNKNOWN = 0;\n        PASSENGER_TYPE_MALE = 1;\n        PASSENGER_TYPE_FEMALE = 2;\n        PASSENGER_TYPE_BABY = 3;\n    }\n\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/GrpcServer/Services/PassengerGrpcServices.cs",
    "content": "using Grpc.Core;\nusing MediatR;\n\nnamespace Passenger.GrpcServer.Services;\n\nusing Mapster;\nusing Passengers.Features.GettingPassengerById.V1;\nusing GetPassengerByIdResult = Passenger.GetPassengerByIdResult;\n\npublic class PassengerGrpcServices : PassengerGrpcService.PassengerGrpcServiceBase\n{\n    private readonly IMediator _mediator;\n\n    public PassengerGrpcServices(IMediator mediator)\n    {\n        _mediator = mediator;\n    }\n\n    public override async Task<GetPassengerByIdResult> GetById(GetByIdRequest request, ServerCallContext context)\n    {\n        var result = await _mediator.Send(new GetPassengerById(new Guid(request.Id)));\n        return result?.Adapt<GetPassengerByIdResult>();\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/PassengerCreatedDomainEvent.cs",
    "content": "namespace Passenger.Identity.Consumers.RegisteringNewUser.V1;\n\nusing BuildingBlocks.Core.Event;\n\npublic record PassengerCreatedDomainEvent(Guid Id, string Name, string PassportNumber, bool IsDeleted = false) : IDomainEvent;"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/RegisterNewUser.cs",
    "content": "namespace Passenger.Identity.Consumers.RegisteringNewUser.V1;\n\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Humanizer;\nusing MassTransit;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Passengers.ValueObjects;\n\npublic class RegisterNewUserHandler : IConsumer<UserCreated>\n{\n    private readonly PassengerDbContext _passengerDbContext;\n    private readonly IEventDispatcher _eventDispatcher;\n    private readonly ILogger<RegisterNewUserHandler> _logger;\n    private readonly AppOptions _options;\n\n    public RegisterNewUserHandler(PassengerDbContext passengerDbContext,\n        IEventDispatcher eventDispatcher,\n        ILogger<RegisterNewUserHandler> logger,\n        IOptions<AppOptions> options)\n    {\n        _passengerDbContext = passengerDbContext;\n        _eventDispatcher = eventDispatcher;\n        _logger = logger;\n        _options = options.Value;\n    }\n\n    public async Task Consume(ConsumeContext<UserCreated> context)\n    {\n        Guard.Against.Null(context.Message, nameof(UserCreated));\n\n        _logger.LogInformation($\"consumer for {nameof(UserCreated).Underscore()} in {_options.Name}\");\n\n        var passengerExist =\n            await _passengerDbContext.Passengers.AnyAsync(x => x.PassportNumber.Value == context.Message.PassportNumber);\n\n        if (passengerExist)\n        {\n            return;\n        }\n\n        var passenger = Passengers.Models.Passenger.Create(PassengerId.Of(NewId.NextGuid()), Name.Of(context.Message.Name),\n            PassportNumber.Of(context.Message.PassportNumber));\n\n        await _passengerDbContext.AddAsync(passenger);\n\n        await _passengerDbContext.SaveChangesAsync();\n\n        await _eventDispatcher.SendAsync(\n            new PassengerCreatedDomainEvent(passenger.Id, passenger.Name, passenger.PassportNumber),\n            typeof(IInternalCommand));\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passenger.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.AspNetCore\" Version=\"2.76.0\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"10.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Data\\Migrations\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"GrpcServer\\Protos\\passenger.proto\" GrpcServices=\"Both\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\Aspire\\src\\ServiceDefaults\\ServiceDefaults.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\BuildingBlocks\\BuildingBlocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/PassengerEventMapper.cs",
    "content": "using BuildingBlocks.Contracts.EventBus.Messages;\nusing BuildingBlocks.Core;\nusing BuildingBlocks.Core.Event;\n\nnamespace Passenger;\n\nusing Identity.Consumers.RegisteringNewUser.V1;\nusing Passengers.Features.CompletingRegisterPassenger.V1;\n\npublic sealed class PassengerEventMapper : IEventMapper\n{\n    public IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            PassengerRegistrationCompletedDomainEvent e => new PassengerRegistrationCompleted(e.Id),\n            PassengerCreatedDomainEvent e => new PassengerCreated(e.Id),\n            _ => null\n        };\n    }\n\n    public IInternalCommand? MapToInternalCommand(IDomainEvent @event)\n    {\n        return @event switch\n        {\n            PassengerRegistrationCompletedDomainEvent e => new CompleteRegisterPassengerMongoCommand(e.Id, e.PassportNumber, e.Name, e.PassengerType,\n                e.Age, e.IsDeleted),\n            PassengerCreatedDomainEvent e => new CompleteRegisterPassengerMongoCommand(e.Id, e.PassportNumber, e.Name, Passengers.Enums.PassengerType.Unknown,\n                0, e.IsDeleted),\n            _ => null\n        };\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/PassengerRoot.cs",
    "content": "namespace Passenger;\n\npublic class PassengerRoot\n{\n\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerDto.cs",
    "content": "namespace Passenger.Passengers.Dtos;\n\npublic record PassengerDto(Guid Id, string Name, string PassportNumber, Enums.PassengerType PassengerType, int Age);"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Enums/PassengerType.cs",
    "content": "namespace Passenger.Passengers.Enums;\n\npublic enum PassengerType\n{\n    Unknown = 0,\n    Male,\n    Female,\n    Baby\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Exceptions/InvalidAgeException.cs",
    "content": "namespace Passenger.Passengers.Exceptions;\n\nusing BuildingBlocks.Exception;\n\npublic class InvalidAgeException : BadRequestException\n{\n    public InvalidAgeException() : base(\"Age Cannot be null or negative\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Exceptions/InvalidNameException.cs",
    "content": "namespace Passenger.Passengers.Exceptions;\n\nusing BuildingBlocks.Exception;\n\n\npublic class InvalidNameException : BadRequestException\n{\n    public InvalidNameException() : base(\"Name cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Exceptions/InvalidPassportNumberException.cs",
    "content": "namespace Passenger.Passengers.Exceptions;\n\nusing BuildingBlocks.Exception;\n\n\npublic class InvalidPassportNumberException : BadRequestException\n{\n    public InvalidPassportNumberException() : base(\"Passport number cannot be empty or whitespace.\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Exceptions/PassengerAlreadyExist.cs",
    "content": "namespace Passenger.Passengers.Exceptions;\n\nusing BuildingBlocks.Exception;\n\npublic class PassengerNotExist : BadRequestException\n{\n    public PassengerNotExist(string code = default) : base(\"Please register before!\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Exceptions/PassengerNotFoundException.cs",
    "content": "namespace Passenger.Passengers.Exceptions;\n\nusing BuildingBlocks.Exception;\n\npublic class PassengerNotFoundException : NotFoundException\n{\n    public PassengerNotFoundException(string code = default) : base(\"Passenger not found!\")\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassenger.cs",
    "content": "namespace Passenger.Passengers.Features.CompletingRegisterPassenger.V1;\n\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing BuildingBlocks.Web;\nusing Data;\nusing Dtos;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing Exceptions;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MassTransit;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.EntityFrameworkCore;\nusing ValueObjects;\n\npublic record CompleteRegisterPassenger(string PassportNumber, Enums.PassengerType PassengerType, int Age)\n    : ICommand<CompleteRegisterPassengerResult>,\n        IInternalCommand\n{\n    public Guid Id { get; init; } = NewId.NextGuid();\n}\n\npublic record PassengerRegistrationCompletedDomainEvent(\n    Guid Id,\n    string Name,\n    string PassportNumber,\n    Enums.PassengerType PassengerType,\n    int Age,\n    bool IsDeleted = false\n) : IDomainEvent;\n\npublic record CompleteRegisterPassengerResult(PassengerDto PassengerDto);\n\npublic record CompleteRegisterPassengerRequestDto(string PassportNumber, Enums.PassengerType PassengerType, int Age);\n\npublic record CompleteRegisterPassengerResponseDto(PassengerDto PassengerDto);\n\npublic class CompleteRegisterPassengerEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder\n            .MapPost(\n                $\"{EndpointConfig.BaseApiPath}/passenger/complete-registration\",\n                async (\n                    CompleteRegisterPassengerRequestDto request,\n                    IMapper mapper,\n                    IMediator mediator,\n                    CancellationToken cancellationToken\n                ) =>\n                {\n                    var command = mapper.Map<CompleteRegisterPassenger>(request);\n\n                    var result = await mediator.Send(command, cancellationToken);\n\n                    var response = result.Adapt<CompleteRegisterPassengerResponseDto>();\n\n                    return Results.Ok(response);\n                }\n            )\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"CompleteRegisterPassenger\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Passenger\").Build())\n            .Produces<CompleteRegisterPassengerResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Complete Register Passenger\")\n            .WithDescription(\"Complete Register Passenger\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class CompleteRegisterPassengerValidator : AbstractValidator<CompleteRegisterPassenger>\n{\n    public CompleteRegisterPassengerValidator()\n    {\n        RuleFor(x => x.PassportNumber).NotNull().WithMessage(\"The PassportNumber is required!\");\n        RuleFor(x => x.Age).GreaterThan(0).WithMessage(\"The Age must be greater than 0!\");\n        RuleFor(x => x.PassengerType)\n            .Must(p =>\n                p.GetType().IsEnum && p == Enums.PassengerType.Baby\n                || p == Enums.PassengerType.Female\n                || p == Enums.PassengerType.Male\n                || p == Enums.PassengerType.Unknown\n            )\n            .WithMessage(\"PassengerType must be Male, Female, Baby or Unknown\");\n    }\n}\n\ninternal class CompleteRegisterPassengerCommandHandler\n    : ICommandHandler<CompleteRegisterPassenger, CompleteRegisterPassengerResult>\n{\n    private readonly IMapper _mapper;\n    private readonly PassengerDbContext _passengerDbContext;\n\n    public CompleteRegisterPassengerCommandHandler(IMapper mapper, PassengerDbContext passengerDbContext)\n    {\n        _mapper = mapper;\n        _passengerDbContext = passengerDbContext;\n    }\n\n    public async Task<CompleteRegisterPassengerResult> Handle(\n        CompleteRegisterPassenger request,\n        CancellationToken cancellationToken\n    )\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var passenger = await _passengerDbContext.Passengers.SingleOrDefaultAsync(\n            x => x.PassportNumber.Value == request.PassportNumber,\n            cancellationToken\n        );\n\n        if (passenger is null)\n        {\n            throw new PassengerNotExist();\n        }\n\n        passenger.CompleteRegistrationPassenger(\n            passenger.Id,\n            passenger.Name,\n            passenger.PassportNumber,\n            request.PassengerType,\n            Age.Of(request.Age)\n        );\n\n        var updatePassenger = _passengerDbContext.Passengers.Update(passenger).Entity;\n\n        var passengerDto = _mapper.Map<PassengerDto>(updatePassenger);\n\n        return new CompleteRegisterPassengerResult(passengerDto);\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassengerMongo.cs",
    "content": "namespace Passenger.Passengers.Features.CompletingRegisterPassenger.V1;\n\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Core.Event;\nusing Data;\nusing MapsterMapper;\nusing MediatR;\nusing Models;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\nusing ValueObjects;\n\npublic record CompleteRegisterPassengerMongoCommand(Guid Id, string PassportNumber, string Name,\n    Enums.PassengerType PassengerType, int Age, bool IsDeleted = false) : InternalCommand;\n\n\ninternal class CompleteRegisterPassengerMongoHandler : ICommandHandler<CompleteRegisterPassengerMongoCommand>\n{\n    private readonly PassengerReadDbContext _passengerReadDbContext;\n    private readonly IMapper _mapper;\n\n    public CompleteRegisterPassengerMongoHandler(\n        PassengerReadDbContext passengerReadDbContext,\n        IMapper mapper)\n    {\n        _passengerReadDbContext = passengerReadDbContext;\n        _mapper = mapper;\n    }\n\n    public async Task<Unit> Handle(CompleteRegisterPassengerMongoCommand request, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(request, nameof(request));\n\n        var passengerReadModel = _mapper.Map<PassengerReadModel>(request);\n\n        var passenger = await _passengerReadDbContext.Passenger.AsQueryable()\n            .FirstOrDefaultAsync(x => x.PassengerId == passengerReadModel.PassengerId && !x.IsDeleted, cancellationToken);\n\n        if (passenger is not null)\n        {\n            await _passengerReadDbContext.Passenger.UpdateOneAsync(\n                x => x.PassengerId == PassengerId.Of(passengerReadModel.PassengerId),\n                Builders<PassengerReadModel>.Update\n                    .Set(x => x.PassengerId, PassengerId.Of(passengerReadModel.PassengerId))\n                    .Set(x => x.Age, passengerReadModel.Age)\n                    .Set(x => x.Name, passengerReadModel.Name)\n                    .Set(x => x.IsDeleted, passengerReadModel.IsDeleted)\n                    .Set(x => x.PassengerType, passengerReadModel.PassengerType)\n                    .Set(x => x.PassportNumber, passengerReadModel.PassportNumber),\n                cancellationToken: cancellationToken);\n        }\n        else\n        {\n            await _passengerReadDbContext.Passenger.InsertOneAsync(passengerReadModel,\n                cancellationToken: cancellationToken);\n        }\n\n        return Unit.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/V1/GetPassengerById.cs",
    "content": "namespace Passenger.Passengers.Features.GettingPassengerById.V1;\n\nusing Ardalis.GuardClauses;\nusing BuildingBlocks.Core.CQRS;\nusing BuildingBlocks.Web;\nusing Duende.IdentityServer.EntityFramework.Entities;\nusing FluentValidation;\nusing Mapster;\nusing MapsterMapper;\nusing MediatR;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\nusing Passenger.Data;\nusing Passenger.Passengers.Dtos;\nusing Passenger.Passengers.Exceptions;\n\npublic record GetPassengerById(Guid Id) : IQuery<GetPassengerByIdResult>;\n\npublic record GetPassengerByIdResult(PassengerDto PassengerDto);\n\npublic record GetPassengerByIdResponseDto(PassengerDto PassengerDto);\n\npublic class GetPassengerByIdEndpoint : IMinimalEndpoint\n{\n    public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)\n    {\n        builder.MapGet($\"{EndpointConfig.BaseApiPath}/passenger/{{id}}\",\n                async (Guid id, IMediator mediator, CancellationToken cancellationToken) =>\n                {\n                    var result = await mediator.Send(new GetPassengerById(id), cancellationToken);\n\n                    var response = result.Adapt<GetPassengerByIdResponseDto>();\n\n                    return Results.Ok(response);\n                })\n            .RequireAuthorization(nameof(ApiScope))\n            .WithName(\"GetPassengerById\")\n            .WithApiVersionSet(builder.NewApiVersionSet(\"Passenger\").Build())\n            .Produces<GetPassengerByIdResponseDto>()\n            .ProducesProblem(StatusCodes.Status400BadRequest)\n            .WithSummary(\"Get Passenger By Id\")\n            .WithDescription(\"Get Passenger By Id\")\n            .WithOpenApi()\n            .HasApiVersion(1.0);\n\n        return builder;\n    }\n}\n\npublic class GetPassengerByIdValidator : AbstractValidator<GetPassengerById>\n{\n    public GetPassengerByIdValidator()\n    {\n        RuleFor(x => x.Id).NotNull().WithMessage(\"Id is required!\");\n    }\n}\n\ninternal class GetPassengerByIdHandler : IQueryHandler<GetPassengerById, GetPassengerByIdResult>\n{\n    private readonly IMapper _mapper;\n    private readonly PassengerReadDbContext _passengerReadDbContext;\n\n    public GetPassengerByIdHandler(IMapper mapper, PassengerReadDbContext passengerReadDbContext)\n    {\n        _mapper = mapper;\n        _passengerReadDbContext = passengerReadDbContext;\n    }\n\n    public async Task<GetPassengerByIdResult> Handle(GetPassengerById query, CancellationToken cancellationToken)\n    {\n        Guard.Against.Null(query, nameof(query));\n\n        var passenger =\n            await _passengerReadDbContext.Passenger.AsQueryable()\n                .SingleOrDefaultAsync(x => x.PassengerId == query.Id && x.IsDeleted == false, cancellationToken);\n\n        if (passenger is null)\n        {\n            throw new PassengerNotFoundException();\n        }\n\n        var passengerDto = _mapper.Map<PassengerDto>(passenger);\n\n        return new GetPassengerByIdResult(passengerDto);\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Features/PassengerMappings.cs",
    "content": "using Mapster;\n\nnamespace Passenger.Passengers.Features;\n\nusing CompletingRegisterPassenger.V1;\nusing Dtos;\nusing MassTransit;\nusing Models;\nusing ValueObjects;\n\npublic class PassengerMappings : IRegister\n{\n    public void Register(TypeAdapterConfig config)\n    {\n        config.NewConfig<CompleteRegisterPassengerMongoCommand, PassengerReadModel>()\n        .Map(d => d.Id, s => NewId.NextGuid())\n            .Map(d => d.PassengerId, s => PassengerId.Of(s.Id));\n\n        config.NewConfig<CompleteRegisterPassengerRequestDto, CompleteRegisterPassenger>()\n            .ConstructUsing(x => new CompleteRegisterPassenger(x.PassportNumber, x.PassengerType, x.Age));\n\n        config.NewConfig<PassengerReadModel, PassengerDto>()\n            .ConstructUsing(x => new PassengerDto(x.PassengerId, x.Name, x.PassportNumber, x.PassengerType, x.Age));\n\n        config.NewConfig<Passenger, PassengerDto>()\n            .ConstructUsing(x => new PassengerDto(x.Id.Value, x.Name.Value, x.PassportNumber.Value, x.PassengerType, x.Age.Value));\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Models/Passenger.cs",
    "content": "using BuildingBlocks.Core.Model;\n\nnamespace Passenger.Passengers.Models;\n\nusing Features.CompletingRegisterPassenger.V1;\nusing Identity.Consumers.RegisteringNewUser.V1;\nusing ValueObjects;\n\npublic record Passenger : Aggregate<PassengerId>\n{\n    public PassportNumber PassportNumber { get; private set; } = default!;\n    public Name Name { get; private set; } = default!;\n    public Enums.PassengerType PassengerType { get; private set; }\n    public Age? Age { get; private set; }\n\n    public void CompleteRegistrationPassenger(PassengerId id, Name name, PassportNumber passportNumber,\n        Enums.PassengerType passengerType, Age age, bool isDeleted = false)\n    {\n        this.Id = id;\n        this.Name = name;\n        this.PassportNumber = passportNumber;\n        this.PassengerType = passengerType;\n        this.Age = age;\n        this.IsDeleted = isDeleted;\n\n        var @event = new PassengerRegistrationCompletedDomainEvent(this.Id, this.Name,\n            this.PassportNumber,\n            this.PassengerType, this.Age, this.IsDeleted);\n\n        this.AddDomainEvent(@event);\n    }\n\n\n    public static Passenger Create(PassengerId id, Name name, PassportNumber passportNumber, bool isDeleted = false)\n    {\n        var passenger = new Passenger { Id = id, Name = name, PassportNumber = passportNumber, IsDeleted = isDeleted };\n\n        var @event = new PassengerCreatedDomainEvent(passenger.Id, passenger.Name, passenger.PassportNumber,\n            passenger.IsDeleted);\n\n        passenger.AddDomainEvent(@event);\n\n        return passenger;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/Models/PassengerReadModel.cs",
    "content": "namespace Passenger.Passengers.Models;\n\npublic class PassengerReadModel\n{\n    public required Guid Id { get; init; }\n    public required Guid PassengerId { get; init; }\n    public required string PassportNumber { get; init; }\n    public required string Name { get; init; }\n    public required Enums.PassengerType PassengerType { get; init; }\n    public int Age { get; init; }\n    public required bool IsDeleted { get; init; }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/ValueObjects/Age.cs",
    "content": "namespace Passenger.Passengers.ValueObjects;\n\nusing Exceptions;\n\npublic record Age\n{\n    public int Value { get; }\n\n    private Age(int value)\n    {\n        Value = value;\n    }\n\n    public static Age Of(int value)\n    {\n        if (value <= 0)\n        {\n            throw new InvalidAgeException();\n        }\n\n        return new Age(value);\n    }\n\n    public static implicit operator int(Age age)\n    {\n        return age.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/ValueObjects/Name.cs",
    "content": "namespace Passenger.Passengers.ValueObjects;\n\nusing Passenger.Passengers.Exceptions;\n\npublic record Name\n{\n    public string Value { get; }\n\n    private Name(string value)\n    {\n        Value = value;\n    }\n\n    public static Name Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidNameException();\n        }\n\n        return new Name(value);\n    }\n\n    public static implicit operator string(Name name)\n    {\n        return name.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/ValueObjects/PassengerId.cs",
    "content": "namespace Passenger.Passengers.ValueObjects;\n\nusing System;\nusing Passenger.Exceptions;\n\npublic record PassengerId\n{\n    public Guid Value { get; }\n\n    private PassengerId(Guid value)\n    {\n        Value = value;\n    }\n\n    public static PassengerId Of(Guid value)\n    {\n        if (value == Guid.Empty)\n        {\n            throw new InvalidPassengerIdException(value);\n        }\n\n        return new PassengerId(value);\n    }\n\n    public static implicit operator Guid(PassengerId passengerId)\n    {\n        return passengerId.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger/Passengers/ValueObjects/PassportNumber.cs",
    "content": "namespace Passenger.Passengers.ValueObjects;\n\nusing Passenger.Passengers.Exceptions;\n\npublic record PassportNumber\n{\n    public string Value { get; }\n\n    public override string ToString()\n    {\n        return Value;\n    }\n\n    private PassportNumber(string value)\n    {\n        Value = value;\n    }\n\n    public static PassportNumber Of(string value)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n        {\n            throw new InvalidPassportNumberException();\n        }\n\n        return new PassportNumber(value);\n    }\n\n    public static implicit operator string(PassportNumber passportNumber)\n    {\n        return passportNumber.Value;\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/Passenger.Api.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Passenger\\Passenger.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/Program.cs",
    "content": "using BuildingBlocks.Web;\nusing Passenger;\nusing Passenger.Extensions.Infrastructure;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddMinimalEndpoints(assemblies: typeof(PassengerRoot).Assembly);\nbuilder.AddInfrastructure();\n\nvar app = builder.Build();\n\napp.MapMinimalEndpoints();\napp.UseInfrastructure();\n\napp.Run();\n\nnamespace Passenger.Api\n{\n    public partial class Program\n    {\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/Properties/launchSettings.json",
    "content": "{\n    \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n    \"profiles\": {\n        \"Passenger.Api\": {\n            \"commandName\": \"Project\",\n            \"dotnetRunMessages\": true,\n            \"launchUrl\": \"swagger\",\n            \"launchBrowser\": true,\n            \"applicationUrl\": \"http://localhost:6012;https://localhost:5012\",\n            \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/appsettings.Development.json",
    "content": "{\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/appsettings.docker.json",
    "content": "{\n    \"App\": \"Passenger-Service\",\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=passenger;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=postgres;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://identity:80\",\n        \"Audience\": \"passenger-api\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://mongo:27017\",\n        \"DatabaseName\": \"passenger-db\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"rabbitmq\",\n        \"ExchangeName\": \"passenger\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/appsettings.json",
    "content": "{\n    \"AppOptions\": {\n        \"Name\": \"Passenger-Service\"\n    },\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=passenger;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"MongoOptions\": {\n        \"ConnectionString\": \"mongodb://localhost:27017\",\n        \"DatabaseName\": \"passenger-db\"\n    },\n    \"Jwt\": {\n        \"Authority\": \"http://localhost:6005\",\n        \"Audience\": \"passenger-api\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"passenger\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"HealthOptions\": {\n        \"Enabled\": false\n    },\n    \"ObservabilityOptions\": {\n        \"InstrumentationName\": \"passenger_service\",\n        \"OTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4317\"\n        },\n        \"AspireDashboardOTLPOptions\": {\n            \"OTLPGrpExporterEndpoint\": \"http://localhost:4319\"\n        },\n        \"ZipkinOptions\": {\n            \"HttpExporterEndpoint\": \"http://localhost:9411/api/v2/spans\"\n        },\n        \"JaegerOptions\": {\n            \"OTLPGrpcExporterEndpoint\": \"http://localhost:14317\",\n            \"HttpExporterEndpoint\": \"http://localhost:14268/api/traces\"\n        },\n        \"UsePrometheusExporter\": true,\n        \"UseOTLPExporter\": true,\n        \"UseAspireOTLPExporter\": true,\n        \"UseGrafanaExporter\": false,\n        \"ServiceName\": \"Passenger Service\"\n    },\n    \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "src/Services/Passenger/src/Passenger.Api/appsettings.test.json",
    "content": "{\n    \"Logging\": {\n        \"LogLevel\": {\n            \"Default\": \"Information\"\n        }\n    },\n    \"PostgresOptions\": {\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=passenger_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    },\n    \"RabbitMqOptions\": {\n        \"HostName\": \"localhost\",\n        \"ExchangeName\": \"passenger\",\n        \"UserName\": \"guest\",\n        \"Password\": \"guest\",\n        \"Port\": 5672\n    },\n    \"PersistMessageOptions\": {\n        \"Interval\": 30,\n        \"Enabled\": true,\n        \"ConnectionString\": \"Server=localhost;Port=5432;Database=persist_message_test;User Id=postgres;Password=postgres;Include Error Detail=true\"\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/Fakes/FakeCompleteRegisterPassengerCommand.cs",
    "content": "using AutoBogus;\nusing Passenger.Passengers.Enums;\n\nnamespace Integration.Test.Fakes;\n\nusing global::Passenger.Passengers.Features.CompletingRegisterPassenger.V1;\n\npublic sealed class FakeCompleteRegisterPassengerCommand : AutoFaker<CompleteRegisterPassenger>\n{\n    public FakeCompleteRegisterPassengerCommand(string passportNumber, Guid passengerId)\n    {\n        RuleFor(r => r.Id, _ => passengerId);\n        RuleFor(r => r.PassportNumber, _ => passportNumber);\n        RuleFor(r => r.PassengerType, _ => PassengerType.Male);\n        RuleFor(r => r.Age, _ => 30);\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/Fakes/FakeCompleteRegisterPassengerMongoCommand.cs",
    "content": "namespace Integration.Test.Fakes;\n\nusing AutoBogus;\nusing global::Passenger.Passengers.Enums;\nusing global::Passenger.Passengers.Features.CompletingRegisterPassenger.V1;\nusing MassTransit;\n\npublic class FakeCompleteRegisterPassengerMongoCommand : AutoFaker<CompleteRegisterPassengerMongoCommand>\n{\n    public FakeCompleteRegisterPassengerMongoCommand()\n    {\n        RuleFor(r => r.Id, _ => NewId.NextGuid());\n        RuleFor(r => r.Name, _ => \"Sam\");\n        RuleFor(r => r.PassportNumber, _ => \"123456789\");\n        RuleFor(r => r.Age, _ => 30);\n        RuleFor(r => r.IsDeleted, _ => false);\n        RuleFor(r => r.PassengerType, _ => PassengerType.Male);\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/Integration.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Passenger.Api\\Passenger.Api.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs",
    "content": "using BuildingBlocks.TestBase;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Passenger.Data;\nusing Passenger.Passengers.ValueObjects;\nusing Xunit;\n\nnamespace Integration.Test.Passenger.Features;\n\npublic class CompleteRegisterPassengerTests : PassengerIntegrationTestBase\n{\n    public CompleteRegisterPassengerTests(\n        TestFixture<Program, PassengerDbContext, PassengerReadDbContext> integrationTestFactory\n    )\n        : base(integrationTestFactory) { }\n\n    [Fact]\n    public async Task should_complete_register_passenger_and_update_to_db()\n    {\n        // Arrange\n        var passenger = global::Passenger.Passengers.Models.Passenger.Create(\n            PassengerId.Of(Guid.CreateVersion7()),\n            Name.Of(\"Sam\"),\n            PassportNumber.Of(\"123456789\")\n        );\n\n        await Fixture.InsertAsync(passenger);\n\n        var command = new FakeCompleteRegisterPassengerCommand(passenger.PassportNumber, passenger.Id).Generate();\n\n        // Act\n        var response = await Fixture.SendAsync(command);\n\n        // Assert\n        response.Should().NotBeNull();\n        response?.PassengerDto?.Name.Should().Be(passenger.Name);\n        response?.PassengerDto?.PassportNumber.Should().Be(command.PassportNumber);\n        response?.PassengerDto?.PassengerType.ToString().Should().Be(command.PassengerType.ToString());\n        response?.PassengerDto?.Age.Should().Be(command.Age);\n    }\n}\n"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/Passenger/Features/GetPassengerByIdTests.cs",
    "content": "using System.Threading.Tasks;\nusing BuildingBlocks.TestBase;\nusing FluentAssertions;\nusing Integration.Test.Fakes;\nusing Passenger;\nusing Passenger.Api;\nusing Passenger.Data;\nusing Xunit;\n\nnamespace Integration.Test.Passenger.Features;\n\nusing global::Passenger.Passengers.Features.GettingPassengerById.V1;\n\npublic class GetPassengerByIdTests : PassengerIntegrationTestBase\n{\n    public GetPassengerByIdTests(\n        TestFixture<Program, PassengerDbContext, PassengerReadDbContext> integrationTestFactory) : base(integrationTestFactory)\n    {\n    }\n\n    [Fact]\n    public async Task should_retrive_a_passenger_by_id_currectly()\n    {\n        // Arrange\n        var command = new FakeCompleteRegisterPassengerMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        var query = new GetPassengerById(command.Id);\n\n        // Act\n        var response = await Fixture.SendAsync(query);\n\n        // Assert\n        response.Should().NotBeNull();\n        response?.PassengerDto?.Id.Should().Be(command.Id);\n    }\n\n    [Fact]\n    public async Task should_retrive_a_passenger_by_id_from_grpc_service()\n    {\n        // Arrange\n        var command = new FakeCompleteRegisterPassengerMongoCommand().Generate();\n\n        await Fixture.SendAsync(command);\n\n        var passengerGrpcClient = new PassengerGrpcService.PassengerGrpcServiceClient(Fixture.Channel);\n\n        // Act\n        var response = await passengerGrpcClient.GetByIdAsync(new GetByIdRequest { Id = command.Id.ToString() });\n\n        // Assert\n        response?.Should().NotBeNull();\n        response?.PassengerDto?.Id.Should().Be(command.Id.ToString());\n    }\n}"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/PassengerIntegrationTestBase.cs",
    "content": "using BuildingBlocks.TestBase;\nusing Passenger.Api;\nusing Passenger.Data;\nusing Xunit;\n\nnamespace Integration.Test;\n\n[Collection(IntegrationTestCollection.Name)]\npublic class PassengerIntegrationTestBase : TestBase<Program, PassengerDbContext, PassengerReadDbContext>\n{\n    public PassengerIntegrationTestBase(TestFixture<Program, PassengerDbContext, PassengerReadDbContext> integrationTestFactory)\n        : base(integrationTestFactory)\n    {\n    }\n}\n\n[CollectionDefinition(Name)]\npublic class IntegrationTestCollection : ICollectionFixture<TestFixture<Program, PassengerDbContext, PassengerReadDbContext>>\n{\n    public const string Name = \"Passenger Integration Test\";\n}"
  },
  {
    "path": "src/Services/Passenger/tests/IntegrationTest/xunit.runner.json",
    "content": "{\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "src/Services/Passenger/tests/PerformanceTest/.openapi-generator/FILES",
    "content": ".openapi-generator-ignore\nREADME.md\nscript.js\n"
  },
  {
    "path": "src/Services/Passenger/tests/PerformanceTest/.openapi-generator/VERSION",
    "content": "6.6.0-SNAPSHOT\n"
  },
  {
    "path": "src/Services/Passenger/tests/PerformanceTest/.openapi-generator-ignore",
    "content": "# OpenAPI Generator Ignore\n# Generated by openapi-generator https://github.com/openapitools/openapi-generator\n\n# Use this file to prevent files from being overwritten by the generator.\n# The patterns follow closely to .gitignore or .dockerignore.\n\n# As an example, the C# client generator defines ApiClient.cs.\n# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:\n#ApiClient.cs\n\n# You can match any string of characters against a directory, file or extension with a single asterisk (*):\n#foo/*/qux\n# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux\n\n# You can recursively match patterns against a directory, file or extension with a double asterisk (**):\n#foo/**/qux\n# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux\n\n# You can also negate patterns with an exclamation (!).\n# For example, you can ignore all files in a docs folder with the file extension .md:\n#docs/*.md\n# Then explicitly reverse the ignore rule for a single file:\n#!docs/README.md\n"
  },
  {
    "path": "src/Services/Passenger/tests/PerformanceTest/README.md",
    "content": "# Generated k6 script\n\nThe `script.js` file contains most of the Swagger/OpenAPI specification and you can customize it to your needs.\n\nGlobal header variables are defined at the top of the file, like `api_key`. Each path in the specification is converted into a [group](https://docs.k6.io/docs/tags-and-groups) in k6 and each group contains all the request methods related to that path. Path and query parameters are extracted from the specification and put at the start of the group. The URL is constructed from the base URL plus path and query.\n\nIf the Swagger/OpenAPI specification used as the input spec contains examples at parameter level, those will be extracted and utilized as parameter values. The `handleParamValue` custom Mustache lambda registered for use in the K6 `script.mustache` template handles the conditional checks, formatting, and outputting of parameter values. If a given parameter has value specified – either in `example` or `examples` field, defined at the parameter level – that value will be used. For list (`examples`), entire list will be output in the generated script and the first element from that list will be assigned as parameter value. If a given parameter does not have an example defined, a placeholder value with `TODO_EDIT_THE_` prefix will be generated for that parameter, and you will have to assign a value before you can run the script. In other words, you can now generate K6 test scripts which are ready to run, provided the Swagger/OpenAPI specification used as the input spec contains examples for all of the path/query parameters; see `modules/openapi-generator/src/test/resources/3_0/examples.yaml` for an example of such specification, and https://swagger.io/docs/specification/adding-examples/ for more information about adding examples.\n\nk6 specific parameters are in the [`params`](https://docs.k6.io/docs/params-k6http) object, and `body` contains the [request](https://docs.k6.io/docs/http-requests) body which is in the form of `identifier: type`, which the `type` should be substituted by a proper value. Then goes the request and the check.\n\n[Check](https://docs.k6.io/docs/checks) are like asserts but differ in that they don't halt execution, instead they just store the result of the check, pass or fail, and let the script execution continue.\n\nEach request is always followed by a 0.1 second [sleep](https://docs.k6.io/docs/sleep-t-1) to prevent the script execution from flooding the system with too many requests simultaneously.\n\nNote that the default iteration count and VU count is 1. So each request in each group will be executed once. For more information, see the [k6 options](https://docs.k6.io/docs/options).\n"
  },
  {
    "path": "src/Services/Passenger/tests/PerformanceTest/script.js",
    "content": "/*\n * APIs\n * An example application with OpenAPI, Swashbuckle, and API versioning.\n *\n * OpenAPI spec version: 1.0\n * Contact:\n *\n * NOTE: This class is auto generated by OpenAPI Generator.\n * https://github.com/OpenAPITools/openapi-generator\n *\n * OpenAPI generator version: 6.6.0-SNAPSHOT\n */\n\n\nimport http from \"k6/http\";\nimport { group, check, sleep } from \"k6\";\n\nconst BASE_URL = \"/\";\n// Sleep duration between successive requests.\n// You might want to edit the value of this variable or remove calls to the sleep function on the script.\nconst SLEEP_DURATION = 0.1;\n// Global variables should be initialized.\n\nexport default function() {\n    group(\"/api/v1/passenger/{id}\", () => {\n        let id = 'TODO_EDIT_THE_ID'; // specify value as there is no example value for this parameter in OpenAPI spec\n\n        // Request No. 1: GetPassengerById\n        {\n            let url = BASE_URL + `/api/v1/passenger/${id}`;\n            let request = http.get(url);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n    group(\"/api/v1/passenger/complete-registration\", () => {\n\n        // Request No. 1: CompleteRegisterPassenger\n        {\n            let url = BASE_URL + `/api/v1/passenger/complete-registration`;\n            // TODO: edit the parameters of the request body.\n            let body = {\"passportNumber\": \"string\", \"passengerType\": \"passengertype\", \"age\": \"integer\"};\n            let params = {headers: {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}};\n            let request = http.post(url, JSON.stringify(body), params);\n\n            check(request, {\n                \"Success\": (r) => r.status === 200\n            });\n        }\n    });\n\n}\n"
  },
  {
    "path": "src/Services/Passenger/tests/tests.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Integration.Test\", \"IntegrationTest\\Integration.Test.csproj\", \"{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  }
]