From 72c9d337eb517ffd19d74b67e3180a0006db1ebd Mon Sep 17 00:00:00 2001 From: Ashutosh Mishra Date: Fri, 21 Jun 2024 19:03:49 +0530 Subject: [PATCH] Adding GET operation for NVA Inbound Security Rule --- .../inbound-security-rule/_create.md | 16 ++ .../inbound-security-rule/_show.md | 16 ++ .../inbound-security-rule/readme.md | 3 + Commands/tree.json | 55 ++++ .../2024-01-01.json | 1 + .../2024-01-01.xml | 269 ++++++++++++++++++ 6 files changed, 360 insertions(+) create mode 100644 Commands/network/virtual-appliance/inbound-security-rule/_show.md create mode 100644 Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.json create mode 100644 Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml diff --git a/Commands/network/virtual-appliance/inbound-security-rule/_create.md b/Commands/network/virtual-appliance/inbound-security-rule/_create.md index 10017fdda..7cead500e 100644 --- a/Commands/network/virtual-appliance/inbound-security-rule/_create.md +++ b/Commands/network/virtual-appliance/inbound-security-rule/_create.md @@ -19,3 +19,19 @@ Create the specified Network Virtual Appliance Inbound Security Rules. ```bash network virtual-appliance inbound-security-rule create --network-virtual-appliance-name "MyName" -g "MyRG" --subscription {subID} --rule-type "AutoExpire" --name "TemporaryRuleCollection" --rules "[{name:'inboundRule',protocol:'TCP',destination-port-ranges:['80-120'],applies-on:['publicnicipconfig'],source-address-prefix:'20.0.0.0/32'}]" ``` + +### [2024-01-01](/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml) **Stable** + + + +#### examples + +- Create Inbound Security Rule of Permanent Rule Type + ```bash + network virtual-appliance inbound-security-rule create --nva-name "MyName" -g "MyRG" --subscription {subID} --rule-type "Permanent" --name "PermanentRuleCollection" --rules "[{name:'inboundRule',protocol:'TCP',destination-port-ranges:['80-120'],applies-on:['slbIP'],source-address-prefix:'*'}]" + ``` + +- Create Inbound Security Rule of AutoExpire Rule Type + ```bash + network virtual-appliance inbound-security-rule create --nva-name "MyName" -g "MyRG" --subscription {subID} --rule-type "AutoExpire" --name "TemporaryRuleCollection" --rules "[{name:'inboundRule',protocol:'TCP',destination-port-ranges:['80-120'],applies-on:['publicnicipconfig'],source-address-prefix:'20.0.0.0/32'}]" + ``` diff --git a/Commands/network/virtual-appliance/inbound-security-rule/_show.md b/Commands/network/virtual-appliance/inbound-security-rule/_show.md new file mode 100644 index 000000000..096bb8943 --- /dev/null +++ b/Commands/network/virtual-appliance/inbound-security-rule/_show.md @@ -0,0 +1,16 @@ +# [Command] _network virtual-appliance inbound-security-rule show_ + +Get the available specified Network Virtual Appliance Inbound Security Rules Collection. + +## Versions + +### [2024-01-01](/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml) **Stable** + + + +#### examples + +- Get Inbound Security Rule + ```bash + network virtual-appliance inbound-security-rule show --nva-name "MyName" -g "MyRG" --subscription {subID} --name "InboundRuleCollection" + ``` diff --git a/Commands/network/virtual-appliance/inbound-security-rule/readme.md b/Commands/network/virtual-appliance/inbound-security-rule/readme.md index ff32d6a13..792729ef9 100644 --- a/Commands/network/virtual-appliance/inbound-security-rule/readme.md +++ b/Commands/network/virtual-appliance/inbound-security-rule/readme.md @@ -6,3 +6,6 @@ Manage Azure Network Virtual Appliance Inbound Security Rules. - [create](/Commands/network/virtual-appliance/inbound-security-rule/_create.md) : Create the specified Network Virtual Appliance Inbound Security Rules. + +- [show](/Commands/network/virtual-appliance/inbound-security-rule/_show.md) +: Get the available specified Network Virtual Appliance Inbound Security Rules Collection. diff --git a/Commands/tree.json b/Commands/tree.json index 1da3776f7..71cb0e066 100644 --- a/Commands/tree.json +++ b/Commands/tree.json @@ -111243,6 +111243,61 @@ "version": "2023-11-01" } ] + }, + { + "examples": [ + { + "commands": [ + "network virtual-appliance inbound-security-rule create --nva-name \"MyName\" -g \"MyRG\" --subscription {subID} --rule-type \"Permanent\" --name \"PermanentRuleCollection\" --rules \"[{name:'inboundRule',protocol:'TCP',destination-port-ranges:['80-120'],applies-on:['slbIP'],source-address-prefix:'*'}]\"" + ], + "name": "Create Inbound Security Rule of Permanent Rule Type" + }, + { + "commands": [ + "network virtual-appliance inbound-security-rule create --nva-name \"MyName\" -g \"MyRG\" --subscription {subID} --rule-type \"AutoExpire\" --name \"TemporaryRuleCollection\" --rules \"[{name:'inboundRule',protocol:'TCP',destination-port-ranges:['80-120'],applies-on:['publicnicipconfig'],source-address-prefix:'20.0.0.0/32'}]\"" + ], + "name": "Create Inbound Security Rule of AutoExpire Rule Type" + } + ], + "name": "2024-01-01", + "resources": [ + { + "id": "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/networkvirtualappliances/{}/inboundsecurityrules/{}", + "plane": "mgmt-plane", + "version": "2024-01-01" + } + ] + } + ] + }, + "show": { + "help": { + "short": "Get the available specified Network Virtual Appliance Inbound Security Rules Collection." + }, + "names": [ + "network", + "virtual-appliance", + "inbound-security-rule", + "show" + ], + "versions": [ + { + "examples": [ + { + "commands": [ + "network virtual-appliance inbound-security-rule show --nva-name \"MyName\" -g \"MyRG\" --subscription {subID} --name \"InboundRuleCollection\"" + ], + "name": "Get Inbound Security Rule" + } + ], + "name": "2024-01-01", + "resources": [ + { + "id": "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/networkvirtualappliances/{}/inboundsecurityrules/{}", + "plane": "mgmt-plane", + "version": "2024-01-01" + } + ] } ] } diff --git a/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.json b/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.json new file mode 100644 index 000000000..d6798add5 --- /dev/null +++ b/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.json @@ -0,0 +1 @@ +{"plane": "mgmt-plane", "resources": [{"id": "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/networkvirtualappliances/{}/inboundsecurityrules/{}", "version": "2024-01-01", "swagger": "mgmt-plane/network/ResourceProviders/Microsoft.Network/Paths/L3N1YnNjcmlwdGlvbnMve3N1YnNjcmlwdGlvbklkfS9yZXNvdXJjZUdyb3Vwcy97cmVzb3VyY2VHcm91cE5hbWV9L3Byb3ZpZGVycy9NaWNyb3NvZnQuTmV0d29yay9uZXR3b3JrVmlydHVhbEFwcGxpYW5jZXMve25ldHdvcmtWaXJ0dWFsQXBwbGlhbmNlTmFtZX0vaW5ib3VuZFNlY3VyaXR5UnVsZXMve3J1bGVDb2xsZWN0aW9uTmFtZX0=/V/MjAyNC0wMS0wMQ=="}], "commandGroups": [{"name": "network virtual-appliance inbound-security-rule", "commands": [{"name": "create", "version": "2024-01-01", "resources": [{"id": "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/networkvirtualappliances/{}/inboundsecurityrules/{}", "version": "2024-01-01", "swagger": "mgmt-plane/network/ResourceProviders/Microsoft.Network/Paths/L3N1YnNjcmlwdGlvbnMve3N1YnNjcmlwdGlvbklkfS9yZXNvdXJjZUdyb3Vwcy97cmVzb3VyY2VHcm91cE5hbWV9L3Byb3ZpZGVycy9NaWNyb3NvZnQuTmV0d29yay9uZXR3b3JrVmlydHVhbEFwcGxpYW5jZXMve25ldHdvcmtWaXJ0dWFsQXBwbGlhbmNlTmFtZX0vaW5ib3VuZFNlY3VyaXR5UnVsZXMve3J1bGVDb2xsZWN0aW9uTmFtZX0=/V/MjAyNC0wMS0wMQ=="}], "argGroups": [{"name": "", "args": [{"type": "string", "var": "$Path.networkVirtualApplianceName", "options": ["nva-name"], "required": true, "group": "", "idPart": "name", "help": {"short": "The name of the Network Virtual Appliance."}}, {"type": "ResourceGroupName", "var": "$Path.resourceGroupName", "options": ["g", "resource-group"], "required": true, "idPart": "resource_group"}, {"type": "string", "var": "$Path.ruleCollectionName", "options": ["n", "name", "rule-collection-name"], "required": true, "idPart": "child_name_1", "help": {"short": "The name of security rule collection."}}, {"type": "SubscriptionId", "var": "$Path.subscriptionId", "options": ["subscription"], "required": true, "idPart": "subscription"}]}, {"name": "Parameters", "args": [{"type": "ResourceId", "var": "$parameters.id", "options": ["id"], "group": "Parameters", "help": {"short": "Resource ID."}, "format": {"template": "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/networkVirtualAppliances/{}/inboundSecurityRules/{}"}}]}, {"name": "Properties", "args": [{"type": "string", "var": "$parameters.properties.ruleType", "options": ["rule-type"], "group": "Properties", "help": {"short": "Rule Type. This should be either AutoExpire or Permanent. Auto Expire Rule only creates NSG rules. Permanent Rule creates NSG rule and SLB LB Rule."}, "enum": {"items": [{"name": "AutoExpire", "value": "AutoExpire"}, {"name": "Permanent", "value": "Permanent"}]}}, {"type": "array", "var": "$parameters.properties.rules", "options": ["rules"], "group": "Properties", "help": {"short": "List of allowed rules."}, "item": {"type": "object", "args": [{"type": "array", "var": "$parameters.properties.rules[].appliesOn", "options": ["applies-on"], "help": {"short": "Public IP name in case of Permanent Rule type & Interface Name in case of Auto Expire Rule type"}, "item": {"type": "string"}}, {"type": "integer32", "var": "$parameters.properties.rules[].destinationPortRange", "options": ["destination-port-range"], "help": {"short": "NVA port ranges to be opened up. One needs to provide specific ports."}, "format": {"maximum": 65535, "minimum": 0}}, {"type": "array", "var": "$parameters.properties.rules[].destinationPortRanges", "options": ["destination-port-ranges"], "help": {"short": "NVA port ranges to be opened up. One can provide a range of ports. Allowed port value between 0 and 65535."}, "item": {"type": "string"}}, {"type": "string", "var": "$parameters.properties.rules[].name", "options": ["name"], "help": {"short": "Name of the rule."}}, {"type": "string", "var": "$parameters.properties.rules[].protocol", "options": ["protocol"], "help": {"short": "Protocol. This should be either TCP or UDP."}, "enum": {"items": [{"name": "TCP", "value": "TCP"}, {"name": "UDP", "value": "UDP"}]}}, {"type": "string", "var": "$parameters.properties.rules[].sourceAddressPrefix", "options": ["source-address-prefix"], "help": {"short": "The CIDR or source IP range."}}]}}]}], "operations": [{"longRunning": {"finalStateVia": "azure-async-operation"}, "operationId": "InboundSecurityRule_CreateOrUpdate", "http": {"path": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkVirtualAppliances/{networkVirtualApplianceName}/inboundSecurityRules/{ruleCollectionName}", "request": {"method": "put", "path": {"params": [{"type": "string", "name": "networkVirtualApplianceName", "arg": "$Path.networkVirtualApplianceName", "required": true}, {"type": "string", "name": "resourceGroupName", "arg": "$Path.resourceGroupName", "required": true}, {"type": "string", "name": "ruleCollectionName", "arg": "$Path.ruleCollectionName", "required": true}, {"type": "string", "name": "subscriptionId", "arg": "$Path.subscriptionId", "required": true}]}, "query": {"consts": [{"readOnly": true, "const": true, "default": {"value": "2024-01-01"}, "type": "string", "name": "api-version", "required": true}]}, "body": {"json": {"schema": {"type": "object", "name": "parameters", "required": true, "props": [{"type": "ResourceId", "name": "id", "arg": "$parameters.id", "format": {"template": "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/networkVirtualAppliances/{}/inboundSecurityRules/{}"}}, {"type": "string", "name": "name", "arg": "$Path.ruleCollectionName"}, {"type": "object", "name": "properties", "props": [{"type": "string", "name": "ruleType", "arg": "$parameters.properties.ruleType", "enum": {"items": [{"value": "AutoExpire"}, {"value": "Permanent"}]}}, {"type": "array", "name": "rules", "arg": "$parameters.properties.rules", "item": {"type": "object", "props": [{"type": "array", "name": "appliesOn", "arg": "$parameters.properties.rules[].appliesOn", "item": {"type": "string"}}, {"type": "integer32", "name": "destinationPortRange", "arg": "$parameters.properties.rules[].destinationPortRange", "format": {"maximum": 65535, "minimum": 0}}, {"type": "array", "name": "destinationPortRanges", "arg": "$parameters.properties.rules[].destinationPortRanges", "item": {"type": "string"}}, {"type": "string", "name": "name", "arg": "$parameters.properties.rules[].name"}, {"type": "string", "name": "protocol", "arg": "$parameters.properties.rules[].protocol", "enum": {"items": [{"value": "TCP"}, {"value": "UDP"}]}}, {"type": "string", "name": "sourceAddressPrefix", "arg": "$parameters.properties.rules[].sourceAddressPrefix"}]}}], "clientFlatten": true}], "clientFlatten": true}}}}, "responses": [{"statusCode": [200, 201], "body": {"json": {"var": "$Instance", "schema": {"type": "object", "props": [{"readOnly": true, "type": "string", "name": "etag"}, {"type": "ResourceId", "name": "id", "format": {"template": "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/networkVirtualAppliances/{}/inboundSecurityRules/{}"}}, {"type": "string", "name": "name"}, {"type": "object", "name": "properties", "props": [{"readOnly": true, "type": "string", "name": "provisioningState", "enum": {"items": [{"value": "Deleting"}, {"value": "Failed"}, {"value": "Succeeded"}, {"value": "Updating"}]}}, {"type": "string", "name": "ruleType", "enum": {"items": [{"value": "AutoExpire"}, {"value": "Permanent"}]}}, {"type": "array", "name": "rules", "item": {"type": "object", "props": [{"type": "array", "name": "appliesOn", "item": {"type": "string"}}, {"type": "integer32", "name": "destinationPortRange", "format": {"maximum": 65535, "minimum": 0}}, {"type": "array", "name": "destinationPortRanges", "item": {"type": "string"}}, {"type": "string", "name": "name"}, {"type": "string", "name": "protocol", "enum": {"items": [{"value": "TCP"}, {"value": "UDP"}]}}, {"type": "string", "name": "sourceAddressPrefix"}]}}], "clientFlatten": true}, {"readOnly": true, "type": "string", "name": "type"}]}}}}, {"isError": true, "body": {"json": {"schema": {"type": "@ODataV4Format"}}}}]}}], "outputs": [{"type": "object", "ref": "$Instance", "clientFlatten": true}]}, {"name": "show", "version": "2024-01-01", "resources": [{"id": "/subscriptions/{}/resourcegroups/{}/providers/microsoft.network/networkvirtualappliances/{}/inboundsecurityrules/{}", "version": "2024-01-01", "swagger": "mgmt-plane/network/ResourceProviders/Microsoft.Network/Paths/L3N1YnNjcmlwdGlvbnMve3N1YnNjcmlwdGlvbklkfS9yZXNvdXJjZUdyb3Vwcy97cmVzb3VyY2VHcm91cE5hbWV9L3Byb3ZpZGVycy9NaWNyb3NvZnQuTmV0d29yay9uZXR3b3JrVmlydHVhbEFwcGxpYW5jZXMve25ldHdvcmtWaXJ0dWFsQXBwbGlhbmNlTmFtZX0vaW5ib3VuZFNlY3VyaXR5UnVsZXMve3J1bGVDb2xsZWN0aW9uTmFtZX0=/V/MjAyNC0wMS0wMQ=="}], "argGroups": [{"name": "", "args": [{"type": "string", "var": "$Path.networkVirtualApplianceName", "options": ["nva-name"], "required": true, "group": "", "idPart": "name", "help": {"short": "The name of the Network Virtual Appliance."}}, {"type": "ResourceGroupName", "var": "$Path.resourceGroupName", "options": ["g", "resource-group"], "required": true, "idPart": "resource_group"}, {"type": "string", "var": "$Path.ruleCollectionName", "options": ["n", "name", "rule-collection-name"], "required": true, "idPart": "child_name_1", "help": {"short": "The name of security rule collection."}}, {"type": "SubscriptionId", "var": "$Path.subscriptionId", "options": ["subscription"], "required": true, "idPart": "subscription"}]}], "operations": [{"operationId": "InboundSecurityRule_Get", "http": {"path": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkVirtualAppliances/{networkVirtualApplianceName}/inboundSecurityRules/{ruleCollectionName}", "request": {"method": "get", "path": {"params": [{"type": "string", "name": "networkVirtualApplianceName", "arg": "$Path.networkVirtualApplianceName", "required": true}, {"type": "string", "name": "resourceGroupName", "arg": "$Path.resourceGroupName", "required": true}, {"type": "string", "name": "ruleCollectionName", "arg": "$Path.ruleCollectionName", "required": true}, {"type": "string", "name": "subscriptionId", "arg": "$Path.subscriptionId", "required": true}]}, "query": {"consts": [{"readOnly": true, "const": true, "default": {"value": "2024-01-01"}, "type": "string", "name": "api-version", "required": true}]}}, "responses": [{"statusCode": [200], "body": {"json": {"var": "$Instance", "schema": {"type": "object", "props": [{"readOnly": true, "type": "string", "name": "etag"}, {"type": "ResourceId", "name": "id", "format": {"template": "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/networkVirtualAppliances/{}/inboundSecurityRules/{}"}}, {"type": "string", "name": "name"}, {"type": "object", "name": "properties", "props": [{"readOnly": true, "type": "string", "name": "provisioningState", "enum": {"items": [{"value": "Deleting"}, {"value": "Failed"}, {"value": "Succeeded"}, {"value": "Updating"}]}}, {"type": "string", "name": "ruleType", "enum": {"items": [{"value": "AutoExpire"}, {"value": "Permanent"}]}}, {"type": "array", "name": "rules", "item": {"type": "object", "props": [{"type": "array", "name": "appliesOn", "item": {"type": "string"}}, {"type": "integer32", "name": "destinationPortRange", "format": {"maximum": 65535, "minimum": 0}}, {"type": "array", "name": "destinationPortRanges", "item": {"type": "string"}}, {"type": "string", "name": "name"}, {"type": "string", "name": "protocol", "enum": {"items": [{"value": "TCP"}, {"value": "UDP"}]}}, {"type": "string", "name": "sourceAddressPrefix"}]}}], "clientFlatten": true}, {"readOnly": true, "type": "string", "name": "type"}]}}}}, {"isError": true, "body": {"json": {"schema": {"type": "@ODataV4Format"}}}}]}}], "outputs": [{"type": "object", "ref": "$Instance", "clientFlatten": true}], "confirmation": ""}]}]} \ No newline at end of file diff --git a/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml b/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml new file mode 100644 index 000000000..456c4e5b0 --- /dev/null +++ b/Resources/mgmt-plane/L3N1YnNjcmlwdGlvbnMve30vcmVzb3VyY2Vncm91cHMve30vcHJvdmlkZXJzL21pY3Jvc29mdC5uZXR3b3JrL25ldHdvcmt2aXJ0dWFsYXBwbGlhbmNlcy97fS9pbmJvdW5kc2VjdXJpdHlydWxlcy97fQ==/2024-01-01.xml @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +