MSCommerce.psm1

################################
# Start: Platform gate
# WAM broker authentication (introduced in MSCommerce 3.0 for ICM 796868403)
# requires Windows. Fail fast with a clear message on non-Windows PS Core hosts
# rather than letting a confusing MSAL/native exception surface later.
################################

if ($PSVersionTable.PSEdition -eq 'Core' -and -not $IsWindows) {
    throw "MSCommerce requires Windows. WAM broker authentication is unavailable on $($PSVersionTable.OS)."
}

################################
# End: Platform gate
################################

################################
# Start: P/Invoke helpers for WAM parent window
################################

if (-not ('MSCommerceNativeMethods' -as [type])) {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
public static class MSCommerceNativeMethods {
    [DllImport("kernel32.dll")]
    public static extern IntPtr GetConsoleWindow();
 
    [DllImport("user32.dll", ExactSpelling = true)]
    public static extern IntPtr GetAncestor(IntPtr hwnd, uint flags);
 
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
 
    /// <summary>
    /// Returns a window handle suitable for WAM's modal authentication dialog.
    /// Tries three sources in order: console window (works in conhost/cmd),
    /// current process main window, and foreground window (works in Windows Terminal).
    /// </summary>
    public static IntPtr GetConsoleOrTerminalWindow() {
        IntPtr hwnd = GetConsoleWindow();
        if (hwnd != IntPtr.Zero)
            return GetAncestor(hwnd, 3 /* GetRootOwner */);
 
        hwnd = Process.GetCurrentProcess().MainWindowHandle;
        if (hwnd != IntPtr.Zero)
            return hwnd;
 
        return GetForegroundWindow();
    }
}
"@

}

################################
# End: P/Invoke helpers
################################

################################
# Start: Module-scope caches
# ICM 796868403: A singleton PublicClientApplication per ClientId is required.
# Building a fresh PCA on every Connect-MSCommerce call put the WAM broker into
# a bad state on the second invocation (Tag 0x1e3d43d2 / unknown_broker_error).
# The Microsoft Learn WAM reference sample also builds exactly one PCA and
# reuses it across acquisitions. The IAccount cache lets us prime
# AcquireTokenSilent with the exact account from the prior successful sign-in,
# avoiding the multi-account heuristic the original M-1 refinement used. The
# AuthResult cache short-circuits repeated Connect-MSCommerce calls when the
# previously issued access token is still valid (true no-op idempotency: avoids
# touching MSAL/WAM at all on the second call).
#
# Cache keys are $ClientId only. If future changes add tenant/authority/cloud
# options to the PCA builder, the key must be expanded to include them.
################################

$script:PCACache = @{}
$script:AccountCache = @{}
$script:AuthResultCache = @{}

################################
# End: Module-scope caches
################################

################################
# Start: Internal use functions
################################

function Get-AccessTokenFromSessionData() {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)]
    [System.Management.Automation.SessionState]
    $SessionState
  )

  if ($null -eq $SessionState.PSVariable) {
    throw "unable to access SessionState. PSVariable, Please call Connect-MSCommerce before calling any other Powershell CmdLet for the MSCommerce Module"
  }

  $token = $SessionState.PSVariable.GetValue("token");

  if ($null -eq $token) {
    throw "You must call the Connect-MSCommerce cmdlet before calling any other cmdlets"
  }

  return $token
}

function HandleError() {
  param(
    [Parameter(Mandatory = $true)]
    $ErrorContext,

    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $CustomErrorMessage
  )

  $errorMessage = $ErrorContext.Exception.Message
  $errorDetails = $ErrorContext.ErrorDetails.Message

  if ($_.Exception.Response.StatusCode -eq 401) {
    Write-Error "Your credentials have expired. Please, call Connect-MSCommerce again to regain access to MSCommerce Module."

    return
  }

  write-error "$CustomErrorMessage, ErrorMessage - $errorMessage ErrorDetails - $errorDetails"
}

################################
# End: Internal use functions
################################


################################
# Start: Exported functions
################################

<#
    .SYNOPSIS
    Method to connect to MSCommerce with the credentials specified.
    Uses WAM (Web Account Manager) broker for secure authentication,
    eliminating the SR13 authorization-code phishing vulnerability
    from the previous loopback redirect URI flow (ICM 796868403).
