Examples/Get-EuroExchange.ps1

# TODO $My = [HashTable]::Synchronized(@{})

<#
.SYNOPSIS
EZB-Währungsrechner
 
.DESCRIPTION
Rechnet Euros in Nicht-Euro-Währungen gem. den Vorgaben der EZB.
 
.INPUTS
System.String mit Währungssymbolen
PSCustomObject mit folgenden Properties Currency <string> und Euros <decimal>
 
.OUTPUTS
PSCustomObject
 
.PARAMETER Currency
Währungssymbol der EZB.
 
.PARAMETER Euros
Euro-Betrag der umgerechnet werden soll.
 
.PARAMETER ListCurrency
Eine Übersicht aller möglichen Währungssymbole.
 
.EXAMPLE
Get-EuroExchange -Currency USD
Ermittelt den Wechselkurs für US-Dollar
 
.EXAMPLE
Get-EuroExchange -Currency USD -Euros 100
 
.EXAMPLE
Get-EuroExchange -ListCurrency
 
.EXAMPLE
"USD", "RUB", "AUD" | Get-EuroExchange
 
.EXAMPLE
"USD", "RUB", "AUD" | Get-EuroExchange -Euros 100
 
.EXAMPLE
"USD,10", "RUB,100", "AUD,1000" | ConvertFrom-Csv -Header Currency, Euros | Get-EuroExchange
#>

