UpBank.psm1

$CommandsToExport = @()
$Global:token = $null 
$Global:profileName = $null
$Global:APIVersion = $null 

$UpBankConfigurationFile = Join-Path $env:LOCALAPPDATA UpBankConfiguration.clixml
if (Test-Path $UpBankConfigurationFile) {
    $UpBankConfiguration = Import-Clixml $UpBankConfigurationFile

    if ($UpBankConfiguration.APIVersion) {
        $Global:APIVersion = $UpBankConfiguration.APIVersion
    }

    if ($UpBankConfiguration.defaultProfile) {
        $profile = $UpBankConfiguration.defaultProfile
        $Global:token = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($UpBankConfiguration.$profile.PersonalAccessToken))
    }
}
else {
    $UpBankConfiguration = @{
        APIVersion = "v1"
    }
    $Global:APIVersion = "v1"
}

function Set-UpBankCredential {
    <#
.SYNOPSIS
Sets the default Up Bank API credentials.
 
.DESCRIPTION
Sets the default Up Bank API credentials. Configuration values can
be securely saved to a user's profile using Save-UpBankConfiguration.
 
.PARAMETER Credential
A standard Powershell Credential object.
 
.EXAMPLE
$cred = Get-Credential -Message 'Custom message...' -UserName 'Custom Username'
Set-UpBankCredential -Credential $cred
 
.LINK
http://darrenjrobinson.com/
 
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [PSCredential]$Credential
    )

    $newProfile = @{$Credential.UserName = @{PersonalAccessToken = $Credential.Password } }
    $UpBankConfiguration += $newProfile 
    $Global:token = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($Credential.Password))
    $Global:profileName = $Credential.UserName
}
$CommandsToExport += 'Set-UpBankCredential'


function Switch-UpBankProfile {
    <#
.SYNOPSIS
Changes the Up Bank Account Credentials used to a different Up Bank Profile.
 
.DESCRIPTION
Changes the Up Bank Account Credentials used to a different Up Bank Profile.
Optionally sets the default Up Bank API credentials to a different profile.
Configuration values can be securely saved to a user's profile using Save-UpBankConfiguration.
 
.PARAMETER profile
Profile Name to switch too.
 
.PARAMETER default
(Optional) Set the profile being switched to as the new Default Profile that will be loaded on Module Load.
 
.EXAMPLE
Switch-UpBankProfile -profile Darren
 
.EXAMPLE
Switch-UpBankProfile -profile Darren -default
 
.LINK
http://darrenjrobinson.com/
 
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$profile,
        [Parameter(Mandatory = $false, Position = 0)]
        [switch]$default
    )

    if ($UpBankConfiguration.$profile) {
        $Global:token = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($UpBankConfiguration.$profile.PersonalAccessToken))

        if ($default) {
            $UpBankConfiguration.defaultProfile = $profile
            Export-Clixml -Path $UpBankConfigurationFile -InputObject $UpBankConfiguration
        }
    }
    else {
        Write-Error "No Profile with name $($profile) was found in the Up Bank Configuration file."
        break
    }
}
$CommandsToExport += 'Switch-UpBankProfile'


function Save-UpBankConfiguration {
    <#
.SYNOPSIS
    Saves default Up Bank configuration to a file in the current users Profile.
 
.DESCRIPTION
    Saves default Up Bank configuration to a file within the current
    users Profile. If it exists, this file is then read, each time the
    Up Bank Module is imported. Allowing settings to persist between
    sessions.
 
.EXAMPLE
    Save-UpBankConfiguration
 
.LINK
    http://darrenjrobinson.com/
#>


    [CmdletBinding()]
    param ([switch]$default)
    if ($default) { $UpBankConfiguration.defaultProfile = $Global:profileName }

    Export-Clixml -Path $UpBankConfigurationFile -InputObject $UpBankConfiguration

}
$CommandsToExport += 'Save-UpBankConfiguration'