#>

function Connect-MSCommerce() {
  [CmdletBinding()]
  param(
    [string]
    $ClientId = "3d5cffa9-04da-4657-8cab-c7f074657cad",

    [string]
    $Resource = "aeb86249-8ea3-49e2-900b-54cc8e308f85/.default"   #LicenseManager App Id
  )

  # Build or reuse the singleton PublicClientApplication for this ClientId.
  # See ICM 796868403 PCA-reuse spec doc — per-call PCA construction collides
  # with the native broker channel lifecycle and causes the second
  # Connect-MSCommerce in a session to fail with Tag 0x1e3d43d2.
  # The WithParentActivityOrWindow Func is re-evaluated by MSAL on each
  # AcquireToken call, so the cached PCA still picks up the current top-level
  # window even if the user switched terminal windows since the last call.
  if (-not $script:PCACache.ContainsKey($ClientId)) {
    $brokerOptions = [Microsoft.Identity.Client.BrokerOptions]::new(
        [Microsoft.Identity.Client.BrokerOptions+OperatingSystems]::Windows
    )

    $builder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientId)
    $builder = $builder.WithDefaultRedirectUri()
    $builder = $builder.WithParentActivityOrWindow([System.Func[System.IntPtr]] {
        [MSCommerceNativeMethods]::GetConsoleOrTerminalWindow()
    })
    $builder = [Microsoft.Identity.Client.Broker.BrokerExtension]::WithBroker($builder, $brokerOptions)
    $script:PCACache[$ClientId] = $builder.Build()
  }
  $clientApplication = $script:PCACache[$ClientId]

  $scopes = New-Object Collections.Generic.List[string]
  $scopes.Add($Resource)

  # Fast-path idempotency: if we have a cached AuthenticationResult for this
  # ClientId whose access token is still valid (with a 5-minute safety margin
  # to allow downstream API calls time to complete), reuse it without touching
  # MSAL or the WAM broker at all. This is the strongest form of idempotency
  # for repeated Connect-MSCommerce calls (user requirement #4) and serves as
  # a safety net if the WAM "second broker operation" bug isn't fully resolved
  # by PCA reuse alone.
  $cachedAuth = $script:AuthResultCache[$ClientId]
  if ($null -ne $cachedAuth -and $cachedAuth.ExpiresOn -gt [DateTimeOffset]::UtcNow.AddMinutes(5)) {
    $sessionState = $PSCmdlet.SessionState
    $sessionState.PSVariable.Set("token", $cachedAuth.AccessToken)
    Write-Verbose "Reusing cached access token (expires $($cachedAuth.ExpiresOn.UtcDateTime.ToString('o')))"
    Write-Host "Connection established successfully"
    return
  }

  # Silent-first acquisition (Microsoft Learn WAM reference pattern).
  # We only attempt silent acquisition when $script:AccountCache has an
  # IAccount from a prior successful sign-in. On a cold cache (first Connect
  # after Import-Module), skip silent and go straight to interactive — this
  # preserves the explicit account-picker UX customers expect on first call
  # and avoids silently authenticating as an arbitrary cached WAM account.
  # Only MsalUiRequiredException triggers the interactive fallback; any other
  # exception bubbles to the outer try/catch.
  $authenticationResult = $null
  try {
    $cachedAccount = $script:AccountCache[$ClientId]
    if ($null -ne $cachedAccount) {
      try {
        $authenticationResult = $clientApplication.AcquireTokenSilent($scopes, $cachedAccount).
            ExecuteAsync().GetAwaiter().GetResult()
      } catch [Microsoft.Identity.Client.MsalUiRequiredException] {
        Write-Verbose "Silent token acquisition requires UI: $($_.Exception.Message)"
        # Clear the stale account so a successful interactive sign-in below
        # can replace it with the fresh IAccount the user actually picked.
        $script:AccountCache.Remove($ClientId)
      }
    }

    if ($null -eq $authenticationResult) {
      $authenticationResult = $clientApplication.AcquireTokenInteractive($scopes).
          ExecuteAsync().GetAwaiter().GetResult()
    }
  } catch {
    Write-Error "Unable to establish connection: $($_.Exception.Message)"
    return
  }

  $token = $authenticationResult.AccessToken

  if ($null -eq $token) {
    Write-Error "Unable to establish connection"

    return
  }

  # Cache the account and full AuthenticationResult for the next call:
  # AccountCache primes the silent path; AuthResultCache enables the fast-path
  # above when the token is still within its lifetime.
  $script:AccountCache[$ClientId] = $authenticationResult.Account
  $script:AuthResultCache[$ClientId] = $authenticationResult

  $sessionState = $PSCmdlet.SessionState

  $sessionState.PSVariable.Set("token", $token)

  Write-Host "Connection established successfully"
}

