<#
.SYNOPSIS
    Module containing generic cmdlets for fault handling.

.DESCRIPTION
    Copyright © 2019 Microsoft. All rights reserved.
#>

<#
.SYNOPSIS
    Call to invoke a command with a backoff / retry on failure

.PARAMETER Command
    The script block of the command to execute.
    
.PARAMETER ArgumentList
    The list of arguments to pass to the command block.
    
.PARAMETER CommandOutput
    Reference parameter that is set to the Command output from the last attempt executed. 
    Note: if the TimeoutAction block is executed this will contain the output from that block's execution.
    
.PARAMETER RetryIntervalSec
    The retry interval in seconds. The sleep between attempts will multiply this value against the attempt number.
    
.PARAMETER TimeoutSeconds
    The maximum number of seconds to continue attempting retries from the start of the first attempt.
    Note: this is not a timeout on the command block execution. If the Command execution exceeds this 
    time it will not attempt a retry in the case of failure. Instead it will immediately proceed to 
    executing the TimeoutAction block (if specified).
    
.PARAMETER Logger
    Script block used to log execution messages.
    
.PARAMETER TimeoutAction
    The action to run if all retries have been exhausted.
    
.PARAMETER TreatTimeoutActionAsSuccess
    When specified, treat successful execution of TimeoutAction as success.
#>
[CmdletBinding]
function Invoke-RetryWithBackoff(
  [Parameter(Mandatory = $true)]
  [scriptblock] $Command, 
  
  [Parameter(Mandatory = $false)]
  [object[]] $ArgumentList = $(),
  
  [Parameter(Mandatory = $false)]
  [ref] $CommandOutput,

  [Parameter(Mandatory = $false)]
  [int]$RetryIntervalSec = 5, 
  
  [Parameter(Mandatory = $false)]
  [int]$TimeoutSeconds = 300, 
  
  [Parameter(Mandatory = $false)]
  [scriptblock]$Logger = {param($message) Write-Output $message},
  
  [Parameter(Mandatory = $false)]
  [scriptblock]$TimeoutAction,
  
  [Parameter(Mandatory = $false)]
  [switch] $TreatTimeoutActionAsSuccess
  )
{
  $timeoutTime = $(get-date).AddSeconds($TimeoutSeconds)
  $continue = $true
  $currentRetryIteration = 1
  
  while($continue)
  {
    $continue = $false

    try
    {
      # invoke the script block
      $retValue = Invoke-Command $Command -ArgumentList $ArgumentList -ErrorVariable errors

      # If an output variable was specified, set it with the output from the script block.
      if($CommandOutput)
      {
        $CommandOutput.Value = $retValue
      }
      
      return
    }
    catch
    {
      $sleepSeconds = $RetryIntervalSec * $currentRetryIteration
      $nextAttempt = $(Get-Date).AddSeconds($sleepSeconds)
      
      # script block failed. If another attempt is possible, sleep and try again. Otherwise rethrow the error.
      if($(Get-Date) -le $timeoutTime -and $nextAttempt -le $timeoutTime)
      {
        $currentRetryIteration+=1
        Invoke-Command $Logger -ArgumentList ("Warning: Command failed with: {0}" -f ($_ | Format-List -force | Out-String))
        Invoke-Command $Logger -ArgumentList "Sleeping for $sleepSeconds seconds before retrying."
        Start-Sleep $sleepSeconds
        Invoke-Command $Logger -ArgumentList "Done sleeping. Retrying..."

        # This is the only case where we'd continue.
        $continue = $true
      }
      else
      {
        Invoke-Command $Logger -ArgumentList ("Retries exhausted. Final attempt failure: {0}" -f ($_ | Format-List -force | Out-String))
        
        #If a timeout action was specified, execute it here.
        if($TimeoutAction)
        {
          Invoke-Command $Logger -ArgumentList ("Invoking timeout action...")
          $retValue = Invoke-Command $TimeoutAction -ErrorVariable timeoutErrors
          Invoke-Command $Logger -ArgumentList ("Timeout action completed.")
          
          if($CommandOutput)
          {
            $CommandOutput.Value = $retValue
          }

          if($TreatTimeoutActionAsSuccess)
          {
            Invoke-Command $Logger -ArgumentList "Timeout action treated as success."
            return
          }
        }

        # Re-throw the original command exception.
        throw $_
      }
    }
  }

  # This should never be reached but guard against unexpected failure in the catch block above.
  throw "An unexpected error occurred executing command."
}