function Test-UpBankAPI {
    <#
.SYNOPSIS
Ping UpBank
 
.DESCRIPTION
Ping UpBank
 
.PARAMETER URI
(Optional) Path of UpBank Ping URI
Defaults to https://api.up.com.au/api/v1/util/ping
 
.PARAMETER token
Personal Access Token
 
.EXAMPLE
Test-UpBankAPI -token up:yeah:Y3Rh981Ez.....py
 
.LINK
http://darrenjrobinson.com/
 
#>


    param()

    if (!$token) {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
    
    try {

        $response = Invoke-RestMethod -Method Get `
            -Uri "https://api.up.com.au/api/$($APIVersion)/util/ping" `
            -Headers @{Authorization = "Bearer $($token)" }
        return $response.meta  
    }
    catch {    
        Write-Error $_
        break 
    }
}
$CommandsToExport += 'Test-UpBankAPI'

function Get-UpBankAccounts {
    <#
.SYNOPSIS
List UpBank Accounts
 
.DESCRIPTION
List UpBank Accounts
 
.PARAMETER pageSize
The number of records to return in each page. Defaults to 100
 
.EXAMPLE
Get-UpBankAccounts
 
.LINK
http://darrenjrobinson.com/
 
#>


    param(
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $pageSize = "100"
    )

    if ($token) {
        try {
            if (!$pageSize -lt "100") {
                $recordsToReturn = $pageSize
            }
            else {
                $recordsToReturn = $pageSize
                $pageSize = "100"
            }

            $response = Invoke-RestMethod -Method Get `
                -Uri "https://api.up.com.au/api/$($APIVersion)/accounts?page[size]=$($pageSize)" `
                -Headers @{Authorization = "Bearer $($token)" }
            
            if ($response.links.next) {
                $fullResponse = $null 
                $fullResponse += $response.data
                while ($response.links.next) {
                    $results = $null 
                    $results = Invoke-RestMethod -Method Get `
                        -Uri $response.links.next `
                        -Headers @{Authorization = "Bearer $($token)" }
                    if ($results) {
                        $fullResponse += $results.data
                        $response = $results
                    }
                    if ($fullResponse.count -gt $recordsToReturn) {
                        return $fullResponse | Select-Object -First $recordsToReturn
                        break  
                    }
                }
                return $fullResponse.data
            }
            else {
                return $response.data  
            }

        }
        catch {    
            Write-Error $_
            break 
        }
    }
    else {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
}
$CommandsToExport += 'Get-UpBankAccounts'

function Get-UpBankAccount {
    <#
.SYNOPSIS
Get an UpBank Account
 
.DESCRIPTION
Get an UpBank Account
 
.PARAMETER id
(Required) The id of account to return
 
.EXAMPLE
Get-UpBankAccount -id af78838b-95a9-47f6-aa38-70d827af9539
 
.LINK
http://darrenjrobinson.com/
 
#>


    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [String] $id
    )

    if ($token) {
        try {
            $response = Invoke-RestMethod -Method Get `
                -Uri "https://api.up.com.au/api/$($APIVersion)/accounts/$($id)" `
                -Headers @{Authorization = "Bearer $($token)" }
            return $response.data  
        }
        catch {    
            Write-Error $_
            break 
        }
    }
    else {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
}
$CommandsToExport += 'Get-UpBankAccount'

function Get-UpBankTransactions {
    <#
.SYNOPSIS
Retrieve a list of all transactions across all accounts for the currently authenticated user.
 
.DESCRIPTION
Retrieve a list of all transactions across all accounts for the currently authenticated user.
 
.PARAMETER pageSize
The number of records to return in each page. Defaults to 100
 
.PARAMETER since
(Optional) The start date-time from which to return records, formatted according to rfc-3339.
 
.PARAMETER until
(Optional) The end date-time up to which to return records, formatted according to rfc-3339.
 
.EXAMPLE
Get-UpBankTransactions -pageSize 30
 
.EXAMPLE
Get-UpBankTransactions -pageSize 30 -since 2020-02-01T01:02:03+10:00
 
.EXAMPLE
Get-UpBankTransactions -pageSize 30 -until 2020-02-01T01:02:03+10:00
 
 
.LINK
http://darrenjrobinson.com/
 
#>


    param(
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $pageSize = "100",
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $since,
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $until
    )

    if ($token) {
        Add-Type -AssemblyName System.Web
        try {
            [boolean]$blnPage, $blnSince, $blnUntil = $false 
            $baseURI = "https://api.up.com.au/api/$($APIVersion)/transactions"
            $query = $null 

            if (!$pageSize -lt "100") {
                $recordsToReturn = $pageSize
                $query = "?page[size]=100"
            }
            else {
                $recordsToReturn = $pageSize
                $query = "?page[size]=$($pageSize)"
            }

            if ($since) {
                [boolean]$blnSince = $true 
                if ($blnPage) {
                    $query += "&filter[since]=$($since)"
                }
                else {
                    $query = "?filter[since]=$($since)"
                }
            }
            if ($until) {
                [boolean]$blnUntil = $true 

                if ($blnPage -or $blnSince) {
                    $query += "&filter[until]=$($until)"
                }
                else {
                    $query = "?filter[until]=$($until)"
                }
            }

            $queryEncoded = [System.Web.HttpUtility]::UrlEncode($query)
            $queryEncoded = (Get-Culture).TextInfo.ToUpper($queryEncoded)
            $queryEncoded = $queryEncoded.Replace("%3F", "?")
            $queryEncoded = $queryEncoded.Replace("%3D", "=")
            $queryEncoded = $queryEncoded.Replace("%26", "&")
            $queryEncoded = $queryEncoded.Replace("SINCE", "since")
            $queryEncoded = $queryEncoded.Replace("FILTER", "filter")
            $queryEncoded = $queryEncoded.Replace("UNTIL", "until")
            $queryEncoded = $queryEncoded.Replace("PAGE", "page")
            $queryEncoded = $queryEncoded.Replace("SIZE", "size")

            $response = Invoke-RestMethod -Method Get `
                -Uri "$($baseURI)$($queryEncoded)" `
                -Headers @{Authorization = "Bearer $($token)" }
                
            if ($response.links.next) {
                $fullResponse = $null 
                $fullResponse += $response.data
                while ($response.links.next) {
                    $results = $null 
                    $results = Invoke-RestMethod -Method Get `
                        -Uri $response.links.next `
                        -Headers @{Authorization = "Bearer $($token)" }
                    if ($results) {
                        $fullResponse += $results.data
                        $response = $results
                    }
                    if ($fullResponse.count -gt $recordsToReturn) {
                        return $fullResponse | Select-Object -First $recordsToReturn
                        break  
                    }
                }
                return $fullResponse.data
            }
            else {
                return $response.data  
            }            
        }
        catch {    
            Write-Error $_
            break 
        }
    }
    else {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
}
$CommandsToExport += 'Get-UpBankTransactions'

function Get-UpBankTransaction {
    <#
.SYNOPSIS
Retrieve a specific Up Bank Transaction.
 
.DESCRIPTION
Retrieve a specific Up Bank Transaction.
 
.PARAMETER id
(Required) ID of the transaction to return.
 
.EXAMPLE
Get-UpBankTransaction -id 167ae4de-084f-4ed0-85f7-152525f790fb
 
.LINK
http://darrenjrobinson.com/
 
#>


    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [String] $id
    )

    if ($token) {
        try {
            $response = Invoke-RestMethod -Method Get `
                -Uri "https://api.up.com.au/api/$($APIVersion)/transactions/$($id)" `
                -Headers @{Authorization = "Bearer $($token)" }
            return $response.data  
        }
        catch {    
            Write-Error $_
            break 
        }
    }
    else {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
}
$CommandsToExport += 'Get-UpBankTransaction'


function Get-UpBankAccountTransactions {
    <#
.SYNOPSIS
Retrieve a list of all transactions for a specific account for the currently authenticated user.
 
.DESCRIPTION
Retrieve a list of all transactions for a specific account for the currently authenticated user.
 
.PARAMETER accountID
(Required) Account ID to return transactions from.
 
.PARAMETER pageSize
The number of records to return in each page. Defaults to 100
 
.PARAMETER since
(Optional) The start date-time from which to return records, formatted according to rfc-3339.
 
.PARAMETER until
(Optional) The end date-time up to which to return records, formatted according to rfc-3339.
 
.EXAMPLE
Get-UpBankAccountTransactions -accountID 4bda3ac4-034e-44bc-b761-8277ccbfe2ee
 
.LINK
http://darrenjrobinson.com/
 
#>


    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [String] $accountID,
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $pageSize = "100",
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $since,
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $until
    )

    if ($token) {
        Add-Type -AssemblyName System.Web

        try {
            [boolean]$blnPage, $blnSince, $blnUntil = $false 
            $baseURI = "https://api.up.com.au/api/$($APIVersion)/accounts/$($accountID)/transactions"
            $query = $null 

            if (!$pageSize -lt "100") {
                $blnPage = $true
                $recordsToReturn = $pageSize
                $query = "?page[size]=100"
            }
            else {
                $blnPage = $true
                $recordsToReturn = $pageSize
                $query = "?page[size]=$($pageSize)"
            }

            if ($since) {
                [boolean]$blnSince = $true        
                if ($blnPage) {
                    $query += "&filter[since]=$($since)"
                }
                else {
                    $query = "?filter[since]=$($since)"
                }
            }
            if ($until) {
                [boolean]$blnUntil = $true 

                if ($blnPage -or $blnSince) {
                    $query += "&filter[until]=$($until)"
                }
                else {
                    $query = "?filter[until]=$($until)"
                }
            }

            $queryEncoded = [System.Web.HttpUtility]::UrlEncode($query)
            $queryEncoded = (Get-Culture).TextInfo.ToUpper($queryEncoded)
            $queryEncoded = $queryEncoded.Replace("%3F", "?")
            $queryEncoded = $queryEncoded.Replace("%3D", "=")
            $queryEncoded = $queryEncoded.Replace("%26", "&")
            $queryEncoded = $queryEncoded.Replace("SINCE", "since")
            $queryEncoded = $queryEncoded.Replace("FILTER", "filter")
            $queryEncoded = $queryEncoded.Replace("UNTIL", "until")
            $queryEncoded = $queryEncoded.Replace("PAGE", "page")
            $queryEncoded = $queryEncoded.Replace("SIZE", "size")
            
            $response = Invoke-RestMethod -Method Get `
                -Uri "$($baseURI)$($queryEncoded)"  `
                -Headers @{Authorization = "Bearer $($token)" }
                
            if ($response.links.next) {
                $fullResponse = $null 
                $fullResponse += $response.data
                while ($response.links.next) {
                    $results = $null 
                    $results = Invoke-RestMethod -Method Get `
                        -Uri $response.links.next `
                        -Headers @{Authorization = "Bearer $($token)" }
                    if ($results) {
                        $fullResponse += $results.data
                        $response = $results
                    }
                    if ($fullResponse.count -gt $recordsToReturn) {
                        return $fullResponse | Select-Object -First $recordsToReturn
                        break  
                    }
                }
                return $fullResponse.data
            }
            else {
                return $response.data  
            }
                

        }
        catch {    
            Write-Error $_
            break 
        }
    }
    else {
        Write-Error "No Personal Access Token found in Up Bank Configuration. Use Set-UpBankCredential and Save-UpBankConfiguration to securely store you Up Bank Personal Access Token."
        break
    }
}
$CommandsToExport += 'Get-UpBankAccountTransactions'
# SIG # Begin signature block
# MIIX8wYJKoZIhvcNAQcCoIIX5DCCF+ACAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU/rFVkY1Z57D6YKJXQXxiebRx
# H0OgghMmMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B
# AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG
# A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh
# d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg
# Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV
# UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu
# dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q
# WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC
# i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4
# ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3
# +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI
# fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd
# BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG
# CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro
# YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV
# HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y
# MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf
# plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y
# 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq
# IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3
# DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh
# dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD
# QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE
# BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT
# eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow
# mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0
# jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu
# ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh
# d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz
# C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB
# o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO
# BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw
# Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90
# cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx
# oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy
# bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV
# HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa
# 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH
# bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73
# BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR
# EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW
# yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu
# e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw
# ggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9v
# dCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYT
# AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy
# dC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNp
# Z25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4R
# r2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrw
# nIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnC
# wlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8
# y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM
# 0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6f
# pjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud
# DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGsw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw
# AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE
# Um9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNl
# cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDov
# L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBP
# BgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93
# d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoK
# o6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8w
# DQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+
# C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119E
# efM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR
# 4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4v
# cn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwH
# gfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggVVMIIEPaADAgEC
# AhAM7NF1d7OBuRMX7VCjxmCvMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVT
# MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
# b20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25p
# bmcgQ0EwHhcNMjAwNjE0MDAwMDAwWhcNMjMwNjE5MTIwMDAwWjCBkTELMAkGA1UE
# BhMCQVUxGDAWBgNVBAgTD05ldyBTb3V0aCBXYWxlczEUMBIGA1UEBxMLQ2hlcnJ5
# YnJvb2sxGjAYBgNVBAoTEURhcnJlbiBKIFJvYmluc29uMRowGAYDVQQLExFEYXJy
# ZW4gSiBSb2JpbnNvbjEaMBgGA1UEAxMRRGFycmVuIEogUm9iaW5zb24wggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCPs8uaOSScUDQwhtE/BxPUnBT/FRn
# pQUzLoBTKW0YSKAxUbEURehXJuNBfAj2GGnMOHaB3EvdbxXl1NfLOo3wtRdro04O
# MjOH56Al/9+Rc6DNY48Pl9Ogvuabglah+5oDC/YOYjZS2C9AbBGGRTFjeGHT4w0N
# LLPbxyoTF/wfqZNNy5p+C7823gDR12OvWFgEdTiDnVkn3phxGy8xlK7yrJwFQ0Sn
# z8RknEFSaoKnuYqLvaOiOSG77q6M4+LbGAbwhYToaqWa4xWFFJS8XsX0+t6LA+0a
# Kb3ZEb1GyfySDW2TFf/V1RhuM4iBc6YTUUCj9BTqcpWKgkw2k2xUQHP9AgMBAAGj
# ggHFMIIBwTAfBgNVHSMEGDAWgBRaxLl7KgqjpepxA8Bg+S32ZXUOWDAdBgNVHQ4E
# FgQU6HpAuSSJdceLWep4ajN6JIQcAOgwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM
# MAoGCCsGAQUFBwMDMHcGA1UdHwRwMG4wNaAzoDGGL2h0dHA6Ly9jcmwzLmRpZ2lj
# ZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMDWgM6Axhi9odHRwOi8vY3Js
# NC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDBMBgNVHSAERTBD
# MDcGCWCGSAGG/WwDATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy
# dC5jb20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzAB
# hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9j
# YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2ln
# bmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQA1agcO
# M3seD1Cs5pnHRXwwrhzieRgF4UMJgDI/9KrBh4C0o8DsXvaa+YlXoTdhmeKW/xv5
# i9mkVNmvD3wa3AKe5CNwiPc5kx96lC7BXWfdLoY7ejfTGkoa7qHR3gusmQhuZW+L
# dFmvtTyu4eqcjhOBthoJYp3B8tv8JR99pSxFfsE6C4VGdhKHAmZkDMiaAHHava9Z
# xl4+Uof+TuS6lQBZJjw8Xw76W93DNU9JUNb4+hOp8jir1q7/RTvtQ3QWr+iEzJD8
# JRfvfXF4LpFvlOOWYOF22EU/ciGjUVfQYi7nk/LnHzipb46747K1BwAVnHbYMDx0
# BRtLc/s4g9qZxTrxMYIENzCCBDMCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV
# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G
# A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQ
# DOzRdXezgbkTF+1Qo8ZgrzAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAig
# AoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgEL
# MQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUwtZEoy/5l8dW1ljkrjaW
# RPvl+HgwDQYJKoZIhvcNAQEBBQAEggEAc3S+XjkYhFQOGB/JQ+TRSq3BzVJ3dZpd
# tSv+4XaQVqvcFApDkJ8zaGoj4T3xcMuC9yXEdHecuZNUma5anyvDBF1ZojHRgXcM
# GQzuCWvrc+2C5FRNHBkTKclM17m/lzyrgBrBlM23MX4loOdyHDqb8JecMGHTZ2sy
# TY1XVdZUUeyT/UQNoaF1OCVc6TncJBe0OrGWPvQXxd3Sti/OEZucUfdkinSlIU6I
# CabDT2JnoRTPaVQ3jVrHbjcE3YVech9ZKIxk3lKSOwi+cjYu3fHnm8vRehw33cwz
# hElf5hMkzMy9FuiNO7A3bpMWTBt2peBQwzHuWOpW2MssXqUrlKcRp6GCAgswggIH
# BgkqhkiG9w0BCQYxggH4MIIB9AIBATByMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQK
# ExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBT
# dGFtcGluZyBTZXJ2aWNlcyBDQSAtIEcyAhAOz/Q4yP6/NW4E2GqYGxpQMAkGBSsO
# AwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP
# Fw0yMDA3MzAwMzEzMjZaMCMGCSqGSIb3DQEJBDEWBBQ1UPng6B7s3al3GaorCj91
# 58hJ4DANBgkqhkiG9w0BAQEFAASCAQALDMMf3XwbQrfK5h1Wgnk8OKEg1897olHQ
# 0chRWeYETrHksiaZ9hUy6RsJWlbuIDUhXQgvfqtKRdIRdSNG+NLpRTvcBqZsaSta
# /OqMHw0j5FKVgD8jT5TvwjtWIXIg0N7pNf8DkV3E6wafkd/KOtwX2fAFs2NI1vLu
# G9mQjCSRcMQOHJbml9F8Y00P7ViToQH/Qx39h2zeYPCA5gW1DIMI+8bVhP4qKVGX
# ufzIJf1cy3555C9Hxi1MxhmBLlqWIIOSDH6gtdRoyCBQbj4oSbLRMmETVk4MkGEn
# 9m6GPIoUJPdHLmKp8XnVoiOdDdN76zDVzu0gtOaVDZKFXDK3y3SY
# SIG # End signature block