function Get-EuroExchange {

    [CmdletBinding(DefaultParameterSetName = 'Calculate')]
    param (
        [Parameter(ParameterSetName = "Calculate", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateSet('AUD', 'BGN', 'BRL', 'CAD', 'CHF', 'CNY', 'CZK', 'DKK', 'GBP', 'HKD', 'HRK', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'JPY', 'KRW', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'SEK', 'SGD', 'THB', 'TRY', 'USD', 'ZAR')]
        [Alias("Währung")]
        [string]$Currency,

        [Parameter(ParameterSetName = "Calculate", ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(0.0001, 1000000)]
        [Alias("Euronen")]
        [decimal]$Euros = 1,

        [Parameter(ParameterSetName = "Overview", Mandatory = $true)]
        [switch]$ListCurrency
    )
    begin {
        [datetime]$StartTime = Get-Date

        #region Update local cache and read it

        # ! Build Cache-File:
        [string]$EuroExchangeCacheFile = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'EcbEuroExchangeCache.xml'

        # ! Exist Cache-File read timestamp:
        [TimeSpan]$ECBCacheDifferenceSpan = New-TimeSpan -Hours 999
        if ((Test-Path -Path $EuroExchangeCacheFile)) {
            'ECB-EuroExchange-Cache-File found!' | Write-Verbose
            [xml]$EuroExchangeContent = Get-Content -Path $EuroExchangeCacheFile
            [datetime]$EuroExchangeTime = $EuroExchangeContent.Envelope.Cube.Cube | Select-Object -ExpandProperty 'time'
            [TimeSpan]$ECBCacheDifferenceSpan = (Get-Date) - $EuroExchangeTime
        }

        # ! Is Cache-Difference-TimeSpan greater 39h then update from ECB:
        if($ECBCacheDifferenceSpan.TotalHours -ge 39) {
            'The ECB-EuroExchange-Cache-File is updated because the file was not found or is older then 39 hours.' | Write-Verbose
            Invoke-WebRequest -Uri "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" | Select-Object -ExpandProperty 'Content' | Set-Content -Path $EuroExchangeCacheFile -Force
        }

        # ! Read Cache-File for the next steps:
        [xml]$EuroExchangeContent = Get-Content -Path $EuroExchangeCacheFile
        $EuroExchangeCubes = $EuroExchangeContent.Envelope.Cube.Cube.Cube
        "ECB-EuroExchange-Cache-File from $($EuroExchangeContent.Envelope.Cube.Cube | Select-Object -ExpandProperty 'time') read it." | Write-Verbose

        #endregion

        switch ($PSCmdlet.ParameterSetName) {
            'Overview' {
                "Get-EuroExchange works in Overview-Mode (-ListCurrency = $ListCurrency)." | Write-Verbose
                $EuroExchangeCubes | ForEach-Object -Process { [PSCustomObject]@{ Currency = $_.currency } } | Sort-Object -Property 'Currency'
            }
            'Calculate' {
                'Get-EuroExchange works in Calculate-Mode.' | Write-Verbose
            }
        }
    }
    process {
        if($PSCmdlet.ParameterSetName -eq 'Calculate') {
            [decimal]$CurrencyRate = $EuroExchangeCubes | Where-Object -Property 'currency' -EQ -Value $Currency | Select-Object -ExpandProperty 'rate'
            [PSCustomObject]@{
                Currency    = $Currency.ToUpper()
                Rate        = $CurrencyRate
                Euros       = $Euros
                SumCurrency = $CurrencyRate * $Euros
            }
        }
    }
    end {
        [TimeSpan]$Duration = (Get-Date) - $StartTime
        "Done in $($Duration.TotalMilliseconds) ms!" | Write-Verbose
    }
}

<# ! Manueller UTest bzgl. Feature-Umfang
? Aktueller Wechsel Kurs für USD
Get-EuroExchange -Currency usd
 
? Aktueller Wechsel Kurs für USD über einen ALias-Parameter
Get-EuroExchange -Währung USD
 
? Kurs-Produkt für USD und €100
Get-EuroExchange -Currency USD -Euros 100
 
? Eine Übersicht möglicher Wechselkurs-Symbole mit zusätzlichen Informationen
Get-EuroExchange -ListCurrency -Verbose
 
? Wird das Default-Set angesprungen
Get-EuroExchange
 
"USD", "RUB", "AUD" | Get-EuroExchange
"USD", "RUB", "AUD" | Get-EuroExchange -Euros 100
"USD,10", "RUB,100", "AUD,1000" | ConvertFrom-Csv -Header Currency, Euros | Get-EuroExchange
"USD,10", "RUB,100", "AUD,1000" | ConvertFrom-Csv -Header Currency, Euros | Get-EuroExchange | Where-Object SumCurrency -GE 1000
"USD,10", "RUB,100", "AUD,1000" | ConvertFrom-Csv -Header Currency, Euros | Get-EuroExchange | Out-GridView
"USD,10", "RUB,100", "AUD,1000" | ConvertFrom-Csv -Header Währung, Euronen | Get-EuroExchange
Get-EuroExchange -ListCurrency | Get-EuroExchange -Euros 1000
Get-Command -Name Get-EuroExchange -Syntax
Get-ParameterInfo -CmdletName Get-EuroExchange
Get-Help -Name Get-EuroExchange -ShowWindow
Show-Command -Name Get-EuroExchange -NoCommonParameter -ErrorPopup | Out-GridView
#>


<# ! Manueller UTest bzgl. Validierung
Get-EuroExchange # Currency mus abgefragt werden
Get-EuroExchange -Currency USD -ListCurrency # Diese Parameter-Kombination ist nicht erlaubt
Get-EuroExchange -Euros 100 -ListCurrency # Diese Parameter-Kombination ist nicht erlaubt
Get-EuroExchange -Currency XXX # Gibt es nicht
Get-EuroExchange -Currency USD -Euros -100 # Negative Euros sind nicht erlaubt
Get-EuroExchange -Currency USD -Euros 1000001 # Größer als der max. Bereich.
Get-EuroExchange -Currency USD -Euros 0 # 0 Euros sind nicht erlaubt
Get-EuroExchange -Currency USD -Euros hundert # Nur Zahlen sind erlaubt
Get-EuroExchange -Euros 100 # Ohne Währungssymbol nicht erlaubt
Get-EuroExchange -Currency USD, RUB # Zuviel Währungen
Get-EuroExchange -Currency USD -Euros 50, 100 # Zuviel Euros
#>


# SIG # Begin signature block
# MIIcZAYJKoZIhvcNAQcCoIIcVTCCHFECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBU3weSz5M/uqWO
# KcsW3GjKxfBedqqHUFSh3jXKrIgBGqCCFn8wggNyMIICWqADAgECAhA8emkJ82H0
# pEx+itPRny0WMA0GCSqGSIb3DQEBDQUAMFExIzAhBgkqhkiG9w0BCQEWFGluZm9A
# YXR0aWxha3JpY2suY29tMSowKAYDVQQDDCFBdHRpbGEgS3JpY2sgKFNvZnR3YXJl
# IERldmVsb3BlcikwHhcNMjIxMDE2MTg1MTA3WhcNMzIxMDE2MTkwMTA3WjBRMSMw
# IQYJKoZIhvcNAQkBFhRpbmZvQGF0dGlsYWtyaWNrLmNvbTEqMCgGA1UEAwwhQXR0
# aWxhIEtyaWNrIChTb2Z0d2FyZSBEZXZlbG9wZXIpMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEAvbn3JNw62vDI7mnX6gD+V/MyDkvFSzclaqC3Kfn+wDxj
# xkmgwho343N/JCxAUjHoBjNDpx4W3KTVv3X7PYrPHxoz/134JTIBdV+yIyL/VkCS
# Mnp9exMhMPxa1RvX3p/zphPMosv7xGgRPF3QVKxoBBUtifql80/pDHvOCPtROZ+9
# xSfXJ6P9jXGH4YSlNJxAKv53AXV0avihpa1BWL6ohyS1Bnjdbcw/hq0TIf4as1Dy
# 7IbrU6Fneaqm/XIEEs11I0BrDNwgXnmB8PSojsm/DOtQY5Ps8eGJzwiXP2Vdvk0j
# OsqDaJe3cxiOCXk6dz2zylB6rfP+Kph97bjaQoNI2QIDAQABo0YwRDAOBgNVHQ8B
# Af8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFKrSiXRUaupI
# 5orXIniIR5sTcWwIMA0GCSqGSIb3DQEBDQUAA4IBAQAQ+6LPLF6Ua7JCC9LuwOCG
# UlWwawgV/D5wK+FU8PQ+/onwBx9ZBqXnZw4f7NQtqaiR1bwm7sRTZeaIcif57zHM
# /WBicYjB9dwZoGylfeCW6LRNQaoBvjuavOTsQw3lYF//ylJV8QyUKloJd9W6CVtm
# tBSJEYopjygAm/9E9CxRFPSXxX/G+Af0+G+VeeBjSpaYKO688dVXa7pqMOm6hq9P
# Ww6jgiCL3aRk0qbWwl2mt1POcfdRk/rdvt66BcO91cLDKhSCOIp7coJZ8Cf2xHDP
# 99NcZ8ct02Cco6qjtlUkrCBRYNsuUAcToTvqQLiSSkywj+jTI4gm0vcjSiVXwnyy
# 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/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGrjCCBJagAwIBAgIQ
# BzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEV
# MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
# MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAw
# MDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln
# aUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5
# NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYR
# oUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CE
# iiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCH
# RgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5K
# fc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDni
# pUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2
# nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp
# 88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1C
# vwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+
# 0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl2
# 7KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOC
# AV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaa
# L3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud
# DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw
# AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwB
# BAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+
# ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvX
# bYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tP
# iix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCy
# Xen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpF
# yd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3
# fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t
# 5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejx
# mF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxah
# ZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAA
# zV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vup
# L0QVSucTDh3bNzgaoSv27dZ8/DCCBsIwggSqoAMCAQICEAVEr/OUnQg5pr/bP1/l
# YRYwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYg
# U0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yMzA3MTQwMDAwMDBaFw0zNDEwMTMy
# MzU5NTlaMEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEg
# MB4GA1UEAxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjMwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCjU0WHHYOOW6w+VLMj4M+f1+XS512hDgncL0ijl3o7
# Kpxn3GIVWMGpkxGnzaqyat0QKYoeYmNp01icNXG/OpfrlFCPHCDqx5o7L5Zm42nn
# af5bw9YrIBzBl5S0pVCB8s/LB6YwaMqDQtr8fwkklKSCGtpqutg7yl3eGRiF+0Xq
# DWFsnf5xXsQGmjzwxS55DxtmUuPI1j5f2kPThPXQx/ZILV5FdZZ1/t0QoRuDwbjm
# UpW1R9d4KTlr4HhZl+NEK0rVlc7vCBfqgmRN/yPjyobutKQhZHDr1eWg2mOzLukF
# 7qr2JPUdvJscsrdf3/Dudn0xmWVHVZ1KJC+sK5e+n+T9e3M+Mu5SNPvUu+vUoCw0
# m+PebmQZBzcBkQ8ctVHNqkxmg4hoYru8QRt4GW3k2Q/gWEH72LEs4VGvtK0VBhTq
# YggT02kefGRNnQ/fztFejKqrUBXJs8q818Q7aESjpTtC/XN97t0K/3k0EH6mXApY
# TAA+hWl1x4Nk1nXNjxJ2VqUk+tfEayG66B80mC866msBsPf7Kobse1I4qZgJoXGy
# bHGvPrhvltXhEBP+YUcKjP7wtsfVx95sJPC/QoLKoHE9nJKTBLRpcCcNT7e1NtHJ
# XwikcKPsCvERLmTgyyIryvEoEyFJUX4GZtM7vvrrkTjYUQfKlLfiUKHzOtOKg8tA
# ewIDAQABo4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZI
# AYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQW
# BBSltu8T5+/N0GSh1VapZTGj3tXjSTBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8v
# Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2
# VGltZVN0YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcw
# AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8v
# Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hB
# MjU2VGltZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCBGtbeoKm1
# mBe8cI1PijxonNgl/8ss5M3qXSKS7IwiAqm4z4Co2efjxe0mgopxLxjdTrbebNfh
# YJwr7e09SI64a7p8Xb3CYTdoSXej65CqEtcnhfOOHpLawkA4n13IoC4leCWdKgV6
# hCmYtld5j9smViuw86e9NwzYmHZPVrlSwradOKmB521BXIxp0bkrxMZ7z5z6eOKT
# GnaiaXXTUOREEr4gDZ6pRND45Ul3CFohxbTPmJUaVLq5vMFpGbrPFvKDNzRusEEm
# 3d5al08zjdSNd311RaGlWCZqA0Xe2VC1UIyvVr1MxeFGxSjTredDAHDezJieGYkD
# 6tSRN+9NUvPJYCHEVkft2hFLjDLDiOZY4rbbPvlfsELWj+MXkdGqwFXjhr+sJyxB
# 0JozSqg21Llyln6XeThIX8rC3D0y33XWNmdaifj2p8flTzU8AL2+nCpseQHc2kTm
# Ot44OwdeOVj0fHMxVaCAEcsUDH6uvP6k63llqmjWIso765qCNVcoFstp8jKastLY
# OrixRoZruhf9xHdsFWyuq69zOuhJRrfVf8y2OMDY7Bz1tqG4QyzfTkx9HmhwwHcK
# 1ALgXGC7KP845VJa1qwXIiNO9OzTF/tQa/8Hdx9xl0RBybhG02wyfFgvZ0dl5Rtz
# tpn5aywGRu9BHvDwX+Db2a2QgESvgBBBijGCBTswggU3AgEBMGUwUTEjMCEGCSqG
# SIb3DQEJARYUaW5mb0BhdHRpbGFrcmljay5jb20xKjAoBgNVBAMMIUF0dGlsYSBL
# cmljayAoU29mdHdhcmUgRGV2ZWxvcGVyKQIQPHppCfNh9KRMforT0Z8tFjANBglg
# hkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3
# DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV
# MC8GCSqGSIb3DQEJBDEiBCCn4VMp4TX+52vnM9vxd/jl5L6wQdPOU6pWm8dZMt5D
# MDANBgkqhkiG9w0BAQEFAASCAQAOB7PnRSbA0Vbii4Wasp3dun2e6AUP1klSIvya
# pSeIdcOQRLSi5gyvYnmLhAwYoU+xZ3vgBKT+Ybau4ghD4APSm/2q2cISaGt9D0KJ
# Q3RuQkdPcbJjTHKVWBJGKidxibDo6OFLfUDebulFVfEKWZ79h6MttaX8b/ThXJKu
# U+3XzNltaYw9QByjTiRHOXjuxIRSbvDdc7jBovN4MZheMHotRn9kiUJ086PMNgFq
# H/O/o1PQ91uot2UHc2c8iSiwkoqQKOXBiY88gFLKOt0i27pL1afxhTx6r1rMWz24
# UQaIIh2V2FexEBEJ9Ku7VukGRhIQc2znw6Z/Unz4ue1It4EAoYIDIDCCAxwGCSqG
# SIb3DQEJBjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRp
# Z2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQw
# OTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglg
# hkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcN
# AQkFMQ8XDTI0MDMwNTIwMDM0NlowLwYJKoZIhvcNAQkEMSIEIMra6cCmx6r6oBcv
# ia7JXyORcEQaHvcNd5fsLIC+aRvJMA0GCSqGSIb3DQEBAQUABIICAEdkFJGwLWtl
# IXR/IrbQv7aw4UJ/msY0n1A2FmcvUDMUAlm0wl5JhLdaZB+HdHLJgu9zftc0chEu
# oPEhtoIjMgb+PxUMPjEOJI7NiiagmslLMt8lW4EgisixU7S4/P/mJVacqNIquVX0
# tPjIei/HmvXNgbdm5wxYjDQyIroim89A9ovPu0UwaB4lb9W3luTPphNDwGZaW/Hw
# 1ugZt8ICAlqZ2dzEd+UKqteeQDKCDraUtI0+RZhr7TcDujbdS/3zLmzYRcPhrKXs
# of27oYdbJtOVa/cJfUQ0AA4cq8MbGPUXyrTpXvruAsfdYWQlgOeh++oBzpHxwPtV
# VRd8b/SwrOsyqlBCUELWu5dKTWXwNEgGSyGetHnRQvQOn3WZmEOseY7hdy91i0KT
# PG/tZJYmVN/9KFcemYcR4eE6NqBf8dcQsedeYU5RT/G6rjMs8k+G2denSdyEw1Oe
# xdKHf9xOozAR1ucRjbSUo5Zg2Jt+O7DliBEbdxWdbIPz41Um5IJ4Sa9NoxvVm9H5
# 5VptXcZzEriQRGUtwKyqpIj8eCObIP5Arn/MfImwswcluqvUwCdAkjZumBgc6a9F
# 40MbnGzhsAeqiYOTmMgl+SzwUn2pRQe5vFpcR0Wq+KbzgOi1hgT6ppxs/6I3HQnN
# 0eRK2WhGmu3El1AefjikrjPxYsfVfTeL
# SIG # End signature block