<#
    .SYNOPSIS
    Method to retrieve configurable policies
#>

function Get-MSCommercePolicies() {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $false)]
    [string] $Token
  )

  if (!$Token) {
    $Token = Get-AccessTokenFromSessionData -SessionState $PSCmdlet.SessionState
  }
  $correlationId = New-Guid
  $baseUri = "https://licensing.m365.microsoft.com"

  $restPath = "$baseUri/v1.0/policies"

  try {
    $response = Invoke-RestMethod `
      -Method GET `
      -Uri $restPath `
      -Headers @{
        "x-ms-correlation-id" = $correlationId
        "Authorization" = "Bearer $($Token)"
      }

    foreach ($policy in $response.items) {
      New-Object PSObject -Property @{
        PolicyId = $policy.id
        Description = $policy.description
        DefaultValue = $policy.defaultValue
      }
    }
  } catch {
    HandleError -ErrorContext $_ -CustomErrorMessage "Failed to retrieve policies"
  }
}

<#
    .SYNOPSIS
    Method to retrieve a description of the specified policy
#>

function Get-MSCommercePolicy() {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $PolicyId,
    [Parameter(Mandatory = $false)]
    [string] $Token
  )

  if (!$Token) {
    $Token = Get-AccessTokenFromSessionData -SessionState $PSCmdlet.SessionState
  }

  $correlationId = New-Guid
  $baseUri = "https://licensing.m365.microsoft.com"

  $restPath = "$baseUri/v1.0/policies/$PolicyId"

  try {
    $response = Invoke-RestMethod `
      -Method GET `
      -Uri $restPath `
        -Headers @{
        "x-ms-correlation-id" = $correlationId
        "Authorization" = "Bearer $($Token)"
      }

    New-Object PSObject -Property @{
      PolicyId = $response.id
      Description = $response.description
      DefaultValue = $response.defaultValue
    }
  } catch {
    HandleError -ErrorContext $_ -CustomErrorMessage "Failed to retrieve policy with PolicyId '$PolicyId'"
  }
}

<#
    .SYNOPSIS
    Method to retrieve applicable products for the specified policy and their current settings
#>