Export-ModuleMember -Function Invoke-RetryWithBackoff
# SIG # Begin signature block
# MIIr/AYJKoZIhvcNAQcCoIIr7TCCK+kCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDmCW3lk7U8ChV+
# MS0bGiaN9CgqhH/ub+m7uiMFb2WxeKCCEW4wggh+MIIHZqADAgECAhM2AAAB33OB
# lxa+Mv0NAAIAAAHfMA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH
# QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe
# Fw0yNDAxMjAwMTMzNDRaFw0yNTAxMTkwMTMzNDRaMCQxIjAgBgNVBAMTGU1pY3Jv
# c29mdCBBenVyZSBDb2RlIFNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
# AoIBAQDVucAmkbIWpspYysyydQyyRh2L8q5igYFcy2vDk8xGvVMRBhxwbOsJIEd0
# wY8N7WU/xgkYMnSsM4vmc2B49DGdrAjSJqbsx0zf+DLFjrBITUecdRhlq0VKGX8U
# bVOkg0aIfFNLRs4DSrCZYh26zyB8qkL/jUmB7DhcBEhhgOlXRQ4LHnUv7qf+iXqD
# uwFz9tUTAh8JGsgLRBK0oSsRfUB+FJF2KyUxzmeFXJKiEynsWz4kqoM91ag1Yw0U
# 8d0e+RgAKi3Ft1cXA+3qKM6I1H11e/NdIjh7oThvrBtfEngwlwbTF3KZOHdhLBFZ
# 18U4v8VeTlb4r94346CY2+SKnQa7AgMBAAGjggWKMIIFhjApBgkrBgEEAYI3FQoE
# HDAaMAwGCisGAQQBgjdbAQEwCgYIKwYBBQUHAwMwPQYJKwYBBAGCNxUHBDAwLgYm
# KwYBBAGCNxUIhpDjDYTVtHiE8Ys+hZvdFs6dEoFgg93NZoaUjDICAWQCAQ4wggJ2
# BggrBgEFBQcBAQSCAmgwggJkMGIGCCsGAQUFBzAChlZodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpaW5mcmEvQ2VydHMvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1F
# JTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBSBggrBgEFBQcwAoZGaHR0cDovL2NybDEu
# YW1lLmdibC9haWEvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUy
# MDAxKDIpLmNydDBSBggrBgEFBQcwAoZGaHR0cDovL2NybDIuYW1lLmdibC9haWEv
# QlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBS
# BggrBgEFBQcwAoZGaHR0cDovL2NybDMuYW1lLmdibC9haWEvQlkyUEtJQ1NDQTAx
# LkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBSBggrBgEFBQcwAoZG
# aHR0cDovL2NybDQuYW1lLmdibC9haWEvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1F
# JTIwQ1MlMjBDQSUyMDAxKDIpLmNydDCBrQYIKwYBBQUHMAKGgaBsZGFwOi8vL0NO
# PUFNRSUyMENTJTIwQ0ElMjAwMSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2Vy
# dmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1BTUUsREM9R0JM
# P2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0
# aG9yaXR5MB0GA1UdDgQWBBSO7i0qme7tjtjFjyuIjlmGM6cbCTAOBgNVHQ8BAf8E
# BAMCB4AwRQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEWMBQGA1UEBRMNMjM2MTY3KzUwMTk3MDCCAeYGA1UdHwSCAd0wggHZMIIB
# 1aCCAdGgggHNhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpaW5mcmEvQ1JM
# L0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwxLmFtZS5nYmwv
# Y3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwyLmFtZS5n
# YmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwzLmFt
# ZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmw0
# LmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGgb1sZGFwOi8v
# L0NOPUFNRSUyMENTJTIwQ0ElMjAwMSgyKSxDTj1CWTJQS0lDU0NBMDEsQ049Q0RQ
# LENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZp
# Z3VyYXRpb24sREM9QU1FLERDPUdCTD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0
# P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwHwYDVR0jBBgw
# FoAUllGE4Gtve/7YBqvD8oXmKa5q+dQwHwYDVR0lBBgwFgYKKwYBBAGCN1sBAQYI
# KwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAJe/YXNSCoXitLf/X5pfJZpep3cs
# jdqmBgg+8Kr++8XMjWwdm4tiLasJMUPCgmp5NYn3wC4GefGYwfF7Xm2FMSR2i6QU
# HjigGu6BjdWQh4EwGaNqXLkXlUM7Ww2Z0KrRtpCL16DCOTNZuCFPAytSHFskPWrr
# 6q3EBuiM6P5VLgFSKiAxcunldJorbrBrvZSZib1OINzFGAQszUR0ytovW6FOp+uo
# VhiQCqnOheC1ppnZPss7vnXoogyO0xgSW40bRlltGfwnlOd3IZ/43ZOj5XeeShg5
# 2SzVEiyYrZjD17MSNzQM1JKI07+mtAC7D+eZ/+g2pM/91oHcrDq9Nq4QrS0wggjo
# MIIG0KADAgECAhMfAAAAUeqP9pxzDKg7AAAAAABRMA0GCSqGSIb3DQEBCwUAMDwx
# EzARBgoJkiaJk/IsZAEZFgNHQkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxEDAOBgNV
# BAMTB2FtZXJvb3QwHhcNMjEwNTIxMTg0NDE0WhcNMjYwNTIxMTg1NDE0WjBBMRMw
# EQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRUwEwYDVQQD
# EwxBTUUgQ1MgQ0EgMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ
# mlIJfQGejVbXKpcyFPoFSUllalrinfEV6JMc7i+bZDoL9rNHnHDGfJgeuRIYO1LY
# /1f4oMTrhXbSaYRCS5vGc8145WcTZG908bGDCWr4GFLc411WxA+Pv2rteAcz0eHM
# H36qTQ8L0o3XOb2n+x7KJFLokXV1s6pF/WlSXsUBXGaCIIWBXyEchv+sM9eKDsUO
# LdLTITHYJQNWkiryMSEbxqdQUTVZjEz6eLRLkofDAo8pXirIYOgM770CYOiZrcKH
# K7lYOVblx22pdNawY8Te6a2dfoCaWV1QUuazg5VHiC4p/6fksgEILptOKhx9c+ia
# piNhMrHsAYx9pUtppeaFAgMBAAGjggTcMIIE2DASBgkrBgEEAYI3FQEEBQIDAgAC
# MCMGCSsGAQQBgjcVAgQWBBQSaCRCIUfL1Gu+Mc8gpMALI38/RzAdBgNVHQ4EFgQU
# llGE4Gtve/7YBqvD8oXmKa5q+dQwggEEBgNVHSUEgfwwgfkGBysGAQUCAwUGCCsG
# AQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNxQCAQYJKwYBBAGCNxUGBgorBgEEAYI3
# CgMMBgkrBgEEAYI3FQYGCCsGAQUFBwMJBggrBgEFBQgCAgYKKwYBBAGCN0ABAQYL
# KwYBBAGCNwoDBAEGCisGAQQBgjcKAwQGCSsGAQQBgjcVBQYKKwYBBAGCNxQCAgYK
# KwYBBAGCNxQCAwYIKwYBBQUHAwMGCisGAQQBgjdbAQEGCisGAQQBgjdbAgEGCisG
# AQQBgjdbAwEGCisGAQQBgjdbBQEGCisGAQQBgjdbBAEGCisGAQQBgjdbBAIwGQYJ
# KwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMBIGA1UdEwEB/wQI
# MAYBAf8CAQAwHwYDVR0jBBgwFoAUKV5RXmSuNLnrrJwNp4x1AdEJCygwggFoBgNV
# HR8EggFfMIIBWzCCAVegggFToIIBT4YxaHR0cDovL2NybC5taWNyb3NvZnQuY29t
# L3BraWluZnJhL2NybC9hbWVyb290LmNybIYjaHR0cDovL2NybDIuYW1lLmdibC9j
# cmwvYW1lcm9vdC5jcmyGI2h0dHA6Ly9jcmwzLmFtZS5nYmwvY3JsL2FtZXJvb3Qu
# Y3JshiNodHRwOi8vY3JsMS5hbWUuZ2JsL2NybC9hbWVyb290LmNybIaBqmxkYXA6
# Ly8vQ049YW1lcm9vdCxDTj1BTUVSb290LENOPUNEUCxDTj1QdWJsaWMlMjBLZXkl
# MjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPUFNRSxE
# Qz1HQkw/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNz
# PWNSTERpc3RyaWJ1dGlvblBvaW50MIIBqwYIKwYBBQUHAQEEggGdMIIBmTBHBggr
# BgEFBQcwAoY7aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL2NlcnRz
# L0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUHMAKGK2h0dHA6Ly9jcmwyLmFt
# ZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUHMAKGK2h0dHA6
# Ly9jcmwzLmFtZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUH
# MAKGK2h0dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQw
# gaIGCCsGAQUFBzAChoGVbGRhcDovLy9DTj1hbWVyb290LENOPUFJQSxDTj1QdWJs
# aWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9u
# LERDPUFNRSxEQz1HQkw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNl
# cnRpZmljYXRpb25BdXRob3JpdHkwDQYJKoZIhvcNAQELBQADggIBAFAQI7dPD+jf
# XtGt3vJp2pyzA/HUu8hjKaRpM3opya5G3ocprRd7vdTHb8BDfRN+AD0YEmeDB5HK
# QoG6xHPI5TXuIi5sm/LeADbV3C2q0HQOygS/VT+m1W7a/752hMIn+L4ZuyxVeSBp
# fwf7oQ4YSZPh6+ngZvBHgfBaVz4O9/wcfw91QDZnTgK9zAh9yRKKls2bziPEnxeO
# ZMVNaxyV0v152PY2xjqIafIkUjK6vY9LtVFjJXenVUAmn3WCPWNFC1YTIIHw/mD2
# cTfPy7QA1pT+GPARAKt0bKtq9aCd/Ym0b5tPbpgCiRtzyb7fbNS1dE740re0COE6
# 7YV2wbeo2sXixzvLftH8L7s9xv9wV+G22qyKt6lmKLjFK1yMw4Ni5fMabcgmzRvS
# jAcbqgp3tk4a8emaaH0rz8MuuIP+yrxtREPXSqL/C5bzMzsikuDW9xH10graZzSm
# PjilzpRfRdu20/9UQmC7eVPZ4j1WNa1oqPHfzET3ChIzJ6Q9G3NPCB+7KwX0OQmK
# yv7IDimj8U/GlsHD1z+EF/fYMf8YXG15LamaOAohsw/ywO6SYSreVW+5Y0mzJutn
# BC9Cm9ozj1+/4kqksrlhZgR/CSxhFH3BTweH8gP2FEISRtShDZbuYymynY1un+Ry
# fiK9+iVTLdD1h/SxyxDpZMtimb4CgJQlMYIZ5DCCGeACAQEwWDBBMRMwEQYKCZIm
# iZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRUwEwYDVQQDEwxBTUUg
# Q1MgQ0EgMDECEzYAAAHfc4GXFr4y/Q0AAgAAAd8wDQYJYIZIAWUDBAIBBQCgga4w
# GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG
# AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIB3KM5LEVnjMwCHZgDN2LGdNJZxDvFki
# ir+qRQqxHJ9FMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYA
# dKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEA
# RdmW3PdaRoiNXVMAZfBY+594JupasKrHv1ohmA8xaEeLJp1hMk8gWD/Y7HOGBSyg
# iu7brzQpoDvX9D4Z/48xBqWMaIBxbECglti/bp48/VFcr0/tCI/mKXvwyxDZYrDQ
# cA+j+XFOBgQIOZGEBeriFQY+AZUCwIwVwE9qDP8XSCLnbnDdlQmu1o5qeMBrj1sy
# vZqIZJXyxP7Kbe0pEyKjGorzNe8TaSnNI5Oaft8TslwJQSM/sOFpuQx+8relmvwT
# JUr3oqrX3yCoL9hMryqR6jTo7CwmP/V98SroyKjFWLw0eXPBlAO7nYr/mja6uY9/
# HHh4tpR2SqvFnVxH8pyFwKGCF6wwgheoBgorBgEEAYI3AwMBMYIXmDCCF5QGCSqG
# SIb3DQEHAqCCF4UwgheBAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsqhkiG9w0B
# CRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUA
# BCAb/LHamXEh3k+ztQ3wAcjWCUJ1FfyyvwWpkyXw8snXGgIGZusgRj0uGBIyMDI0
# MTAwNDE0NTk0Mi44MVowBIACAfSggdmkgdYwgdMxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM2MDUt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# oIIR+zCCBygwggUQoAMCAQICEzMAAAH3WCB1BMr7wvQAAQAAAfcwDQYJKoZIhvcN
# AQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjQwNzI1MTgz
# MTA2WhcNMjUxMDIyMTgzMTA2WjCB0zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9u
# cyBMaW1pdGVkMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzYwNS0wNUUwLUQ5
# NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0G
# CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQ50dME2ibr+5cpoQo/2s8hORPpDEX
# XW2PMHQ2TVvIOk+sVMeFreHHBJ1NyvxjRreToRCXCrLpE7PjZ7RHl4Nb50KhBqmK
# kMgVQ5ineg26rBf/F6kBMSRjXszJcXHqtBbY1xZQlbdCjYC4nQc61uVKki1Bk8aY
# ecaqS38MHjkXDGTpWhK/E1xAqEoROS7Ou3xToNFxxCbUV2GY8qAPOBx8M8zmj4af
# NuIy7rLTr0DgQeYsyaR5xKRW8GZxnxWfMUdMOQYt2mcNXkVeNU5sCBtIzRyephIZ
# 9GntUYcFGrKixy9HhtxD4JX2kONsnpLmtmfW4DyFGGPT0ezfcdF6+3ihYBVgYi2A
# Swb4GsJhumBYwMQhWcCA9kSI8BojzAEZ6YTh94SS7PtMDCCREFxTMuBDi68+pEPU
# D4mS3br6kOpZhKfQwDyPTNpxCT2r8C9yI9cP0i3Z7P6aoTOAVFGwkYu1x/0eSy8r
# wmx3ojnMVKGWqLlunN/Vjg06I06HlDBbWki8DmKuVqXuoWGQB555mqainz643Flf
# EUJAbdHezmldbz0WIKH2uZetWo4LCBxcUglABCSWUqwj5Qmoar2uZEAEnPmUcpMV
# iYXBwznYpZaM3HfPqh3DPaH6zFrF7BOh70aq0PHf9pT7Ko1FwHzDS1JdR/7KU3i6
# TnEcSkunH5k02wIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFN9GpDM/eb09la4t/Wnz
# +Z4V+SaYMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRY
# MFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p
# Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEF
# BQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAo
# MSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYD
# VR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQA3RqNp8gt4vpJAgwgwBczV
# B3rFqhyLaY6ulHy8pbLJOwvdvzcDtcYuIBtDFOuqde9VZZ42y3lhAPyxo75ROA4s
# l1N19QAOEtegr5GXCN+d2KYglP0wf21RhcvMlcqFkzT2i4/A2yufxg4sil0CLlM/
# I3wKXXU4ZlKU/2vwme+iZbTQCgng+X2uWDQbmVxCScBeodr2dB1anVnFeo137Qmw
# qaVHy1wA1ffcKUz02doKUkTEtAeIp4dRRa2rIsyXrlNbrBEzteUXtj49OcLx241a
# fi4ueD4439nf0Y7qoGPsgRnGirijdq8SH1trjdRTpODNVloGbxVoDTBLBR7+mqlM
# 5gVY3rZcveCX8kLanN8g/E/rpd9EsjFp+MFVebwpUOfZwwv0i9ErTaz3jVjn5FHi
# BIA6EuJBDoDTdU1G6n6ykxrST5dM8CL7ZowfnFrVmNv8ry71/0zTlTT9tQwlckM/
# 77KxakltVEOIcbuzNpxr6vceJQ+NAnJCXY2I5xhMZX8NwussIErbMbnTcUZvTg3k
# p/XReADAVpeWh3kH14qH3k+dcrHYs0GAvAbzlqeWGEbHEFDmYWwkaQGfQ9k+0DNn
# J+v3qrHOmnakf0MklyMoIOsyZnOJdrOlrlVU3foI7WQNTgAGRJhNc4zxGYle5Cbu
# ZQXdtaaP6GMAlvinPqFPlTCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAA
# ABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1
# dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWlj
# cm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4IC
# DwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/
# bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNE
# t6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2
# Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOOR
# j7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnop
# N6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0g
# z3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/
# BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8Qmgu
# EOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFd
# XzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y
# 7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQAB
# o4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS
# /mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1Gely
# MFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAT
# BgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+ii
# XGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0y
# My5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNy
# dDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5O
# R2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6
# th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhT
# dSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnD
# vBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvf
# SaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+
# CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5a
# GZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+
# fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmN
# cP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGe
# Pu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNY
# s6FwZvKhggNWMIICPgIBATCCAQGhgdmkgdYwgdMxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM2MDUt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# oiMKAQEwBwYFKw4DAhoDFQBvbwoMb/Fds0GOYzv+erDduCsQ5qCBgzCBgKR+MHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6qoN
# JjAiGA8yMDI0MTAwNDA2NDM1MFoYDzIwMjQxMDA1MDY0MzUwWjB0MDoGCisGAQQB
# hFkKBAExLDAqMAoCBQDqqg0mAgEAMAcCAQACAiKGMAcCAQACAhPoMAoCBQDqq16m
# AgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSCh
# CjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAGLf1oqWg8BfhSxbSTqKxu4o
# Y3VMMCX4xbsOkTacLX1DGTM1vY13n9jxGuqCcnlxSr6XnTEs9vCNpuqFaHOt4JO6
# aV/Beegb4JajYfNTwHCMPV1IUxiQiiawn3pFoTcy2fjE3e3t7ZtDcB0SL0jUQQF9
# mauXuiPrIB0teztnRsfhKKCj5+GkGWnjD75QgTZ/Bql3Lk3AcMfxXyn8wif9vb4H
# VIocOts3fMffEDMoCWzEtz+m67oKrGtNKHYQISVMIjCJXJCYEUyYz79xRGGmaDIg
# g4v/z7TfkcMNuT0Qub4W8y9Vst6HXh3k6oHd5BKlyGVz7QcI07s5pQVQR3eXQKkx
# ggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA
# AfdYIHUEyvvC9AABAAAB9zANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkD
# MQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCAKxKvPd2+zLAuivkQbPTqm
# WE8KMd7YUDvHfGUZN+VaXzCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EICHa
# mNprdxrR5xi6G7rS5gc/8gqc9t51tVAnlKggflniMIGYMIGApH4wfDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
# IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAH3WCB1BMr7wvQAAQAAAfcwIgQg1tJs
# ikk1dXbg+aD+xc6oIIeecfdVEJEXqkAQ9QPwBPcwDQYJKoZIhvcNAQELBQAEggIA
# ifiMORem7ZfiCRbtV/1UKFudFx4CAhmMoA8SNiXq2uYbWuvgpaBGm4for58FsnQ+
# /MsFjpdLI09ed5/i6/UPLtR4Dbwjo/yNUz9AWQzktoLVO74XTv/Tq0qEBgfCqJju
# KOgFFVqhHs1U+IKPBXu6EKBcOsT9itIZ9RIZq6RB9PXCjkW9lZNetmcyC0rBDXRp
# CrscHAvEtm492izSwztE5ze3w77Kg5HNt+jJhICY1j5UGPXeRX26fMESbk66pey/
# EXmrAg+xvrtqiYZUnht0OU6rwo+ryUUpepk4T61FYFFvm8CC3H9XPFCWPg4NyR2/
# CcJT61IQ5b06hHVjJvYr4JHZI8ujhNmD9BDt3g/BAhvmgmXk28geE4Jfzr6G151P
# gZaZdyBOKOL9tphxB4o494FMZMo01jyqSgBJo9cwqBY3eHhBscI2IvjV2GR1BJqh
# YGnfd6Q4sX7z4BMBs92dnBdPceCWNE5F+cSQJ/8JqK2sEISbkOxhe1Itu1dYk8Cw
# wpMq9yki3EF4sQbA20djwSKCovsK1m8eqwY12s6Ed0cmS/8tnZov3EE92eiBwKPy
# AdI96dK2Opkl5rPVQwcidy6X9lGmGtKBewm1ww5xeYL1roq7frY19Eu/6BF59Tko
# 0T+gsbqBBv1g1/GpceLMrvoudnSo2DqRlAAB5LLQspU=
# SIG # End signature block
