Modules/COM-Webhooks.psm1
#------------------- FUNCTIONS FOR COMPUTE OPS MANAGEMENT WEBHOOKS----------------------------------------------------------------------------------------------------------------------------------------------- using module .\Constants.psm1 # Public functions Function Get-HPECOMWebhook { <# .SYNOPSIS Retrieve webhook resources in the specified region. .DESCRIPTION This Cmdlet retrieves a collection of webhooks available in the specified region. .PARAMETER Region Specifies the region code of a Compute Ops Management instance provisioned in the workspace (e.g., 'us-west', 'eu-central', etc.). This mandatory parameter can be retrieved using 'Get-HPEGLService -Name "Compute Ops Management" -ShowProvisioned' or 'Get-HPEGLRegion -ShowProvisioned'. Auto-completion (Tab key) is supported for this parameter, providing a list of region codes provisioned in your workspace. .PARAMETER Name An optional parameter to specify the name of a webhook to display. .PARAMETER Deliveries An optional switch parameter to retrieve details of the most recent deliveries attempted. Compute Ops Management stores the ten most recent deliveries and the five most recent failures. .PARAMETER WhatIf Shows the raw REST API call that would be made to COM instead of sending the request. This option is useful for understanding the inner workings of the native REST API calls used by COM. .EXAMPLE Get-HPECOMWebhook -Region us-west Returns a collection of webhooks available in the western US region. .EXAMPLE Get-HPECOMWebhook -Region us-west -Name 'Webhook event for server shutdown' Returns the webhook resource named 'Webhook event for server shutdown' located in the western US region. .EXAMPLE Get-HPECOMWebhook -Region us-west -Name 'Webhook event for server shutdown' -Deliveries Returns the most recent deliveries attempted by the webhook named 'Webhook event for server shutdown'. .INPUTS None. You cannot pipe objects to this Cmdlet. #> [CmdletBinding(DefaultParameterSetName = 'Region')] Param( [Parameter (Mandatory)] [ValidateScript({ if (($_ -in $Global:HPECOMRegions.region)) { $true } else { Throw "The COM region '$_' is not provisioned in this workspace! Please specify a valid region code (e.g., 'us-west', 'eu-central'). `nYou can retrieve the region code using: Get-HPEGLService -Name 'Compute Ops Management' -ShowProvisioned. `nYou can also use the Tab key for auto-completion to see the list of provisioned region codes." } })] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) # Filter region based on $Global:HPECOMRegions global variable and create completions $Global:HPECOMRegions.region | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } })] [String]$Region, [Parameter (ParameterSetName = 'Region')] [Parameter (Mandatory, ParameterSetName = 'Deliveries')] [String]$Name, [Parameter (ParameterSetName = 'Deliveries')] [Switch]$Deliveries, [Switch]$WhatIf ) Begin { $Caller = (Get-PSCallStack)[1].Command "[{0}] Called from: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose } Process { "[{0}] Bound PS Parameters: {1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose if ($Name -and -not $Deliveries) { $Uri = (Get-COMWebhooksUri) + "?filter=name eq '$Name'" } elseif ($Deliveries) { $Uri = (Get-COMWebhooksUri) + "?filter=name eq '$Name'" try { [Array]$Webhook = Invoke-HPECOMWebRequest -Method Get -Uri $Uri -Region $Region $WebhookID = $Webhook.id "[{0}] ID found for Webhook name '{1}': '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $WebhookID | Write-Verbose if ($Null -eq $WebhookID) { Throw "Webhook with this name cannot be found!" } $Uri = (Get-COMWebhooksUri) + "/" + $WebhookID + "/deliveries" } catch { $PSCmdlet.ThrowTerminatingError($_) } } else { $Uri = Get-COMWebhooksUri } try { [Array]$CollectionList = Invoke-HPECOMWebRequest -Method Get -Uri $Uri -Region $Region -WhatIfBoolean $WhatIf -Verbose:$VerbosePreference -ErrorAction Stop } catch { $PSCmdlet.ThrowTerminatingError($_) } $ReturnData = @() if ($Null -ne $CollectionList) { # Add region to object $CollectionList | Add-Member -type NoteProperty -name region -value $Region if ($Deliveries) { $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "COM.Webhooks.Deliveries" } else { $ReturnData = Invoke-RepackageObjectWithType -RawObject $CollectionList -ObjectName "COM.Webhooks" $ReturnData = $ReturnData | Sort-Object name } return $ReturnData } else { return } } } Function New-HPECOMWebhook { <# .SYNOPSIS Creates a new webhook in a specified region. .DESCRIPTION This Cmdlet can be used to create a new webhook with a destination endpoint and an OData configuration for event filtering. .PARAMETER Region Specifies the region code of a Compute Ops Management instance provisioned in the workspace (e.g., 'us-west', 'eu-central', etc.) where the webhook will be created. This mandatory parameter can be retrieved using 'Get-HPEGLService -Name "Compute Ops Management" -ShowProvisioned' or 'Get-HPEGLRegion -ShowProvisioned'. Auto-completion (Tab key) is supported for this parameter, providing a list of region codes provisioned in your workspace. .PARAMETER Name Specifies the name of the webhook to create. .PARAMETER EventFilter Specifies the OData configuration for events to receive. Filters use OData style filters as described in https://developer.greenlake.hpe.com/docs/greenlake/services/compute-ops-mgmt/public/guide/#filtering The general syntax for an OData filter looks like 'property op value' with: - 'property' refers to the field or property to filter on in the entity. - 'op' is the operator, such as eq (equals), ne (not equal), gt (greater than), ge (greater or equal), lt (less than), le (less or equal), etc. - 'value' is the value to compare against the property. Filtering examples: - To receive webhooks for group and server events only: type eq 'compute-ops/group' or type eq 'compute-ops/server' - To receive webhooks for all servers that are shut down: type eq 'compute-ops/server' and old/hardware/powerState eq 'ON' and changed/hardware/powerState eq True - To receive webhooks for all servers that get disconnect from COM: type eq 'compute-ops/server' and old/state/connected eq True and changed/state/connected eq True -To receive webhooks for all jobs that run a server firmware update: type eq 'compute-ops/job' and contains(name, 'FirmwareUpdate.New') and new/state eq 'RUNNING' - To receive webhooks for all servers that transition to an unhealthy status: type eq 'compute-ops/server' and old/hardware/health/summary eq 'OK' and changed/hardware/health/summary eq True - To receive webhooks for all events within a specified group: type eq 'compute-ops/group' and contains(name, 'Production') - To receive webhooks for all new firmware bundles that are available: type eq 'compute-ops/firmware-bundle' and operation eq 'Created' - To receive webhooks for all servers added to COM that require activation: type eq 'compute-ops/server' and operation eq 'Created' - To receive webhooks for all new servers added and connected to COM: type eq 'compute-ops/server' and old/state/connected eq False and changed/state/connected eq True For more information about COM webhooks, see https://jullienl.github.io/Implementing-webhooks-with-COM/ .PARAMETER Destination Specifies the HTTPS webhook endpoint capable of receiving HTTP GET and POST requests. .PARAMETER WhatIf Shows the raw REST API call that would be made to COM instead of sending the request. This option is useful for understanding the inner workings of the native REST API calls used by COM. .EXAMPLE New-HPECOMWebhook -Region eu-central -Name "Webhook for servers that disconnect" ` -Destination "https://hook.eu2.make.com/baea2fa0f8be4d546445c98253392058" ` -EventFilter "type eq 'compute-ops/alert' and old/hardware/powerState eq 'ON' and changed/hardware/powerState eq True" This example creates a webhook named "Webhook for servers that disconnect" in the `eu-central` region. The webhook will send events to the specified destination URL when a server's hardware power state changes from 'ON'. The filter criteria are defined using OData syntax. .EXAMPLE New-HPECOMWebhook -Region eu-central -Name "Webhook for servers that become unhealthy" ` -Destination "https://hook.eu2.make.com/baea2fa0f8be4d546445c98253392058" ` -EventFilter "type eq 'compute-ops/server' and old/hardware/health/summary eq 'OK' and changed/hardware/health/summary eq True" This example creates a webhook named "Webhook for servers that become unhealthy" in the `eu-central` region. The webhook will trigger when servers transition from a healthy state (`OK`) to an unhealthy state. The events will be sent to the specified destination URL, filtered according to the provided OData criteria. .EXAMPLE New-HPECOMWebhook -Region eu-central -Name "Webhook for new activated servers" ` -Destination "https://hook.eu2.make.com/baea2fa0f8be4d546445c98253392058" ` -EventFilter "type eq 'compute-ops/server' and old/state/connected eq False and changed/state/connected eq True" This example creates a webhook named "Webhook for new activated servers" in the `eu-central` region. This webhook will send notifications to the given destination URL whenever new servers are activated and connected to COM. The filter ensures that the event captures the change in connection state from `False` to `True`. .INPUTS Pipeline input is not supported .OUTPUTS System.Collections.ArrayList A custom status object or array of objects containing the following PsCustomObject keys: * Name - Name of the webhook attempted to be created * Region - Name of the region where to create the webhook * Status - Status of the creation attempt (Failed for http error return; Complete if creation is successful; Warning if no action is needed) * Details - More information about the status * Exception: Information about any exceptions generated during the operation. #> [CmdletBinding()] Param( [Parameter (Mandatory)] [ValidateScript({ if (($_ -in $Global:HPECOMRegions.region)) { $true } else { Throw "The COM region '$_' is not provisioned in this workspace! Please specify a valid region code (e.g., 'us-west', 'eu-central'). `nYou can retrieve the region code using: Get-HPEGLService -Name 'Compute Ops Management' -ShowProvisioned. `nYou can also use the Tab key for auto-completion to see the list of provisioned region codes." } })] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) # Filter region based on $Global:HPECOMRegions global variable and create completions $Global:HPECOMRegions.region | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } })] [String]$Region, [Parameter (Mandatory)] [ValidateScript({ $_.Length -lt 256 })] [String]$Name, [Parameter (Mandatory)] [ValidateScript({ # Regex pattern to validate OData filter strings with multiple 'and'/'or' conditions if ($_ -match "^\s*([\w/]+ (eq|ne|gt|lt|ge|le) '.+'|[\w/]+ eq (true|false))(\s+(and|or)\s+([\w/]+ (eq|ne|gt|lt|ge|le) '.+'|[\w/]+ eq (true|false)))*\s*$") { return $true } else { throw "The filter string '$_' is not a valid OData filter." } })] [String]$EventFilter, [Parameter (Mandatory)] [ValidateScript({ if ($_ -match '^https?:\/\/[a-zA-Z0-9-\.]+\.[a-z]{2,4}(/\S*)?$') { return $true } else { throw "The URL '$_' is not a valid HTTP/HTTPS URL." } })] [String]$Destination, [Switch]$WhatIf ) Begin { $Caller = (Get-PSCallStack)[1].Command "[{0}] Called from: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose $CreateWebhookStatus = [System.Collections.ArrayList]::new() } Process { "[{0}] Bound PS Parameters: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose $Uri = Get-COMWebhooksUri # Build object for the output $objStatus = [pscustomobject]@{ Name = $Name Region = $Region Status = $Null Details = $Null Exception = $Null } try { $WebhookResource = Get-HPECOMWebhook -Region $Region -Name $Name } catch { $PSCmdlet.ThrowTerminatingError($_) } if ($WebhookResource) { "[{0}] Webhook '{1}' is already present in the '{2}' region!" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Name, $Region | Write-Verbose if ($WhatIf) { $ErrorMessage = "Webhook '{0}': Resource is already present in the '{1}' region! No action needed." -f $Name, $Region Write-warning $ErrorMessage return } else { $objStatus.Status = "Warning" $objStatus.Details = "Webhook already exists in the region! No action needed." } } else { # Build payload $payload = ConvertTo-Json @{ name = $Name destination = $Destination state = "ENABLED" eventFilter = $EventFilter headers = @{} } try { $Response = Invoke-HPECOMWebRequest -Region $Region -Uri $Uri -method POST -body $payload -WhatIfBoolean $WhatIf -Verbose:$VerbosePreference if (-not $WhatIf) { "[{0}] Webhook creation raw response: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Response | Write-Verbose "[{0}] Webhook '{1}' successfully created in '{2}' region" -f $MyInvocation.InvocationName.ToString().ToUpper(), $name, $Region | Write-Verbose $objStatus.Status = "Complete" $objStatus.Details = "Webhook successfully created in $Region region" } } catch { if (-not $WhatIf) { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be created!" $objStatus.Exception = $Global:HPECOMInvokeReturnData } } } [void] $CreateWebhookStatus.add($objStatus) } end { if (-not $WhatIf) { $CreateWebhookStatus = Invoke-RepackageObjectWithType -RawObject $CreateWebhookStatus -ObjectName "COM.objStatus.NSDE" Return $CreateWebhookStatus } } } Function Set-HPECOMWebhook { <# .SYNOPSIS Update an existing webhook in a specified region. .DESCRIPTION This Cmdlet is used to update an existing webhook to modify its destination, its OData filtering configuration, or to re-initiate the verification handshake. If a parameter is not provided, the cmdlet retains the current settings and only updates the provided parameters. .PARAMETER Region Specifies the region code of a Compute Ops Management instance provisioned in the workspace (e.g., 'us-west', 'eu-central', etc.) where the webhook to be updated is located. This mandatory parameter can be retrieved using 'Get-HPEGLService -Name "Compute Ops Management" -ShowProvisioned' or 'Get-HPEGLRegion -ShowProvisioned'. Auto-completion (Tab key) is supported for this parameter, providing a list of region codes provisioned in your workspace. .PARAMETER Name Specifies the name of the webhook to update. .PARAMETER NewName Specifies the new name for the webhook. .PARAMETER EventFilter Specifies the new OData filter configuration for events to receive. Filters use OData style filters as described in [HPE Developer Documentation](https://developer.greenlake.hpe.com/docs/greenlake/services/compute-ops-mgmt/public/guide/#filtering). The general syntax for an OData filter is 'property op value', where: - `property` refers to the field or property to filter on within the entity. - `op` is the operator, such as eq (equals), ne (not equal), gt (greater than), ge (greater or equal), lt (less than), le (less or equal), etc. - `value` is the value to compare against the property. Filtering examples: - To receive webhooks for group and server events only: type eq 'compute-ops/group' or type eq 'compute-ops/server' - To receive webhooks for all servers that are shut down: type eq 'compute-ops/server' and old/hardware/powerState eq 'ON' and changed/hardware/powerState eq True - To receive webhooks for all servers that get disconnect from COM: type eq 'compute-ops/server' and old/state/connected eq True and changed/state/connected eq True -To receive webhooks for all jobs that run a server firmware update: type eq 'compute-ops/job' and contains(name, 'FirmwareUpdate.New') and new/state eq 'RUNNING' - To receive webhooks for all servers that transition to an unhealthy status: type eq 'compute-ops/server' and old/hardware/health/summary eq 'OK' and changed/hardware/health/summary eq True - To receive webhooks for all events within a specified group: type eq 'compute-ops/group' and contains(name, 'Production') - To receive webhooks for all new firmware bundles that are available: type eq 'compute-ops/firmware-bundle' and operation eq 'Created' - To receive webhooks for all servers added to COM that require activation: type eq 'compute-ops/server' and operation eq 'Created' - To receive webhooks for all new servers added and connected to COM: type eq 'compute-ops/server' and old/state/connected eq False and changed/state/connected eq True For more information about COM webhooks, see https://jullienl.github.io/Implementing-webhooks-with-COM/ .PARAMETER Destination Specifies the new HTTPS webhook endpoint that is able to receive HTTP GET and POST requests. .PARAMETER RetryWebhookHandshake Re-initiates the webhook verification handshake. .PARAMETER WhatIf Shows the raw REST API call that would be made to COM instead of sending the request. This option is useful for understanding the inner workings of the native REST API calls used by COM. .EXAMPLE Set-HPECOMWebhook -Region eu-central -Name "New_webhook" -NewName "Webhook for servers that become unhealthy" ` -Destination "https://hook.eu2.make.com/baea2fa0f8be4d546445c98253392058" ` -EventFilter "type eq 'compute-ops/server' and old/hardware/health/summary eq 'OK' and changed/hardware/health/summary eq True" This example updates an existing webhook named "New_webhook" to a new name "Webhook for servers that become unhealthy" in the `eu-central` region. The webhook will send events to the specified destination URL when a server's health summary transitions from `OK` to unhealthy (`True`), using the specified OData filter. .EXAMPLE Set-HPECOMWebhook -Region eu-central -Name "Webhook for servers that become unhealthy" -RetryWebhookHandshake This example re-initiates the verification handshake for the webhook named "Webhook for servers that become unhealthy" in the `eu-central` region. .EXAMPLE Set-HPECOMWebhook -Region eu-central -Name "Webhook for servers that become unhealthy" -Destination "https://hook.us1.make.com/wwedws2fa0f8be4d546445c98253392058" This example updates the destination URL for the webhook named "Webhook for servers that become unhealthy" in the `eu-central` region. .EXAMPLE Set-HPECOMWebhook -Region eu-central -Name "Webhook for servers that become unhealthy" -EventFilter "type eq 'compute-ops/server' and old/hardware/health/summary eq 'OK' and changed/hardware/health/summary eq True" This example updates the OData filter configuration for the webhook named "Webhook for servers that become unhealthy" in the `eu-central` region. .EXAMPLE Get-HPECOMWebhook -Region eu-central | Set-HPECOMWebhook -RetryWebhookHandshake This example re-initiates the verification handshake for all webhooks in the `eu-central` region. .EXAMPLE "POSH_webhook_Alert", "POSH_webhook_firmwarebundle" | Set-HPECOMWebhook -Region eu-central -RetryWebhookHandshake This example re-initiates the verification handshake for the webhooks named "POSH_webhook_Alert" and "POSH_webhook_firmwarebundle" in the `eu-central` region. .INPUTS System.String, System.String[] A single string object or a list of string objects representing the webhooks's names. System.Collections.ArrayList List of webhooks from 'Get-HPECOMWebhook'. .OUTPUTS System.Collections.ArrayList Returns a custom status object or array of objects containing the following properties: * Name - Name of the webhook attempted to be set. * Region - Name of the region where the webhook is updated. * Status - Status of the modification attempt (Failed if an HTTP error occurs; Complete if successful; Warning if no action is needed). * Details - Additional information about the status. * Exception - Information about any exceptions generated during the operation. #> [CmdletBinding()] Param( [Parameter (Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript({ if (($_ -in $Global:HPECOMRegions.region)) { $true } else { Throw "The COM region '$_' is not provisioned in this workspace! Please specify a valid region code (e.g., 'us-west', 'eu-central'). `nYou can retrieve the region code using: Get-HPEGLService -Name 'Compute Ops Management' -ShowProvisioned. `nYou can also use the Tab key for auto-completion to see the list of provisioned region codes." } })] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) # Filter region based on $Global:HPECOMRegions global variable and create completions $Global:HPECOMRegions.region | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } })] [String]$Region, [Parameter (Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateScript({ $_.Length -lt 256 })] [String]$Name, [ValidateScript({ $_.Length -lt 256 })] [String]$NewName, [ValidateScript({ # Regex pattern to validate OData filter strings with multiple 'and'/'or' conditions if ($_ -match "^\s*([\w/]+ (eq|ne|gt|lt|ge|le) '.+'|[\w/]+ eq (true|false))(\s+(and|or)\s+([\w/]+ (eq|ne|gt|lt|ge|le) '.+'|[\w/]+ eq (true|false)))*\s*$") { return $true } else { throw "The filter string '$_' is not a valid OData filter." } })] [String]$EventFilter, [ValidateScript({ if ($_ -match '^https?:\/\/[a-zA-Z0-9-\.]+\.[a-z]{2,4}(/\S*)?$') { return $true } else { throw "The URL '$_' is not a valid HTTP/HTTPS URL." } })] [String]$Destination, [Switch]$RetryWebhookHandshake, [Switch]$WhatIf ) Begin { $Caller = (Get-PSCallStack)[1].Command "[{0}] Called from: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose $SetWebhookStatus = [System.Collections.ArrayList]::new() } Process { "[{0}] Bound PS Parameters: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose try { $WebhookResource = Get-HPECOMWebhook -Region $Region -Name $Name $WebhookID = $WebhookResource.id } catch { $PSCmdlet.ThrowTerminatingError($_) } "[{0}] Webhook ID found: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $WebhookID | Write-Verbose # Build object for the output $objStatus = [pscustomobject]@{ Name = $Name Region = $Region Status = $Null Details = $Null Exception = $Null } if (-not $WebhookID) { # Must return a message if not found if ($WhatIf) { $ErrorMessage = "Webhook '{0}': Resource cannot be found in the '{1}' region!" -f $Name, $Region Write-warning $ErrorMessage return } else { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be found in the region!" } } else { $Uri = (Get-COMWebhooksUri) + "/" + $WebhookID $Payload = @{} # Conditionally add properties if ($NewName) { $Payload.name = $NewName } else { $Payload.name = $Name } if ($Destination) { $Payload.destination = $Destination } else { $Payload.destination = $WebhookResource.destination } if ($RetryWebhookHandshake) { $Payload.state = "ENABLED" } else { $Payload.state = $WebhookResource.state } if ($EventFilter) { $Payload.eventFilter = $EventFilter } else { $Payload.eventFilter = $WebhookResource.eventFilter } # Convert the hashtable to JSON $jsonPayload = $Payload | ConvertTo-Json try { $Response = Invoke-HPECOMWebRequest -Region $Region -Uri $Uri -method PATCH -body $jsonPayload -ContentType "application/merge-patch+json" -WhatIfBoolean $WhatIf -Verbose:$VerbosePreference if (-not $WhatIf) { "[{0}] Webhook update raw response: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Response | Write-Verbose "[{0}] Webhook '{1}' successfully updated in '{2}' region" -f $MyInvocation.InvocationName.ToString().ToUpper(), $name, $Region | Write-Verbose $objStatus.Status = "Complete" $objStatus.Details = "Webhook successfully updated in $Region region" } } catch { if (-not $WhatIf) { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be updated!" $objStatus.Exception = $Global:HPECOMInvokeReturnData } } } [void] $SetWebhookStatus.add($objStatus) } end { if (-not $WhatIf) { $SetWebhookStatus = Invoke-RepackageObjectWithType -RawObject $SetWebhookStatus -ObjectName "COM.objStatus.NSDE" Return $SetWebhookStatus } } } Function Send-HPECOMWebhookTest { <# .SYNOPSIS Simulate a webhook by sending a typical resource object to its configured endpoint URL. .DESCRIPTION This Cmdlet can simulate a webhook by sending a resource object that matches the filtering configuration of an existing webhook to its configured endpoint URL. This test is useful for validating communication between COM and the webhook destination endpoint. It also helps capture data content and test the flow of your automation process. .PARAMETER Region Specifies the region code of a Compute Ops Management instance provisioned in the workspace (e.g., 'us-west', 'eu-central', etc.) where the webhook is located. This mandatory parameter can be retrieved using 'Get-HPEGLService -Name "Compute Ops Management" -ShowProvisioned' or 'Get-HPEGLRegion -ShowProvisioned'. Auto-completion (Tab key) is supported for this parameter, providing a list of region codes provisioned in your workspace. .PARAMETER Name The name of the webhook to be used for the sending test. .PARAMETER WhatIf Shows the raw REST API call that would be made to COM instead of sending the request. This option is useful for understanding the inner workings of the native REST API calls used by COM. .EXAMPLE Send-HPECOMWebhookTest -Region eu-central -Name "Webhook event for servers that are disconnected" Sends a typical resource object that matches the filtering configuration (i.e. a server resource object in this case) of the existing webhook named 'Webhook event for servers that are disconnected' located in the 'eu-central' region to the destination endpoint. .EXAMPLE Get-HPECOMWebhook -Region eu-central | Send-HPECOMWebhookTest Sends a typical resource object that matches the filtering configuration of all existing webhooks in the 'eu-central' region to their respective destination endpoints. .EXAMPLE "Webhook event for servers that are disconnected", "Webhook event for servers that are unhealthy" | Send-HPECOMWebhookTest -Region eu-central Sends a typical resource object that matches the filtering configuration of the webhooks named 'Webhook event for servers that are disconnected' and 'Webhook event for servers that are unhealthy' located in the 'eu-central' region to their respective destination endpoints. .INPUTS System.String, System.String[] A single string object or a list of string objects representing the webhooks's names. System.Collections.ArrayList List of webhooks from 'Get-HPECOMWebhook'. .OUTPUTS System.Collections.ArrayList A custom status object or array of objects containing the following PsCustomObject keys: * Name - The name of the webhook used for the sending test. * Region - The name of the region where the webhook is located. * Status - The status of the send test attempt (Failed for HTTP error return; Complete if successful; Warning if no action is needed). * Details - Additional information about the status. * Exception - Information about any exceptions generated during the operation. #> [CmdletBinding()] Param( [Parameter (Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript({ if (($_ -in $Global:HPECOMRegions.region)) { $true } else { Throw "The COM region '$_' is not provisioned in this workspace! Please specify a valid region code (e.g., 'us-west', 'eu-central'). `nYou can retrieve the region code using: Get-HPEGLService -Name 'Compute Ops Management' -ShowProvisioned. `nYou can also use the Tab key for auto-completion to see the list of provisioned region codes." } })] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) # Filter region based on $Global:HPECOMRegions global variable and create completions $Global:HPECOMRegions.region | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } })] [String]$Region, [Parameter (Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [String]$Name, [Switch]$WhatIf ) Begin { $Caller = (Get-PSCallStack)[1].Command "[{0}] Called from: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose $SendWebhookTestStatus = [System.Collections.ArrayList]::new() } Process { "[{0}] Bound PS Parameters: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose # Build object for the output $objStatus = [pscustomobject]@{ Name = $Name Region = $Region Status = $Null Details = $Null Exception = $Null } try { $WebhookResource = Get-HPECOMWebhook -Region $Region -Name $Name $WebhookID = $WebhookResource.id } catch { $PSCmdlet.ThrowTerminatingError($_) } "[{0}] Webhook ID found: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $WebhookID | Write-Verbose if (-not $WebhookID) { # Must return a message if not found if ($WhatIf) { $ErrorMessage = "Webhook '{0}' cannot be found in the Compute Ops Management instance!" -f $Name Write-Warning $ErrorMessage } else { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be found in the Compute Ops Management instance!" } } else { $EventFilter = $WebhookResource.eventFilter $Destination = $WebhookResource.destination # Define the regex pattern to match the resource type of webhook filter $pattern = "type eq '([^']*)'" # Use the -match operator to apply the pattern and capture the webhook resource type value if ($EventFilter -match $pattern) { # Extract the full type value (e.g. 'compute-ops/server') $fullTypeValue = $matches[1] # Extract the part after the last slash (e.g. 'server') $typeValue = $fullTypeValue -split '/' | Select-Object -Last 1 "[{0}] Extracted webhook resource type: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $typeValue | Write-Verbose } else { throw "The webhook test cannot be sent as the webhook resource type cannot be extracted from the webhook filter definition." } # Object to send creation switch ($typeValue) { server { $Object = Get-HPECOMServer -Region $Region | Select-Object -First 1 } alert { $_SerialNumber = Get-HPECOMServer -Region $Region | Select-Object -First 1 | ForEach-Object serialNumber $Object = Get-HPECOMServer -Region $Region -Name $_SerialNumber -ShowAlerts | Select-Object -First 1 } group { $Object = Get-HPECOMGroup -Region $Region | Where-Object { $_.devices.count -gt 1 } | Select-Object -first 1 } server-setting { $Object = Get-HPECOMSetting -Region $Region -Category Firmware | Select-Object -First 1 } job { $Object = Get-HPECOMJob -Region $Region | Select-Object -First 1 } compliance { $_name = Get-HPECOMGroup -Region $Region | Where-Object { $_.devices.count -gt 1 } | Select-Object -first 1 | ForEach-Object name $Object = Get-HPECOMGroup -Region $Region -Name $_name -ShowCompliance | Select-Object -First 1 } firmware-bundle { $Object = Get-HPECOMFirmwareBundle -Region $Region | Select-Object -First 1 } } $jsonPayload = ConvertTo-Json -Depth 20 -InputObject $Object "[{0}] Webhook test object that will be sent: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $jsonPayload | Write-Verbose try { if ($WhatIf) { Invoke-RestMethodWhatIf -Uri $Destination -Method POST -Body $jsonPayload -ContentType "application/json" -Cmdlet Invoke-RestMethod } else { $Response = Invoke-RestMethod -Uri $Destination -method POST -body $jsonPayload -ContentType "application/json" } if (-not $WhatIf) { "[{0}] Webhook test raw response: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Response | Write-Verbose "[{0}] Webhook '{1}' test successfully send to '{2}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $name, $Destination | Write-Verbose $objStatus.Status = "Complete" $objStatus.Details = "Webhook test successfully sent to '$Destination' using a resource object of type '$typeValue'." } } catch { $errorResponse = $_.Exception.Response if ($errorResponse) { $statusCode = $errorResponse.StatusCode if (-not $WhatIf -and $statusCode -eq 410) { $objStatus.Status = "Failed" $objStatus.Details = "Error: The destination webhook '$Destination' is no longer available!" $objStatus.Exception = $_.Exception.message } elseif (-not $WhatIf) { $objStatus.Status = "Failed" $objStatus.Details = "Webhook test sent to '$Destination' using a resource object of type '$typeValue' was not accepted!" $objStatus.Exception = $_.Exception.message } } } [void] $SendWebhookTestStatus.add($objStatus) } } end { if (-not $WhatIf) { $SendWebhookTestStatus = Invoke-RepackageObjectWithType -RawObject $SendWebhookTestStatus -ObjectName "COM.objStatus.NSDE" Return $SendWebhookTestStatus } } } Function Remove-HPECOMWebhook { <# .SYNOPSIS Removes a webhook resource from a specified region. .DESCRIPTION This Cmdlet removes a webhook resource from a specific region using its name property. .PARAMETER Name The name of the webhook to remove. .PARAMETER Region Specifies the region code of a Compute Ops Management instance provisioned in the workspace (e.g., 'us-west', 'eu-central', etc.) where the webhook should be removed. This mandatory parameter can be retrieved using 'Get-HPEGLService -Name "Compute Ops Management" -ShowProvisioned' or 'Get-HPEGLRegion -ShowProvisioned'. Auto-completion (Tab key) is supported for this parameter, providing a list of region codes provisioned in your workspace. .PARAMETER WhatIf Displays the raw REST API call that would be made to COM instead of executing the request. This option is useful for understanding the inner workings of the native REST API calls used by COM. .EXAMPLE Remove-HPECOMWebhook -Region eu-central -Name "Webhook for servers that become unhealthy" Removes the webhook named 'Webhook for servers that become unhealthy' from the central EU region. .EXAMPLE Get-HPECOMWebhook -Region us-west -Name "Webhook for servers that become unhealthy" | Remove-HPECOMWebhook Removes the webhook named 'Webhook for servers that become unhealthy' from the western US region. .EXAMPLE Get-HPECOMWebhook -Region eu-central | Remove-HPECOMWebhook Removes all webhooks from the central EU region. .EXAMPLE "POSH_webhook_Alert", "POSH_webhook_firmwarebundle" | Remove-HPECOMWebhook -Region eu-central Removes the webhooks named 'POSH_webhook_Alert' and 'POSH_webhook_firmwarebundle' from the central EU region. .INPUTS System.String, System.String[] A single string object or a list of string objects representing the webhooks's names. System.Collections.ArrayList A list of webhooks retrieved from 'Get-HPECOMWebhook'. .OUTPUTS System.Collections.ArrayList A custom status object or array of objects containing the following properties: * Name - The name of the webhook attempted to be removed. * Region - The name of the region where the webhook was removed. * Status - The status of the removal attempt (Failed for HTTP error; Complete if removal is successful; Warning if no action is needed). * Details - Additional information about the status. * Exception - Information about any exceptions generated during the operation. #> [CmdletBinding(DefaultParameterSetName = 'Default')] Param( [Parameter (Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript({ if (($_ -in $Global:HPECOMRegions.region)) { $true } else { Throw "The COM region '$_' is not provisioned in this workspace! Please specify a valid region code (e.g., 'us-west', 'eu-central'). `nYou can retrieve the region code using: Get-HPEGLService -Name 'Compute Ops Management' -ShowProvisioned. `nYou can also use the Tab key for auto-completion to see the list of provisioned region codes." } })] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) # Filter region based on $Global:HPECOMRegions global variable and create completions $Global:HPECOMRegions.region | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } })] [String]$Region, [Parameter (Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [String]$Name, [Switch]$WhatIf ) Begin { $Caller = (Get-PSCallStack)[1].Command "[{0}] Called from: '{1}'" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Caller | Write-Verbose $RemoveWebhookStatus = [System.Collections.ArrayList]::new() } Process { "[{0}] Bound PS Parameters: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($PSBoundParameters | out-string) | Write-Verbose try { $WebhookResource = Get-HPECOMWebhook -Region $Region -Name $Name } catch { $PSCmdlet.ThrowTerminatingError($_) } # Build object for the output $objStatus = [pscustomobject]@{ Name = $Name Region = $Region Status = $Null Details = $Null Exception = $Null } $WebhookID = $WebhookResource.id if (-not $WebhookID) { # Must return a message if not found if ($WhatIf) { $ErrorMessage = "Webhook '{0}': Resource cannot be found in the '{1}' region!" -f $Name, $Region Write-warning $ErrorMessage return } else { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be found in the region!" } } else { $Uri = (Get-COMWebhooksUri) + "/" + $WebhookID # Removal task try { $Response = Invoke-HPECOMWebRequest -Region $Region -Uri $Uri -method DELETE -WhatIfBoolean $WhatIf -Verbose:$VerbosePreference if (-not $WhatIf) { "[{0}] Webhook removal raw response: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), $Response | Write-Verbose "[{0}] Webhook '{1}' successfully deleted from '{2}' region" -f $MyInvocation.InvocationName.ToString().ToUpper(), $name, $Region | Write-Verbose $objStatus.Status = "Complete" $objStatus.Details = "Webhook successfully deleted from $Region region" } } catch { if (-not $WhatIf) { $objStatus.Status = "Failed" $objStatus.Details = "Webhook cannot be deleted!" $objStatus.Exception = $Global:HPECOMInvokeReturnData } } } [void] $RemoveWebhookStatus.add($objStatus) } end { if (-not $WhatIf) { $RemoveWebhookStatus = Invoke-RepackageObjectWithType -RawObject $RemoveWebhookStatus -ObjectName "COM.objStatus.NSDE" Return $RemoveWebhookStatus } } } # Private functions (not exported) function Invoke-RestMethodWhatIf { Param ( $Uri, $Method, $Headers, $Websession, $ContentType, $Body, [ValidateSet ('Invoke-HPEGLWebRequest', 'Invoke-HPECOMWebRequest', 'Invoke-RestMethod', 'Invoke-WebRequest')] $Cmdlet ) process { if ( -not $Body ) { $Body = 'No Body provided' } write-warning "You have selected the 'What-If' option; therefore, the call will not be made. Instead, you will see a preview of the REST API call." Write-host "The cmdlet executed for this call will be:" write-host "$Cmdlet" -ForegroundColor green Write-host "The URI for this call will be:" write-host "$Uri" -ForegroundColor green Write-host "The Method of this call will be:" write-host -ForegroundColor green $Method if ($headers) { Write-host "The Header for this call will be:" $headerString = ($Headers | ConvertTo-Json) -Replace 'Bearer \S+', 'Bearer [REDACTED]' | Out-String $headerString = $headerString.TrimEnd("`r", "`n") Write-host -ForegroundColor green $headerString } if ($websession) { Write-host "The Websession for this call will be:" $websessionString = ($websession.headers | ConvertTo-Json) -Replace 'Bearer \S+', 'Bearer [REDACTED]' | Out-String $websessionString = $websessionString.TrimEnd("`r", "`n") write-host -ForegroundColor green $websessionString } if ( $ContentType ) { write-host "The Content-Type is set to:" write-host -ForegroundColor green $ContentType } if ( $Body ) { write-host "The Body of this call will be:" write-host -foregroundcolor green ($Body -Replace '"access_token"\s*:\s*"[^"]+"', '"access_token": "[REDACTED]"' | Out-String) } } } function Invoke-RepackageObjectWithType { Param ( $RawObject, $ObjectName, [boolean] $WhatIf = $false ) process { if ( $RawObject ) { $OutputObject = @() if ( $WhatIf ) { Return } foreach ( $RawElementObject in $RawObject ) { # "[{0}] Element: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($RawElementObject | out-string) | write-verbose $DataSetType = "HPEGreenLake.$ObjectName" $RawElementObject.PSTypeNames.Insert(0, $DataSetType) # "[{0}] Element PSTypeName set: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($RawElementObject.PSTypeNames[0] | out-string)| write-verbose # "[{0}] Element PSObject TypeNames set: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($RawElementObject.PSObject.TypeNames[0] | out-string)| write-verbose $RawElementObject.PSObject.TypeNames.Insert(0, $DataSetType) # "[{0}] Element PSObject TypeNames set: `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($RawElementObject.PSObject.TypeNames[0] | out-string)| write-verbose $OutputObject += $RawElementObject } # "[{0}] Object typenames : `n{1}" -f $MyInvocation.InvocationName.ToString().ToUpper(), ($OutputObject.PSObject.TypeNames | Out-String) | write-verbose if ($OutputObject.PSObject.TypeNames -notcontains $DataSetType) { # "[{0}] Object typenames added using Add-Member as the object is read only" -f $MyInvocation.InvocationName.ToString().ToUpper() | write-verbose foreach ($item in $OutputObject) { [void]($item | Add-Member -MemberType NoteProperty -Name PSObject.TypeNames -Value @( $DataSetType) -Force) } } return $OutputObject } else { # "[{0}] Null value sent to create object type." -f $MyInvocation.InvocationName.ToString().ToUpper() | Write-Verbose return } } } # Export only public functions and aliases Export-ModuleMember -Function 'Get-HPECOMWebhook', 'New-HPECOMWebhook', 'Set-HPECOMWebhook', 'Send-HPECOMWebhookTest', 'Remove-HPECOMWebhook' -Alias * # SIG # Begin signature block # MIItTQYJKoZIhvcNAQcCoIItPjCCLToCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDwF/Q/sVjIwAZC # jMtYafq5EFAVEGoK0eEQeVH88A8UjKCCEfYwggVvMIIEV6ADAgECAhBI/JO0YFWU # jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI # DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM # EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy # dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv # IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s # hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD # J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 # P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme # me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz # T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q # RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz # mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc # QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T # OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ # AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID # AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD # VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE # VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v # ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE # KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI # hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF # OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC # J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ # pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl # d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH # +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M # UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv # ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5 # NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp # BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G # CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI # ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV # DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3 # 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw # mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm # +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe # dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4 # 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM # dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY # MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU # pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV # HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG # A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1 # YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG # AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl # U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0 # aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh # w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd # OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj # cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc # WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO # hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs # zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7 # 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J # KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH # j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2 # Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/ # L9Uo2bC5a4CH2RwwggZhMIIEyaADAgECAhEAyDHh+zCQwUNyJV9S6gqqvTANBgkq # hkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p # dGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2 # MB4XDTI1MDUyMDAwMDAwMFoXDTI4MDUxOTIzNTk1OVowdzELMAkGA1UEBhMCVVMx # DjAMBgNVBAgMBVRleGFzMSswKQYDVQQKDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJw # cmlzZSBDb21wYW55MSswKQYDVQQDDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlz # ZSBDb21wYW55MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA37AD03qw # cmuCQyxRB2VBM7SfUf0SmpQb8iaPvGmxw5uoDBY3gdC/3Xq/rfM3ndCn03hNdGyu # cpC7tD4zmel6yYqxyXDVr45Jd2cz9jFXoYTOMcuDV6I6CvU/EnbFxWhv0VCp+2Ip # z4+uJGI6aVlMpFpLbgPjhp9ogd/89HEyi1FkSFoarnvxxaXm93S81k7FD/4Edtvu # muGI4V8p39GfbCiMuHku8BzSQ2g86gWFnOaVhY6h4XWvEmE8LPYkU/STrej28Flg # kSt9f/Jg6+dvRKm92uN2Z760Eql9+DTWkGmGe4YrIyD25XDa07sS9tIpVWzLrGOy # ecaVpJwVVBqCadXDgkgTYKw/UlS+cEqsviT6wREGl4aX/GbeNO6Y4oDTTYkabW3p # eg1ku0v90oDqzoTaWEE5ly2UajvXIgzpFLLXqpR6GYkv/y3ZJV0chBqRtAObebH7 # XOBa5a2kqMBw0gkIZBJHd8+PCPH/U7eJkeKXtGGj2uTudcGjZgOjVcFYdCRnufJd # isrV7bj0Hzghcv3QyRXL3rRjcNb4ccKNnSgF/8cmiTVpvFHTfUKsYdkbM6wsbjXR # dJNADjGOYRms7tKsii3/oXO+2S1Um7yomBZQ2+wVRCY6MrRX1onDKid5t5AyWFtR # u0aQcdBmHG6JeDiQ3Hrb2g9kZhuFkgABVBkCAwEAAaOCAYkwggGFMB8GA1UdIwQY # MBaAFA8qyyCHKLjsb0iuK1SmKaoXpM0MMB0GA1UdDgQWBBQH4rUE0gsy8LW2G3vm # oYtOnZ8zEjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAK # BggrBgEFBQcDAzBKBgNVHSAEQzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUF # BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIw # QDA+oDygOoY4aHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29k # ZVNpZ25pbmdDQVIzNi5jcmwweQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjho # dHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NB # UjM2LmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJ # KoZIhvcNAQEMBQADggGBAIax+Yaj5EciDlztft4iAfD2CtIWEF0cxR+UbbvJEs86 # 5wyoO3ZQoujr0FJ+P5fjDKLbamHrEWmyoD2YC4lzecmnFOnY0y4uJ9zBY8B6X6TU # 9e6+TfZtlXd44YffXYAfoLX+uYjVJcZOaMuXF61+CFpjLJjepsD8m1gdj5QUz2sH # 6GOfU6mEm8SHvKpgPMV/yhEKqgjlenY6Ao49RkxnDuvRlMP8SFPB+8bxiLegEdGa # ei8nSr/j5YeDZFevUJ696T4W45QGrwAhBBpbKDz6CzlImC1b2C8Bp02XBAsOQs/u # CIaQv5XxUmVxmb85tDJkd7QfqHo2z1T2NYMkvXUcSClYRuVxxC/frpqcrxS9O9xE # v65BoUztAJSXsTdfpUjWeNOnhq8lrwa2XAD3fbagNF6ElsBiNDSbwHCG/iY4kAya # VpbAYtaa6TfzdI/I0EaCX5xYRW56ccI2AnbaEVKz9gVjzi8hBLALlRhrs1uMFtPj # nZ+oA+rbZZyGZkz3xbUYKTGCGq0wghqpAgEBMGkwVDELMAkGA1UEBhMCR0IxGDAW # BgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMg # Q29kZSBTaWduaW5nIENBIFIzNgIRAMgx4fswkMFDciVfUuoKqr0wDQYJYIZIAWUD # BAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC # NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQx # IgQg/e1ox/JQpzjXtMHrtU5GdIfiU4tTtBmldJfe27AhYDUwDQYJKoZIhvcNAQEB # BQAEggIAc3siYQKTVsMn9g0EX7AQCvTbaWsriZ5obTLJNho4PdXQaS44HO+PcjZt # 9eJ9lEGide+cQa6eXPm9srSAm5a4hxwWGqO8+ZWAcsW8umcpp03pAwpD5vfVuHVq # DDcCIFf0k8IGoWX1ss56rp1tm/RNJalL0gDitX8Tgi8G+Tl3BieURmTw9jTo6q3c # djA/ycn94WwWe/bGK4+unHwnIQ5JNqQqFqt6kzO0BSCuTVpC6ifRj5tyt3pNqSs5 # hJjESthSUB4eIUqum4I2mV4JIFd7Z0+D4CL37xz2PDY1zvbtGambHhpDXqJVRLIz # OuwYfYRSJk957d1Bbix5bgzyKaFzntLoBzpUTzHFYepvtlRMUMrQP7VgnqpNfgEX # 4SbCy2fKt6GaybcyiqF8UH6+QzRsod+A7uOopzc1ntlTgbVfYyaWy22OvIP0HCTL # 5cPJv6eB/zsbEssCDNX62GTcKEwocqQ8Zco54V9ZduhiBmPKL2Spoh/gKdXDApl/ # UNgpqzX7FoljHoT7nd9ilbIwoUctfaCIrFcLIuAt/aVB3/vOyqPcvUbs48xUVi7M # SDMtpfi/AnTCLBeD4bZslTqWPBCUYrJBbS2Gx++UgK8H3JNjV/fgqQibo8t3FPw8 # 79CIE9KFDSkpxD5HQQ4n58zZFYOj+b/YRtsuXTlvssTiUXalEK+hgheXMIIXkwYK # KwYBBAGCNwMDATGCF4Mwghd/BgkqhkiG9w0BBwKgghdwMIIXbAIBAzEPMA0GCWCG # SAFlAwQCAgUAMIGHBgsqhkiG9w0BCRABBKB4BHYwdAIBAQYJYIZIAYb9bAcBMEEw # DQYJYIZIAWUDBAICBQAEMI5cPrpFhWJqh6Um8NnDr5wuSAlgzroJvU5bb2VgiyGx # 7M4CdGVw2DtCxO2zNOT7hgIQGIzLPWH71Cvt0By7wbd0bBgPMjAyNTEwMDIxNTUw # MTFaoIITOjCCBu0wggTVoAMCAQICEAwgQ0n50PdZ+5gt5AgbiHswDQYJKoZIhvcN # AQEMBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw # PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2 # IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAwMDBaFw0zNjA5MDMyMzU5NTla # MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE # AxMyRGlnaUNlcnQgU0hBMzg0IFJTQTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAy # MDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbOVL7i3S35ckN # Udj680nGm/v3iwzc7hRDJyYpFeZguz5hF/O3KXxAnuf9SrE1MpaaN0UNYa/jf5ra # iInjXLE57SwugXHwXVrPYlFNlzt2EDFud75vJ3lt/ZIRmUKu4bHFZKpulRjp0AZE # ILIE5qIVqheGSf4vXl59yiYNKtOcDlWB32m8w77tsz61JbgnMCIhs7aYg/IIR0pi # xyY+X5gG56dI/s0nD2JwvW1amfrW4zpbJQ2/hFzIEDP428ls1/mRMzsXjpy8HCnS # VliKxlH3znLmxiPh7jJQFs8HHKtPlo0xn77m2KzwYOYcKmrJUtDh4sfCmKbmLBHj # 1NER8RO2UQU5FZOQnaE47XPNUBazqO116nXZW0VmhA6EjB1R88dKwDDf3EVV68UQ # V/a74NWvWw5XskAJj7FwbyFYh6o8ZVTCSLIFFROADsd4DElvSJCXgYMELpkEDjAY # 39qEzEXh+4mw6zXPCQ8FKdeYeSbXwfAeAg8qTbzt0whyFnKObvMZwJhnhuKyhRhY # v2hOBr0kJ8UxNz3KXbpcMHTOX2t1LC+I6ZphKVpFqcXzijEBieqAHLpnz3KQ+Bad # vtJGLfU3I/fn1aGiT7fp+TLFM+NKsJa8wrunNtGDy18hGVSfGXsblsiuQ+oxsP3M # mgHv0wcWAuvmWNTuutwvDL5wR+nMUwIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIw # ADAdBgNVHQ4EFgQUVZ6552fIkRBJtDZSjXm3JMU/LfgwHwYDVR0jBBgwFoAU729T # SunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoG # CCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2 # U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5 # NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG # /WwHATANBgkqhkiG9w0BAQwFAAOCAgEAG34LJIfYCWrFQedRadkkjuul0CqjQ9yK # TJXjwu2TlBYWDGkc/1a2NHeWyQQA6TdOzOa43IyJ3tW7EeVAmXgpx1OvlxDZgvL6 # XnrSl4GAzuQDgcImoap1B3ONfKuWDdgJ1+eOz3D/sE7zFSaUBqr8P49Nlk74yfFr # f8ijJiwX4v2BZfhUnFkuWNWzkkqalKiefKwxi/sJqqRCkEOYlZTYXryYstld9TTB # dsPL1BBOySBwe+LJAN4HWXqOX9bA5CJI1M1p9hBRHZmwnms8m7U0/M7WG0rB2JSN # Z6cfCrkFErUFHv4P5PAb3tQdfhXRb4m8VmnzPd3cbmwDs+32o7n/oBZn7TJ/yc3n # wP4cABKEeafLbm3pbuoXpVJFkIikavyFsCN9sGE7gxjwbZT3PBUqnpKWO4qSfF3Z # u6KE7fd2KgIawHq2tf77FAp/hCVhKCAW8P1lZIbjKwk9g7H6FuwFMQ40W2v33Ho6 # AmefJWQOi50if6CZX4Gr5rYb74EtTkBc5VyUTGm6hRBdRkXmnexSt3bVCMX1FrTH # hEPTaBLhfCDM362+5j62OE8gLBeYfcREv588ijFlPReDBU/7XtSpRuLlml7hh1p0 # blaMJMG+2aUzglWi8ZhG/IDJ+ZgknHT/RP6orTnBEmmDirzW84q4JA9oT0f30kJW # 98IMGbgqOsQwgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3 # DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX # BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0 # ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJ # BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGln # aUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAy # NSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphBcr48 # RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6pvF4u # GjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNn # QxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEdgkFi # DNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjUjsZv # kgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bRVFLe # GkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeSLsJy # goLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz # 7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36 # czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQb # U2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0 # qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgw # BgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0jBBgw # FoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQM # MAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6 # MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk # Um9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJ # KoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/T8Ob # XAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQE7jU # /kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKC # hHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA # 0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gxdEkM # x1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qI # ijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcytL5T # TLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEBYTpt # MSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+ # 7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiSuEtQ # vLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZPubdc # MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0BAQwFADBl # MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 # d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv # b3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYDVQQG # EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl # cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7J # IT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxS # D1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb # 7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1ef # VFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoY # OAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSa # M0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI # 8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9L # BADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfm # Q6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDr # McXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15Gkv # mB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E # FgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGL # p6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAkBggrBgEF # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRw # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu # Y3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRVHSAAMA0G # CSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzshV6p # Grsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1W # z/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp # 8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++hUD38dglo # hJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5xaiNrIv8S # uFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDjDCCA4gCAQEwfTBp # MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMT # OERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2 # IDIwMjUgQ0ExAhAMIENJ+dD3WfuYLeQIG4h7MA0GCWCGSAFlAwQCAgUAoIHhMBoG # CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUxMDAy # MTU1MDExWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRyvP2gEH9JNLAHHGEP5teW # UACYdzA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCAy8+OxvaLXsm1PHRuM3b2Pi4R2 # oXie1hLNPKp6nv81wjA/BgkqhkiG9w0BCQQxMgQwNB5kmH1dEswFPKvsfh/YZ8c5 # cW/7geweo16q9z19Dd8mxw3YVZhgFaQx9GJYqXzlMA0GCSqGSIb3DQEBAQUABIIC # ADhVkOovh62wdUEsvVNGlfBjmhxzq7XfcH9UjbPDT9B5eV5mxfPSekVAcclHViMy # B/2kBmBMOAEK3+O13ZZM5hQVFBpL+F1PVeB4Yy7siF2Teu3s6rjEPKNCabe0lFVD # Wc28hj53p+0qIUZurLZYvlu5KI3Tn8TzEY+LSfIwXWK23/AI4Ijl619SUUxgr1fe # hQFcv/7C3BB8ld0RdVmlAP/DVsmkVuNbrLIoW5Pswv2V+IbDO/OnCSwviF3n9AL4 # HGfJmT/R26Z6f6pMhn0XHn37OocveHVpxqBUfHKcpy5KLXvyHqQ1tud1l+cDsh2k # NhQQjAwFtXj5a69lNcfHwYDmB+j7WodiO8aEzFAAETCGlzf12LPUyUvZdHrbbfvY # W1G59pU9jT2PuevowSDC048043ek/m06c81m7Oq2SPp3RWJu0SwDR5LX0huzflBC # YdP+3Rblrye/26ka0Va2OLVeut3rDEiLFwFzX2oOsACLKaAxOvganBczUqB+BMk6 # CIPnWU/EM1qforz7teHOGnbWOw29TJPTEY1LHiG0EVmFNJHxsDagdOfLcz9cB+pN # nTttmdqgHUZ3oEYKxS4I0BDIlEynUWF1BFNwFG4FmoAm3hUm+0ilb9/ve+84Q9Nf # G2NDSRPrY+js0EX1a58zIr9E7fBz2MP/vk9gJpQ5rW0y # SIG # End signature block |