public/New-CsFixedNumberDiversion.ps1

#PerformScriptSigning
Function New-UcmCsFixedNumberDiversion
{
    <#
            .SYNOPSIS
            Diverts a number associated with Microsoft Teams Via Microsoft Calling plans or Telstra Calling to an external PSTN number
 
            .DESCRIPTION
            Diverts a number associated with Microsoft Teams Via Microsoft Calling plans or Telstra Calling to an external PSTN number by performing the following actions
            - Creates a Resource Account with named "PSTN_FWD_<inboundNumber>@domain.onmicrosoft.com" by default (Configurable using -AccountPrefix)
            - Licences the account with a Virtual Phone System Licence
            - Licences the account with an appropriate calling licence specified using -LicenceType
            - Creates an AutoAttendant with a 24 hour schedule
            - Configures a forward rule in the AutoAttendant
 
            Note: All accounts will be "Cloud born" and use your tenants onmicrosoft domain as syncing accounts is a PITA
            Warning: The script presently only supports Cloud Numbers, attempting to use Direct Routing numbers will fail.
 
            .EXAMPLE
            PS> New-UcmCsFixedNumberDiversion -OriginalNumber +61370105550 -TargetNumber +61755501234 -Domain Contoso.onmicrosoft.com -Country AU -LicenceType MCOPSTNEAU2
            Forwards the number 61370105550 to 61755501234
 
            .PARAMETER OriginalNumber
            The number of the new AutoAttendant. IE: The number to wish to forward FROM
 
            .PARAMETER TargetNumber
            The number the AutoAttendant will forward calls to. IE: the number to wish to forward TO
 
            .PARAMETER Domain
            This is the domain name that will be used to create the resource accounts for the diversion. This should be an "onmicrosoft" domain or fully AzureAD domain to minimise any directory sync issues
            For example "Contoso.onmicrosoft.com"
 
            .PARAMETER LicenceType
            How will we licence the AutoAttendant to make PSTN calls, Valid options are, MCOPSTN1, MCOPSTN2, MCOPSTNEAU2
            Note, we presently dont support direct routing. I'll get there.
 
            .PARAMETER Country
            As we are setting licence's for the virtual users, we need to know what country to licence them in.
            Make sure to use upper case!
 
            .PARAMETER AccountPrefix (optional)
            This is the name that will be placed before the inbound phone number in the account name, used if you have a special naming convention for service accounts
            "PSTN_FWD_" by default
 
 
            .PARAMETER AADisplayName (optional)
            The name to assign to the AutoAttendant "<Original Number> Forward" by default
 
            .INPUTS
            This function accepts both parameter and pipline input
 
            .OUTPUT
            This Cmdet returns a PSCustomObject with multiple Keys to indicate status
            $Return.Status
            $Return.Message
 
            Return.Status can return one of three values
            "OK" : The Auto Attendent was created
            "Error" : Something went wrong creating the AA, check the output for more information.
            "Unknown" : Cmdlet reached the end of the function without returning anything, this shouldnt happen, if it does please log an issue on Github
 
            Return.Message returns descriptive text based on the outcome, mainly for logging or reporting
 
            .NOTES
            Version: 1.2
            Date: 02/04/2023
 
            .VERSION HISTORY
 
            1.2 Updates for UcmPsTools public module
                Added Country Validation
                Added account creation error checking
                Updated timeframe handling to support updated Teams backend storing all new timeframes as global
                Resolved an issue with E164 formatted numbers causing AAD Account issues
                Resolved an issue with E164 formatted numbers causing invalid forward destinations
                Resoved issues with 'CallHandlingAssociations' parmeter stripping
                Updated to use Set-CsPhoneNumberAssignment instead of 'Set-CsOnlineVoiceApplicationInstance'
 
            1.1: Documentation changes
 
            1.0: Initial Public Release
 
            .REQUIRED FUNCTIONS/MODULES
            Modules
            AzureAD (Install-Module AzureAD)
            MSOnline (Install-Module MSOnline)
            UcmPSTools (Install-Module UcmPsTools) Includes Cmdlets below.
 
            Cmdlets
            Write-UcmLog: https://github.com/Atreidae/UcmPsTools/blob/main/public/Write-UcmLog.ps1
            Write-HTMLReport: https://github.com/Atreidae/UcmPsTools/blob/main/public/Write-HTMLReport.ps1 (optional)
            New-UcmTeamsResourceAccount
            New-UcmOffice365User
            Grant-UcmOffice365UserLicence
            Test-UcmO365ServicePlan
 
            .REQUIRED PERMISSIONS
            'Office365 User Admin' and 'Teams Admin' or better
 
            .LINK
            https://www.UcMadScientist.com
            https://github.com/Atreidae/UcmPSTools
 
            .ACKNOWLEDGEMENTS
            Stack Overflow, disabling services: https://stackoverflow.com/questions/50492591/how-can-i-disable-and-enable-office-365-apps-for-all-users-at-once-using-powersh
            Alex Verboon, Powershell script to remove Office 365 Service Plans from a User: https://www.verboon.info/2015/12/powershell-script-to-remove-office-365-service-plans-from-a-user/
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function')] #Todo https://github.com/Atreidae/UcmPSTools/issues/27

Param
(
    [Parameter(ValueFromPipelineByPropertyName=$true, mandatory=$true, Position=1)] [string]$OriginalNumber,
    [Parameter(ValueFromPipelineByPropertyName=$true, mandatory=$true, Position=2)] [string]$TargetNumber,
    [Parameter(ValueFromPipelineByPropertyName=$true, Position=3)] [string]$AccountPrefix="PSTN_FWD_",
    [Parameter(ValueFromPipelineByPropertyName=$true, mandatory=$true, Position=4)] [string]$Domain,
    [Parameter(ValueFromPipelineByPropertyName=$true, mandatory=$true, Position=5)] [string]$LicenceType,
    [Parameter(ValueFromPipelineByPropertyName=$true, mandatory=$true, Position=6, HelpMessage='The 2 letter country code for the users country, must be in capitals. eg: AU')] [ValidateSet("AF","AX","AL","DZ","AS","AD","AO","AI","AQ","AG","AR","AM","AW","AU","AT","AZ","BS","BH","BD","BB","BY","BE","BZ","BJ","BM","BT","BO","BQ","BA","BW","BV","BR","IO","BN","BG","BF","BI","CV","KH","CM","CA","KY","CF","TD","CL","CN","CX","CC","CO","KM","CG","CD","CK","CR","CI","HR","CU","CW","CY","CZ","DK","DJ","DM","DO","EC","EG","SV","GQ","ER","EE","SZ","ET","FK","FO","FJ","FI","FR","GF","PF","TF","GA","GM","GE","DE","GH","GI","GR","GL","GD","GP","GU","GT","GG","GN","GW","GY","HT","HM","VA","HN","HK","HU","IS","IN","ID","IR","IQ","IE","IM","IL","IT","JM","JP","JE","JO","KZ","KE","KI","KP","KR","KW","KG","LA","LV","LB","LS","LR","LY","LI","LT","LU","MO","MG","MW","MY","MV","ML","MT","MH","MQ","MR","MU","YT","MX","FM","MD","MC","MN","ME","MS","MA","MZ","MM","NA","NR","NP","NL","NC","NZ","NI","NE","NG","NU","NF","MK","MP","NO","OM","PK","PW","PS","PA","PG","PY","PE","PH","PN","PL","PT","PR","QA","RE","RO","RU","RW","BL","SH","KN","LC","MF","PM","VC","WS","SM","ST","SA","SN","RS","SC","SL","SG","SX","SK","SI","SB","SO","ZA","GS","SS","ES","LK","SD","SR","SJ","SE","CH","SY","TW","TJ","TZ","TH","TL","TG","TK","TO","TT","TN","TR","TM","TC","TV","UG","UA","AE","GB","US","UM","UY","UZ","VU","VE","VN","VG","VI","WF","EH","YE","ZM","ZW")][String]$Country,
    [Parameter(ValueFromPipelineByPropertyName=$true, Position=7)] [string]$AADisplayName
)


BEGIN
{
    $StartTime = Get-Date
    $Script:LogFileLocation = $PSCommandPath -replace '.ps1','.log' #Needing to actually figure out a better way of doing this for the module TODO

    Write-UcmLog -Message "$ScriptVersion script started at $StartTime" -Severity 1 -Component $Function
    Write-UcmLog -Message "Perfoming connection checks" -Severity 2 -Component $Function

    #Check to see if we are connected to SFBO
    $Test = (Test-UcmSFBOConnection -reconnect)
    If ($Test.Status -eq "Error")
    {
    Write-UcmLog -Message "Couldnt configure diversions." -Severity 3 -Component $function
    Write-UcmLog -Message "Test-SFBOConnection could not locate an SFBO connection" -Severity 2 -Component $function
    $Return.Status = "Error"
    $Return.Message = "No SFBO Connection ( $($test.message) )"
    Return $Return
    }

    #Check to see if we are connected to MSOL
    $Test = (Test-UcmMSOLConnection -reconnect)
    If ($Test.Status -eq "Error")
    {
    Write-UcmLog -Message "Couldnt configure diversions." -Severity 3 -Component $function
    Write-UcmLog -Message "Test-UcmMSOLConnection could not locate an MSOL connection" -Severity 2 -Component $function
    $Return.Status = "Error"
    $Return.Message = "No MSOL Connection ( $($test.message) )"
    Return $Return
    }

    #Everything went well, lets get ready for pipline
    #Create an object to store all our pipeline objects
    $Objects= @()
}


PROCESS
{
    #Check to see if we got something on the pipeline, if we did. process it

    if ($OriginalNumber)
    {
        Write-UcmLog -Message "Executing process block with Diversion for $originalNumber" -Severity 2 -Component $Function

        $OriginalNumber = ($OriginalNumber).TrimStart("tel:+")
        $OriginalNumber = ($OriginalNumber).TrimStart("+")
        $TargetNumber = ($TargetNumber).TrimStart("tel:+")
        $TargetNumber = ($TargetNumber).TrimStart("+")

        if ($null -eq $AADisplayName) {$AADisplayName = ($OriginalNumber + " Forward")}

        $AADisplayName = ($OriginalNumber + " Forward")  #todo fix the damn naming problem
        Write-UcmLog -Message "Displayname $AADisplayName" -Severity 2 -Component $Function
        #Create the resource account
        $UPN = ($AccountPrefix + $OriginalNumber + "@" + $domain)

        #Check for Resource Account
        #Powershell throws an error if the account isnt found, so lets trap it and use that instead

        Try
        {
            $AAAccount = (get-csonlineapplicationinstance -Identity $upn -ErrorAction Stop)
            Write-UcmLog -Message "Found Existing Resource Account, skipping creation" -Severity 2 -Component $function
            Write-UcmLog -Message $AAAccount -Severity 2 -Component $function
        }

        #we didnt find the account, make it
        Catch
        {
            Write-UcmLog -Message "Creating Required Resource Account" -Severity 2 -Component $function
            $AAAccounttemp = (New-UcmTeamsResourceAccount -upn $upn -ResourceType Autoattendant -displayname "$originalnumber forward")
            Write-UcmLog -Message "waiting for account to appear in AzureAD" -Severity 2 -Component $function

            #start checking for the account
            For ($i = 0; $i -lt 7)
            {
                #Check we havent been waiting too long
                if ($i -gt 5)
                {
                    Write-UcmLog -Message "Account has not appeared after 60 seconds!" -Severity 3 -Component $function
                    Write-UcmLog -Message "Aborting account $AADisplayName" -Severity 3 -Component $function
                    Return
                }

                Write-UcmLog -Message "Waiting 10 seconds" -Severity 2 -Component $function
                Start-sleep -seconds 10
                Try
                {
                    $AAAccount = (get-csonlineapplicationinstance -Identity $upn -ErrorAction stop)
                    Write-UcmLog -Message "Account found" -Severity 2 -Component $function
                    Continue
                }
                Catch
                {
                    Write-UcmLog -Message "Account not found, trying again" -Severity 2 -Component $function
                    $i ++
                }
            }
        }

        #todo, better error handling
        #If ($AAAccount.status -eq "Error") {Throw "something went wrong creating the resource account"}

        #Licence the account for Phone system
        $Licence1 = (Grant-UcmOffice365UserLicence -licencetype PHONESYSTEM_VIRTUALUSER -country $country -upn $upn)

        #Licence the account for PSTN calling
        $Licence2 = (Grant-UcmOffice365UserLicence -licencetype $licencetype -country $country -upn $upn)

        #todo, better error handling
        If ($licence1.status -eq "Error" -or $Licence2.status -eq "Error") {Throw "Something went wrong assinging licences"}


        #Pull the user and make it a callable object

        #$operatorObjectId = (Get-CsOnlineUser $UPN).ObjectId
        #$operatorEntity = New-CsAutoAttendantCallableEntity -Identity $operatorObjectId -Type User

        #check to see if the Autoattendant already exists
        Write-UcmLog -Message "Checking for Existing Autoattendant" -Severity 2 -Component $function
        $o=$null
        $o=(Get-CsAutoAttendant -NameFilter $AADisplayName)

        If ($o -eq $BeNullOrEmpty)
        {
            Write-UcmLog -Message "New-CsAutoAttendantCallableEntity" -Severity 1 -Component $function
            $CallForwardEntity = New-CsAutoAttendantCallableEntity -Identity "tel:+$TargetNumber" -Type ExternalPSTN

            Write-UcmLog -Message "New-CsAutoAttendantMenuOption" -Severity 1 -Component $function
            $DiversionMenuOption = New-CsAutoAttendantMenuOption -Action TransferCallToTarget -DtmfResponse Automatic -CallTarget $CallForwardEntity

            Write-UcmLog -Message "New-CsAutoAttendantMenu" -Severity 1 -Component $function
            $DiversionMenu = New-CsAutoAttendantMenu -Name "Fixed Diversion" -MenuOptions @($DiversionMenuOption)

            Write-UcmLog -Message "New-CsAutoAttendantCallFlow" -Severity 1 -Component $function
            $DiversionCallFlow = New-CsAutoAttendantCallFlow -Name "Fixed Diversion" -Menu $DiversionMenu

            Write-UcmLog -Message "New-CsAutoAttendant $o=New-CsAutoAttendant -Name $AADisplayName -DefaultCallFlow $DiversionCallFlow -CallHandlingAssociations @($afterHoursCallHandlingAssociation) -Language 'en-AU' -TimeZoneId 'AUS Eastern Standard Time'" -Severity 1 -Component $function
            #$o=New-CsAutoAttendant -Name $AADisplayName -DefaultCallFlow $DiversionCallFlow -CallHandlingAssociations @($afterHoursCallHandlingAssociation) -Language "en-AU" -TimeZoneId "AUS Eastern Standard Time"
            $o=New-CsAutoAttendant -Name $AADisplayName -DefaultCallFlow $DiversionCallFlow -Language "en-AU" -TimeZoneId "AUS Eastern Standard Time"

            Write-UcmLog -Message "App instance lookup" -Severity 1 -Component $function
            $applicationInstanceId = (Get-CsOnlineUser $UPN).ObjectId

            Write-UcmLog -Message "New-CsOnlineApplicationInstanceAssociation" -Severity 2 -Component $function
            New-CsOnlineApplicationInstanceAssociation -Identities @($applicationInstanceId) -ConfigurationId $O.identity -ConfigurationType AutoAttendant

            Write-UcmLog -Message "Get-csAutoAttendant" -Severity 1 -Component $function
            Get-csAutoAttendant -Identity $o.identity
        }

        Else
        {
            Write-UcmLog -Message "Found Existing Autoattendant, Checking for Resource Account" -Severity 2 -Component $function

            if ([bool]$o.ApplicationInstances -eq $false)
            {
                Write-UcmLog -Message "Resource Account Association Missing, fixing" -Severity 3 -Component $function

                Write-UcmLog -Message "App instance lookup" -Severity 1 -Component $function
                $applicationInstanceId = (Get-CsOnlineUser $UPN).identity

                Start-sleep -seconds 10

                Write-UcmLog -Message "New-CsOnlineApplicationInstanceAssociation" -Severity 2 -Component $function
                [void](New-CsOnlineApplicationInstanceAssociation -Identities @($applicationInstanceId) -ConfigurationId $O.identity -ConfigurationType AutoAttendant)
            }
        }

        #Assign the phone number to the resource account
        Write-UcmLog -Message "Assigning Number to Resource Account" -Severity 2 -Component $function

        #Set-CsOnlineApplicationInstance -Identity $AAUPN -OnpremPhoneNumber $telephoneNumber ## Direct Routing version!
        #Set-CsOnlineVoiceApplicationInstance -Identity $UPN -TelephoneNumber $telephoneNumber -verbose ##Deprecated
        Set-CsPhoneNumberAssignment -Identity $UPN -PhoneNumber "+$OriginalNumber" -PhoneNumberType CallingPlan  ##todo update for more calling types
    }
    Else
    {
        Throw "Nothing to process"
    }
    #endregion FunctionWork
}


END
{
    #region FunctionSetup, Set Default Variables for HTML Reporting and Write Log
    $function = 'END-Block'

    # Log why we were called
    Write-UcmLog -Message "$($MyInvocation.InvocationName) called with $($MyInvocation.Line)" -Severity 1 -Component $function
    Write-UcmLog -Message "Parameters" -Severity 3 -Component $function -LogOnly
    Write-UcmLog -Message "$($PsBoundParameters.Keys)" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "Parameters Values" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "$($PsBoundParameters.Values)" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "Optional Arguments" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "$Args" -Severity 1 -Component $function -LogOnly

    #endregion FunctionSetup

    Write-UcmLog -Message "Executing process block with Attendant $DisplayName" -Severity 1 -Component $Function
}

}#end function
# SIG # Begin signature block
# MIIRwgYJKoZIhvcNAQcCoIIRszCCEa8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUvDbnXr8F4AoqfKC2n2krR9pN
# nd6ggg4OMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B
# AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk
# IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg
# Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5
# WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP
# DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz
# ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq
# HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC
# fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD
# G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO
# kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD
# K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4
# R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN
# Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I
# U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA
# FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4
# oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN
# AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT
# Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT
# auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9
# ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37
# 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0
# HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL
# 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1
# 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8
# M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF
# hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy
# 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHVjCC
# BT6gAwIBAgIQDyLHeeRvkUFg5QtSFTT8FjANBgkqhkiG9w0BAQsFADBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg
# Q0ExMB4XDTIzMDIyMzAwMDAwMFoXDTI2MDIyMzIzNTk1OVowXjELMAkGA1UEBhMC
# QVUxETAPBgNVBAgTCFZpY3RvcmlhMRAwDgYDVQQHEwdCZXJ3aWNrMRQwEgYDVQQK
# EwtKYW1lcyBBcmJlcjEUMBIGA1UEAxMLSmFtZXMgQXJiZXIwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQC47oExh25TrxvApIYdMRYvjOdZCb8WwgeTemm3
# ZY7BElIWu6+gzRGqQe8RFsN7oIgin5pvjTYIToxt1CCag2A5o8L0NtULmxJEegc+
# VaF24DZQqI4qGQGH/Qnglqys6+yPkwLnfeSxpeWe4u49HUUGDFIxHCh42MlCLp/f
# fHT49QhhpO+LyeLnDoUs6DmahyIb6NeE2cW5AYRXEesW7GRNfXzygBSlVWJOgvcy
# V5Y4IvAZVx2hKKMTjYFIz4/RYMg7fwYZEJ2LRJ/GnVazobKAvh6ZBet5KwVNI9EI
# 29DtWQyK/RoPOguTRcB5VuiZVlv0xjBYM7iJuH2Soa3StQYVxL/5gjZCC9WOs4NR
# EIGU3XmHoogFDvoT1vf1izMPFQzdZfgPvy/XXsbgTVo5ncesJ6WtZwqwCXG1K0XW
# IPZqTHolc1MyU6K1bEHO+7YWLpKgM9THl644G7PEhcKpNDsHlfvLVQdYhI55UJtc
# iyMrTw11CNECvk3GK1mrluvKsrxdaH6G3Sp9VVHRtef6OZ5SlzkM5ID4egB2bXRb
# R/69bEuZr5hhm+v2lBSWIbZj/Mva6i/a/TAvy4vvPLo3DRcASkYZDC4T8gDMzmpG
# Xs4jAc9sfTL9z+o5u1PLJHFGRjJ+Wa2CgSftCdbKLjn+AY9m8ipc8jmOBKNY9yGI
# pQWapQIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0
# TkIwHQYDVR0OBBYEFOBsg1xudlbXVSql8pWbiHoTyZS/MA4GA1UdDwEB/wQEAwIH
# gDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRw
# Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmlu
# Z1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hB
# Mzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcC
# ARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCB
# hDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUF
# BzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk
# RzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAA
# MA0GCSqGSIb3DQEBCwUAA4ICAQBOh5vRXqTCQzv0T1F2EgDkq5VnljlHsa7Ov/d/
# lpOvr8NebBiatxbhfhPCnToY7BD2f7YVsUuQ+VDdcIYsskcU5spBHcFYidg2jGu4
# 59FGMaS765XStDwGGTN/360gEsNYSnKWYL4+8jYWHlzRO0jHloyWz+gF5dYWzdDJ
# u1dudLIJ0RgrEVJeLSgIBWygLL5EyIzOPlrxztsILMSbdPTQLeBIm7ipOk4EACx1
# hhBVUsUoCAlASH+yCKDU4v2HFd7SzrkRUrf7XJ2Na2YsiHjiTGqHIE86KyvxGDhT
# 3n2/jX23Nh/bkWHurHwTfaTCOQ44ZlAbnZQjBlmrFn5hPMXRpciiQFmrKTPD/nuo
# 9MVnCciHEpHJ63/JZNF/eno1122/wVkL7MuRlCVHN7L/wuNQxQk3ARdIju6OD/Gi
# Mwg0Qih6HVWJtkHK3ExoUKKKUZCOvIeHxzp+K6FWUupPZKUgWzn4AHMxm6zr+Sde
# laIAACqAkxYsDYKbM7WlNi3uIH2HeXqU9uSDt5tgPpImrog/ab4HrhpDfITRgT1c
# cxaWQezpJEPC+kqVD41T3wlEie1Qm4vYWg+oBVEMBxVLh6CYbeppCRTEXRGnAiCH
# /Ma1uwyWnNCWxrhd1uSi6sj4ISzgnFyGCvsI0gavKpS5AQhapJgk6/fULTFeS+Ee
# kRH9FDGCAx4wggMaAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2ln
# bmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQDyLHeeRvkUFg5QtSFTT8FjAJ
# BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj
# BgkqhkiG9w0BCQQxFgQU43XOXk8u3F1WEdawU/NpQhLv4aMwDQYJKoZIhvcNAQEB
# BQAEggIAZTmKkJ02pAVNYcF5jGos6APvOP7V76lhDF6TvNGFUy/yy5+hSlV5+rAz
# TpjOI2RtArBMS/dtm5tD6EmiGYl51PApCnv5TEywsoeN+qxbdXL3dheMaWtdT2HV
# waAQpYbjP+pG287Yby0Mhbt3phmyRXvWsUPUgEPiahag557uc6Tw/dctmqmZfcU7
# SdFyLSBtwLW5GYwwxSLBqLsl3M4C0qbmtluJindNcDCaTRdVGvInycAAFLFOoTBD
# YeL2gwo/B0LvOxr2Muppc85EMzbPzDzaETDQwpM9/BbwkyCzIStM5Ut03r5k2gM1
# 5m9S760XeQUcBOzq3v270i2LwQ+URwuo6UqbJG8TVTEC0z48W9nTV9KQ88/UJHwN
# oN81HG83w1CneL1lw1M5mfnW6HNh51BwgnZDrhro/rwpjk6ltFVkeacMsJ4rk69L
# P46H9SZuZZXNy7ph2lqj/+rY7mQMaJVFj74DfdSnet1ZqAl+rMdi05RooEwR0K99
# yEkFLcgT46arPthqY31KXGPY0IGbhThavGw2q2INO5Y4ak63zITT0COwkMjsRD36
# 7BmWDj0MbKeGu8lRZGURfNuoP4dg2i2YvTBlbH52R4pX3k0XEGzX8bhTEgHLYdrn
# v7mmL7zb4Xwq/QSFkHmjPpCQptzKDDyw80c3YoKivjZmbIRnrEw=
# SIG # End signature block