function Get-MSCommerceProductPolicies() {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $PolicyId,
    [Parameter(Mandatory = $false)]
    [string] $Scope,
    [Parameter(Mandatory = $false)]
    [string] $Token
  )

  if (!$Token) {
    $Token = Get-AccessTokenFromSessionData -SessionState $PSCmdlet.SessionState
  }
  $correlationId = New-Guid
  $baseUri = "https://licensing.m365.microsoft.com"

  $query = "scope=product"
  if($false -eq [string]::IsNullOrWhiteSpace($Scope)){
    $query = "scope=$Scope"
  }
  
  $restPath = "$baseUri/v1.0/policies/$PolicyId/products"
  if($false -eq [string]::IsNullOrWhiteSpace($query)){
    $restPath += "?$query"
  }

  try {
    $response = Invoke-RestMethod `
      -Method GET `
      -Uri $restPath `
      -Headers @{
        "x-ms-correlation-id" = $correlationId
        "Authorization" = "Bearer $($Token)"
      }

    foreach ($product in $response.items) {
      $properties = @{}
      $properties.Add("PolicyId", $product.policyId)
      $properties.Add("PolicyValue", $product.policyValue)

      if ($product.scope -eq "product") {
        $properties.Add("ProductName", $product.productName)
        $properties.Add("ProductId", $product.productId)
      }
      else {
        $properties.Add("ScopeId", $product.scopeId)
        $properties.Add("ScopeValue", $product.scopeValue)
        $properties.Add("Scope", $product.scope)
      }
      New-Object PSObject -Property $properties
    }
  } catch {
    HandleError -ErrorContext $_ -CustomErrorMessage "Failed to retrieve product policy with PolicyId '$PolicyId'"
  }
}

<#
    .SYNOPSIS
    Method to retrieve the current setting for the policy for the specified product
#>

function Get-MSCommerceProductPolicy() {
  [CmdletBinding(DefaultParameterSetName = "Product")]
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $PolicyId,
    [Parameter(Mandatory = $true, ParameterSetName = "Product")]
    [ValidateNotNullOrEmpty()]
    [string] $ProductId,
    [Parameter(Mandatory = $true, ParameterSetName = "OfferType")]
    [ValidateNotNullOrEmpty()]
    [string] $OfferType,
    [Parameter(Mandatory = $false)]
    [string] $Token
  )

  if (!$Token) {
    $Token = Get-AccessTokenFromSessionData -SessionState $PSCmdlet.SessionState
  }
  $correlationId = New-Guid
  $baseUri = "https://licensing.m365.microsoft.com"

  $restPath = "$baseUri/v1.0/policies/$PolicyId"
  if ($PSBoundParameters.ContainsKey("OfferType")) {
    $restPath += "/offerTypes/$OfferType"
  }
  else {
    $restPath += "/products/$ProductId"
  }

  try {
    $response = Invoke-RestMethod `
      -Method GET `
      -Uri $restPath `
      -Headers @{
        "x-ms-correlation-id" = $correlationId
        "Authorization" = "Bearer $($Token)"
      }

    $properties = @{}
    $properties.Add("PolicyId", $response.policyId)
    $properties.Add("PolicyValue", $response.policyValue)

    if ($PSBoundParameters.ContainsKey("ProductId")) {
      $properties.Add("ProductName", $response.productName)
      $properties.Add("ProductId", $response.productId)
    }
    else {
      $properties.Add("Scope", $response.scope)
      $properties.Add("ScopeValue", $response.scopeValue)
      $properties.Add("ScopeId", $response.scopeId)
    }
    New-Object PSObject -Property $properties
  } catch {
    HandleError -ErrorContext $_ -CustomErrorMessage "Failed to retrieve product policy with PolicyId '$PolicyId' ProductId '$ProductId'"
  }
}

<#
    .SYNOPSIS
    Method to modify the current setting for the policy for the specified product
#>

function Update-MSCommerceProductPolicy() {
  [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium', DefaultParameterSetName = "ProductEnum")]
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $PolicyId,
    [Parameter(Mandatory = $true, ParameterSetName = "ProductToggle")]
    [Parameter(Mandatory = $true, ParameterSetName = "ProductEnum")]
    [ValidateNotNullOrEmpty()]
    [string] $ProductId,
    [Parameter(Mandatory = $true, ParameterSetName = "OfferTypeToggle")]
    [Parameter(Mandatory = $true, ParameterSetName = "OfferTypeEnum")]
    [string] $OfferType,
    [Parameter(Mandatory = $true, ParameterSetName = "ProductToggle")]
    [Parameter(Mandatory = $true, ParameterSetName = "OfferTypeToggle")]
    [ValidateNotNullOrEmpty()]
    [string] $Enabled,
    [Parameter(Mandatory = $true, ParameterSetName = "ProductEnum")]
    [Parameter(Mandatory = $true, ParameterSetName = "OfferTypeEnum")]
    [ValidateSet("Enabled", "Disabled", "OnlyTrialsWithoutPaymentMethod")]
    [string] $Value,
    [Parameter(Mandatory = $false)]
    [string] $Token
  )

  if ($PSBoundParameters.ContainsKey("Enabled")) {
    if ("True" -ne $Enabled -and "False" -ne $Enabled) {
      Write-Error "Value of `$Enabled must be one of the following: `$True, `$true, `$False, `$false"
      return
    }
  }

  if (!$Token) {
    $Token = Get-AccessTokenFromSessionData -SessionState $PSCmdlet.SessionState
  }
  $correlationId = New-Guid
  $baseUri = "https://licensing.m365.microsoft.com"

  $restPath = "$baseUri/v1.0/policies/$PolicyId"
  if ($PSBoundParameters.ContainsKey("OfferType")) {
    $restPath += "/offerTypes/$OfferType"
  }
  else{
    $restPath += "/products/$ProductId"
  }

  if ($PSBoundParameters.ContainsKey("Enabled")) {
    $policyValue = if ("True" -eq $Enabled -or "true" -eq $Enabled) {"Enabled"} else {"Disabled"}
  }
  else {
    $policyValue = $Value
  }

  $body = @{
    policyValue = $policyValue
  }

  if ($False -eq $PSCmdlet.ShouldProcess("ShouldProcess?")) {
    Write-Host "Updating product policy aborted"

    return
  }

  try {
    $response = Invoke-RestMethod `
      -Method PUT `
      -Uri $restPath `
      -Body ($body | ConvertTo-Json)`
      -ContentType 'application/json' `
      -Headers @{
        "x-ms-correlation-id" = $correlationId
        "Authorization" = "Bearer $($Token)"
      }

    Write-Host "Update policy product success"
    $properties = @{}
    $properties.Add("PolicyId", $response.policyId)
    $properties.Add("PolicyValue", $response.policyValue)

    if ($PSBoundParameters.ContainsKey("ProductId")) {
      $properties.Add("ProductName", $response.productName)
      $properties.Add("ProductId", $response.productId)
    }
    else {
      $properties.Add("Scope", $response.scope)
      $properties.Add("ScopeValue", $response.scopeValue)
      $properties.Add("ScopeId", $response.scopeId)
    }
    return New-Object PSObject -Property $properties
  }
  catch {
    HandleError -ErrorContext $_ -CustomErrorMessage "Failed to update product policy"
  }
}

################################
# End: Exported functions
################################

Write-Host "MSCommerce module loaded"

# SIG # Begin signature block
# MIInKwYJKoZIhvcNAQcCoIInHDCCJxgCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA99uZgymGzyA9X
# /09K5VvuVUJRw/E7fM4Ux+bSNapwx6CCDLowggX1MIID3aADAgECAhMzAAACHU0Z
# yE7XD1dIAAAAAAIdMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQzWhcNMjcwNDE1MTg1
# OTQzWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDQvewXxx9gZZFC6Ys1WBay8BJ8kGA4JQnH5CMafqOASlTpK9H8
# o5ZXTXt0caVQTNMUPt445wXYD+dFtaKWTwDn1I52oUSrC9vJin1Gsqt+zyKJL5Dg
# 3eQXbQNR61DmMy20GLTIO3SFed9Rfi/ophgCLGFLDR3r0KvHjwMb/jYWS0celV/4
# Lz27LfAekm8v9E5IXaeiXbAUYZKK090n4CVl3JBtbN+9DtI9SNu/yjvozW52/u7R
# X/Ttpa/KDlpuokZ+Zcbvmtd9ur9gFLvZzh41o9MsE/clQtdaFWGvuo6Jua/ntpgk
# ey3E5/vBFe+MJPG6phdnuo6r57ZudCudiI1bAgMBAAGjggGbMIIBlzAOBgNVHQ8B
# Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# BBYEFH6QuMwqcPG0hQlQ6c5jCtTTLrVeMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQL
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAxMis1MDc1NTkw
# HwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEwYAYDVR0fBFkwVzBVoFOg
# UYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0
# JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNybDBtBggrBgEFBQcBAQRh
# MF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# Y2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# dDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBKTbYOjzwTG/DXGaz9
# s6+fQeaTtDcFmMY+5UyVFCyj7Pv+5i37qfX8lSL/tBIfYQfWsMuBQlfZurJD6r4H
# VJ2CeH+1fgiq8dcHdVKoZ3Sa2qXoX3cq9iS8cVb06B7+5/XJ7I0OxHH9fDsvJ3T3
# w5V/ZtAIFmLrl+P0CtG+92uzRsn0nTbdFjOkLMLWPLAU3THohKRlSEMgFJpPkm5n
# 5UAZ35xX6FWCrDLsSKb555bTifwa8mJBwdlof0bmfYidH+dxZ1FdDxvLnNl9zeKs
# A4kejaaIqqIPguhwAti5Ql7BlTNoJNwxCvBmqW2MQLnCkYN/VVUsR3V2x/rcTNzo
# Bf/Z/SpROvdaA2ZOOd1uioXJt3tdLQ7vHpqpib0KfWr/FWXW10q38VxfCnRQBqzb
# SuztR7nEMuzX7Ck+B/XaPDXd1qh72+QYyB0Z2VzWmO9zsnb9Uq/dwu8LGeQqnyu6
# 7SDGACvnXii2fb9+US492VTnXSnFKyqwgzUyFMtZK1/sHYTv6bG4TtQUygQxTN+Z
# V+aJIlKO2MqZ7bKrAnOzS9m6NgoTdWOq11bTOZwKlIEV/EhV9SWkDmdpR/hPPT2v
# 6TEj4F8PT/zHjRezIU5c/DGlt/VhY/pK0XkJtEyMmmS1BMtjU/rqBZVMIm3dnxQs
# /TBByr+Cf8Z1r7aifQVQ+WSqzjCCBr0wggSloAMCAQICEzMAAAA5O7Y3Gb8GHWcA
# AAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl
# IEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoXDTM2MDMyMjIyMTMwNFow
# VzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEo
# MCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAyNDCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeqlRYHNa265v4IY9fH8TKh
# emHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo0dtS/EW6I/yEL/bLSY8h
# KpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATvQVL4tcf03aTycsz8QeCd
# M0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a1uv1zerOYMnsneRRwCbp
# yW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1FyQfK0fVkaya8SmVHQ/t
# Of23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfOGSWHIIV4YrTJTT6PNty5
# REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7ttOu1bVnXfHaqPYl2rPs
# 20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJuz2MXMCt7iw7lFPG9LXK
# Gjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxSCwyoGIq0PhaA7Y+VPct5
# pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOmVQop36wUVUYklUy++vDW
# eEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3SkE/xIkgpfl22MM1itkZ
# 35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGC
# NxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPXLQaUEggxMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
# ci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2Ny
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAx
# MV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx
# MV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAFJQfOChP7onn6fLI
# MKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D5W4wMwYeLystcEqfkjz4
# NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBYnbu0+THSuVHTe0VTTPVh
# ily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSIvgn0JksVBVMYVI5QFu/q
# hnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6aR9y34aiM1qmxaxBi6OU
# nyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4wPKC5OmHm1DQIt/MNokbb
# H3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7RTX8AdBPo0I6OEojf39z
# uFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK/fg8B2qjW88MT/WF5V5u
# vZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSKYBv0VisCzfxgeU+dquXW
# 9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkwYTu/9dLeH2pDqeJZAABV
# DWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVTQl0v4q8J/AUmQN5W4n10
# 1cY2L4A7GTQG1h32HHAvfQESWP0xghnHMIIZwwIBATBuMFcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
# c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIdTRnITtcPV0gAAAAAAh0w
# DQYJYIZIAWUDBAIBBQCggZAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwLwYJ
# KoZIhvcNAQkEMSIEIEH8q50iPMCz3Jwpk8QIFmcme3Tf686xJ//z/eZKj3RaMEIG
# CisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAMTkiqc7vlLojc0XS
# zuCe4uol2ojHfH3gW1hHmy0gpV63iGbvxU7/bxk4HQdE/ikylYTWqgSVzp4t+P0r
# VoBtws7yjQmFBVTKotb6lb02bsi3lw1ZGjlZJj+oyuRDuvRAPX9hDsaDk8msCy+I
# Y9P3l0qV+IIG4+j0yi9qN5FSpOak4qQlyFAxmsPlFTUDfvO1mztwMKsrCFAC/eHI
# c9PVEBgfGCMcEk8rrwk3cpb3DUN/JDEtxptsgllR6/f4tg2oZuXw8TFuDiom3pfi
# rwutAlzT6uEmhjuvyRMCMZiEdAj00P49dgl0/fF2rRmdyUGVLnUNCHq8zQxZUsZU
# SiZ4kKGCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCCF38GCSqGSIb3DQEHAqCCF3Aw
# ghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsqhkiG9w0BCRABBKCCAUEEggE9
# MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCBka9e5yoVbrJ7y
# tICe37dlDDKdUNVqA/7fzWQHuY78KwIGaoWumFKJGBMyMDI2MDgyMTE5MjEwMS44
# NjJaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScw
# JQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzMwMy0wNUUwLUQ5NDcxJTAjBgNVBAMT
# HE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WgghHtMIIHIDCCBQigAwIBAgIT
# MwAAAiEzwDX70g8hpAABAAACITANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNjAyMTkxOTM5NTRaFw0yNzA1MTcxOTM5NTRa
# MIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL
# ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxk
# IFRTUyBFU046MzMwMy0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1l
# LVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDb
# cTACqU1YvRocyWL2PL9fyf/+ULs2qK7U1aZsRnDZSnlCr7K7jgA3eFCEJL5BZ7dU
# TC0DeZepf+ZC+7HEbB4IdzmJfQAUDFFerqY5VTHmQvP2XA3lWSFj740idcGUHglP
# 5H/PbCJU7GAHWP2HdcCjdx1lYAo0A+zLI7xwnTQeMyOXX212Eg4UmDPPJgxdTMw6
# WFVWsBPWRBi5gDixy2s+7R8ADk5lbBBFDB5h0CjrNWIN7uCAzF5g7trrL8nXIKp1
# 0mj9RxhcGQ+tlht6VIvdygRVTUGdzFB2/nBvJqQ9kxxFltQST70fEdx4TyaKow/f
# 5+BSh4z4/9f7NXIVVTLn/8kcJAfRqFmRrrFt3IKby7VrzmYuoQWD0lmNFtGQ57Br
# JkPrPFAPek1ALtcbb7FH3nQpvi8ngz/MFX/+cnmNFWFU29VVLmzB9XvLZxbYvkee
# tt0mh5lfteeN2rEwUyrdrKufz9h2S6pbate+C2h02CrXwSka0x6ezpTmGkIJLFt2
# 5ub/UYXNLdHdsxGD6EfckOIoJYsm4MS9F/vSqLNHK89I0vTLBngQEp6LIFkINanR
# T3PtNx3pNKRKJRALc6L6mhW4hL4aHL749qPfQ72t5qAMm5xiKYMgJ2WanidRLNuI
# 251JIN7raaeA/2vb0XFkZcIbTR1pfQGsco4U0g5tjwIDAQABo4IBSTCCAUUwHQYD
# VR0OBBYEFOYjIs5qa6pfuquPyyK1FTr5QDCnMB8GA1UdIwQYMBaAFJ+nFV0AXmJd
# g/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
# MjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGlt
# ZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0l
# AQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA
# A4ICAQA4I/3bkdnTxD2rFum3MF8xVKdEkohAObbePrQ+0fr5bRimjz9sVkKT/7gc
# j4OMcClSYG+IdX6Mp3EYsLHWfjvwfzFoeZE+yTbdBj/1VHZQRuCmw6QqeVCTbw2n
# nS7nBxnWd9oZXbPUpqEawH5DqXQaWFgR9A4KWVK/IvXVDMj1PlPCES1P3JonNbdh
# kkkz49rJuKOm5b7e/BH8loqAmXOXRc22yxWVTMWrEp4pslmv8eT7VoY8X/jdKYTP
# VEXsfmLbVFcqzMuB8vFGfUyWsWROS8wgq7lQYfWcYqh7NymoATX+wWYK3zWG7aRc
# iPGUAzznXdf+aHtIWnQLNa5HFmSXkiak3fSuprWYZiHhuYjE16hroApcBHpm+8S/
# kNqhm9WjQX+2BxnYv+Jejy6lqTi8fLBLS069WXVw/ptf5IV+FtYl34GvVoeg31Uo
# UmVVZe1SDUJkm9dDXc8l/qBDYiAIT2CCsPTyt9XA9JVuHxdP63n7ChvWAO/47QRu
# CDsUlFJoWwyBwl7jeYpaRVMtQt0iuJMGGjgEaJX1Q/2j8sXURvTceLHDD9ipWt09
# 2ZDWMQciDRmhHNFOX1dnjBvk/k1UMcg997j5oYznAnSpJvlg/4BP3aVE0h/YH2Kg
# sKbU4NXZHAjJXj2Slqo1C115CG6qBZaFkM8W6vPZCm5qnSezOjCCB3EwggVZoAMC
# AQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIy
# NVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9
# DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2
# Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N
# 7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXc
# ag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJ
# j361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjk
# lqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37Zy
# L9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M
# 269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLX
# pyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLU
# HMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode
# 2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEA
# ATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYE
# FJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEB
# MEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# RG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEE
# AYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
# /zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEug
# SaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N
# aWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsG
# AQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jv
# b0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt
# 4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsP
# MeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++
# Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9
# QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2
# wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aR
# AfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5z
# bcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nx
# t67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3
# Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+AN
# uOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/Z
# cGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQMIICOAIBATCB+aGB0aSBzjCB
# yzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMc
# TWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBU
# U1MgRVNOOjMzMDMtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1T
# dGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQALbEgZZnyYHXJ1DGb5fGjplXpt
# uaCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3
# DQEBCwUAAgUA7jLPpTAiGA8yMDI2MDgyMTEzMjI0NVoYDzIwMjYwODIyMTMyMjQ1
# WjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDuMs+lAgEAMAoCAQACAiJjAgH/MAcC
# AQACAhKiMAoCBQDuNCElAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkK
# AwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBADry
# t/6VUAHC70HcyLnmbcJVWMIAxdQhrwujpXcQdZaLV5+WpkwhXjaIkL0kmDIB+4hk
# UoZAKxLpSj6enPQPAtS3wqobqbAN+XUrTXvQa3+qZWIOosAaWA/IVKdPMunN1MCw
# kfUuZ/Z15TTl/7PN05idUw3PFDzasZSPsgFkANQ/1XiczgY21jIjuQBEcGS+Vj6U
# 04ddiIv6qc1wSdTi1R61Q+gVcy9WNEO4fBl7pVhp4RsNbC3i2R3cicooXI3nl9Gu
# YEYH6QT1BwoJV05KTSSRzKwgfdfyURI/1kZLBs7byDokKKF4gP6LuqnBtLWkR4/c
# 6Kvv6DCW/wyDulO55S8xggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt
# cCBQQ0EgMjAxMAITMwAAAiEzwDX70g8hpAABAAACITANBglghkgBZQMEAgEFAKCC
# AUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCCy
# bgOVLRbosAt5bWHH/l12KzIRhj8LmEaoKg9TzwGqCzCB+gYLKoZIhvcNAQkQAi8x
# geowgecwgeQwgb0EIADvIQefFVUa4BJy8IZywMAvmGSKdUVqEmy9A++PCj1EMIGY
# MIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIhM8A1+9IP
# IaQAAQAAAiEwIgQgvsWPMfVkS9pUI3E0xrKH/0DyRTGzhoIMz6hkKy5NJoIwDQYJ
# KoZIhvcNAQELBQAEggIAUT+Q6mpnh0tPQ8iBT95ZttiCR8JNTZPB3hgbahTIX33m
# a7lH6aLVZsejaM7caQxH32iLjPez91RhdW3Eu9Knz4SV/H5538tNJ2TdQfRXOLMm
# q0SItlDQE37/GIBnJPhosny7ooSTnlbpdOiRwEo+elXl4agu8ZzaPQVTPdMMwVdp
# Ng5pqXe45YVUWXcCf1cWxGU3a/aRyjJdAdq2sfX0/uurTOqhqV/Y0h3i6GSI3Ce7
# OYjZjwtpxhae+LTBJWJTYtAB5hGFDBjjhjJ/0qgz0KeWMR9FHWcCd3N5FIRvGRHc
# HNlYKubYjNuVNsZUfAZas66XFatlJVASIvq+tFf2TPUstSf8qPIuEUPVRgXMji9F
# P0ayqgk4LVYQFx97aZ5cBsx47xYFXHEr+8Slt0GcPX6l3AOg8nHr7wPFiODW5gxY
# YWMyzLn4W8dfF9vudxSsoC87KdDflEbFY428BCojI+LZJLDe7wvMlUCTZyjlag2o
# DiyAZQAREV3BzjGjemy5eqjbdgkpnO9C6hycqg5rqHerVYPiyTCHtlYHdHH54blH
# Ygr5v74nL9Uyjf7DrEWbyNUE5LjqmRcRMz888pwJAum/kwxnEhn+QIl3cTE59gTJ
# F0EK/+cJf4oMVtmag+vL5TlIflNHZ1P6VfSvgLWJ9p6P+lB/5l+8XkaR688F1aQ=
# SIG # End signature block