Remove-AaddsReplicaSet.ps1

<#PSScriptInfo
.VERSION 1.1
.GUID C61B2D1A-F750-47F5-B51D-57A9AFF95EEB
.AUTHOR aaddsfb@microsoft.com
.COMPANYNAME Microsoft Corporation
.COPYRIGHT (c) Microsoft Corporation
.TAGS Azure-AD-Domain-Services ReplicaSet
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
    07/19/2020 - Initial release
#>


<#
 
.SYNOPSIS
    Removes a replica set from an Azure AD Domain Services domain.
 
.DESCRIPTION
 
    Removes a replica set from an Azure AD Domain Services domain.
 
.PARAMETER ManagedDomainFqdn
    The fqdn of the managed domain (aadds.ufcontoso.com).
    This parameter is mandatroy.
 
.PARAMETER RsResourceGroupName
    The name of resource group hosting the replica set's subnet.
    This parameter is optional.
 
.PARAMETER RsVnetName
    The name of the virtual network hosting the replica set's subnet.
    This parameter is optional.
     
.PARAMETER RsSubnetName
    The name of the virtual subnet hosting the replica set.
    This parameter is optional.
 
.PARAMETER Credential
    The credentials used to authenticate to Azure.
    This parameter is optional.
#>


[CmdletBinding()]
Param (
    
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Specific")]
    [Parameter(
        Mandatory=$true,
        ParameterSetName="UI")]
        [string]
        $ManagedDomainFqdn,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Specific")]
        [string]
        $RsResourceGroupName,
    
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Specific")]
        [string]
        $RsVnetName,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Specific")]
        [string]
        $RsSubnetName,
    
    [Parameter(
        Mandatory=$false,
        ParameterSetName="Specific")]
    [Parameter(
        Mandatory=$false,
        ParameterSetName="UI")]
        [pscredential]
        $Credentials
)


Process
{
function New-HeuristicSubnetId([string] $subscriptionId, 
    [string] $targetResourceGroup, 
    [string] $targetVnetName,
    [string] $targetSubnetName)
{
    $rv = [String]::Empty

    if( ([string]::Empty -eq $subscriptionId) -or 
        ([string]::Empty -eq $targetResourceGroup) -or
        ([string]::Empty -eq $targetVnetName) -or 
        ([string]::Empty -eq $targetSubnetName) )
        {
            return $rv
        }

    $rvTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}/subnets/{3}"

    $rv = ($rvTemplate -f $subscriptionId, $targetResourceGroup, $targetVnetName, $targetSubnetName)
    
    return $rv
}

function Get-AaddsSubscription([string] $managedDomainFqdn)
{
    #
    # Locate Azure AD Domain Services in a subscription
    # Use the first instance found as there should only be one instance per tenant
    $rv = [String]::Empty
        
    ($AzSubs = Get-AzSubscription) | Out-Null 
    foreach($azsub in $AzSubs)
    {
        (Select-AzSubscription $azsub.Id) | Out-Null
        
        $aadds = Get-AzResource -Name $managedDomainFqdn -ApiVersion 2020-01-01 -ExpandProperties -ErrorAction SilentlyContinue

        if($null -ne $aadds)
        {
            # Found Azure AD DS in this subscription
            # Add to the subscription List
            $rv = $azsub.Id
            break
        }
    }

    return $rv 
}

function Convert-SubnetResourceIdToVnetName( [string] $subnetResourceId)
{
    [int] $SUBNET_NAME_INDEX = 9
    [int] $VNET_NAME_INDEX = 7
    
    $rv = [string]::Empty
    
    $parts = $subnetResourceId.Split("/",[System.StringSplitOptions]::RemoveEmptyEntries)
    if( ($SUBNET_NAME_INDEX+1) -ne $parts.Count)
        {return $rv}

    $rv = $parts[$VNET_NAME_INDEX]

    return $rv
}

    Write-Host ([String]::Empty)
    Write-Host -ForegroundColor Cyan "Remove-AaddsReplicaSet"

    # Create an empty replica set settings
    $replicaSetSettingsValue = [System.Collections.ArrayList]@()

    Write-Host ([string]::Empty)
    Write-Host ([string]::Empty)    
    Write-Host -ForegroundColor White "Authenticating to Azure Resource Manager..." -NoNewline

    $armSession = $null
    $vnetName = [string]::Empty
    $location = [string]::Empty

    #
    # Collect credentials from the user for authentication
    if($null -ne $Credentials)
    {        
        $armSession = Connect-AzAccount -Credential $Credentials -ErrorAction SilentlyContinue
    }
    else
    {        
        $armSession = Connect-AzAccount -ErrorAction SilentlyContinue
    }
    
    
    if($null -eq $armSession)
    {
        # Authentication failed
        Write-Host -ForegroundColor Red "[Failed!]"
        Write-Host -ForegroundColor Red "ERROR: Could not authenticate to Azure Resource Manager. Check your credentials and try again."
        Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message)
        Return
    }
    

    Write-Host -ForegroundColor Green "[Successs!]"
    Write-Host ("INFO: Authenticated to Azure as {0}" -f $armSession.Context.Account.Id)
    
    Write-Host "Searching for the Azure AD Domain Service subscription..." -NoNewline
    $azureSubscriptionId = Get-AaddsSubscription $ManagedDomainFqdn
    if([string]::Empty -eq $azureSubscriptionId)
    {
        Write-Host -ForegroundColor Red "[Failed!"]
        Write-Host -ForegroundColor Red "ERROR: Could not find a subscription that has Azure AD Domain Services."
        Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message)
        return
    }
    else
    {
        Write-Host -ForegroundColor Green "[Found!]"
        Select-AzSubscription $azureSubscriptionId -ErrorAction SilentlyContinue| Out-Null
    }
    

    Write-Host "Getting Azure AD Domain Services instance..." -NoNewline
    $aadds = Get-AzResource -Name $ManagedDomainFqdn -ApiVersion 2020-01-01  -ExpandProperties -ErrorAction SilentlyContinue

    if($null -eq $aadds)
    {
        Write-Host -ForegroundColor Red "[Failed!]"
        Write-Host -ForegroundColor Red ("ERROR: Could not find an Azure AD Domain Services resource with the name {0}." -f $ManagedDomainFqdn)        
        Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message)
        Return

    }

    $aaddsSyncOwnerId = $aadds.Properties.SyncOwner

    #region Prerequisites checking...
    Write-Host ([string]::Empty)
    Write-Host "Checking prerequisites..."
    
    Write-Host "Validating resource type..." -NoNewline
    if($aadds.ResourceType -ne "Microsoft.AAD/domainServices")
    {        
        Write-Host -ForegroundColor Red "[Failed!]"
        Write-Host -ForegroundColor Red ("ERROR: The resource is not an Azure AD Domain Services resource (Staus:{0})." -f $aadds.ResourceType)
        Return
    }
    else {Write-Host -ForegroundColor Green "[Pass!]"}

    Write-Host "Validating SKU..." -NoNewline
    if($aadds.properties.sku -eq "Standard")
    {        
        Write-Host -ForegroundColor Red "[Failed!]"
        Write-Host -ForegroundColor Red ("ERROR: The managed domain {0} is does not support replica sets." -f $aadds.Name)
        Write-Host ([string]::Empty)
        Write-Host -ForegroundColor White "Replica Sets are only avaiable on Enterprise and Premium higher SKUs."
        Return
    }
    else
    { Write-Host -ForegroundColor Green "[Pass!]"}
    
    $rs = $aadds.Properties.replicaSets
    
    # Check if a specific vnet and subnet were passed
    if($true -eq ([string]::Empty -eq $RsVnetName) -and ([string]::Empty -eq $RsSubnetName ))
    {
        # Show Menu
        Write-Host -ForegroundColor White "[INFO!] Showing Menu..."
        if(0 -gt $rs.Count)
        {
            Write-Host ("INFO: The managed domain {0} does not have any replica sets" -f $aadds.Name)
        }
        Write-Host ([string]::Empty)
        Write-Host -Foreground Yellow "Replica sets for domain: " -NoNewline
        Write-Host ("{0}" -f $aadds.Name)
        Write-Host ([string]::Empty)
        [int]$count = 0
        [int]$syncOwnerIndex = 0

        foreach($r in $rs)
        {
            Write-Host -ForegroundColor Cyan "Replica Set " -NoNewline
            Write-Host -ForegroundColor Yellow "[" -NoNewline
            Write-Host -ForegroundColor Green ("{0}" -f $count.ToString()) -NoNewline
            Write-Host -ForegroundColor Yellow "]"                                                
            
            if($r.replicaSetId -eq $aaddsSyncOwnerId)
            {
                Write-Host ("Location: {0}*" -f $r.Location)                
                $syncOwnerIndex = $count
            }
            else
            {   
                Write-Host ("Location: {0}" -f $r.Location)                
                
            }        
            Write-Host ([string]::Empty)
            $count++        
        } 
        
        # Ask the user to select the replica set the want to remove
        Write-Host -ForegroundColor White "Type the number of the replica set you want to delete and press Enter."
        Write-Host -ForegroundColor White "To quit, type 'q' and press Enter."
        Write-Host -ForegroundColor Yellow "Delete replica set number: " -NoNewline
        $deleteIndex = Read-Host
        
        # Quit
        if("q" -eq $deleteIndex)
            {Return}
            
        [int]$selection = $null
        
        if($true -eq [int]::TryParse($deleteIndex, [ref]$selection))
        {                        
            # Is this the syncOwner
            if($selection -eq $syncOwnerIndex)
            {
                Write-Host -ForegroundColor Red "ERROR: You cannot delete the first replica set in the domain."
                Return
            }


            # Check if it is out of bounds
            if( $true -eq ((0 -gt $selection) -or ($rs.Count -lt $selection)))
            {
                Write-Host -ForegroundColor Red ("ERROR: {0} is an invalid input" -f $deleteIndex)
                Return
            }

            # Prepare for the remove
            $count = 0
            foreach($r in $rs)
            {
                if($true -eq ($count -ne $selection))
                {
                    $replicaSetSettingsValue.Add($r) | Out-Null
                }
                else
                {
                    $vnetName = Convert-SubnetResourceIdToVnetName($r.subnetId)
                    $location = $r.location
                }
                $count++
            }                        
        }
        else 
        {
            Write-Host -ForegroundColor Red ("ERROR: {0} is an invalid input" -f $deleteIndex)
            Return   
        }

    }
    else
    {
        # specific vnet and subnet provided

        # Build subnet ID
        $selectedSubnetId = New-HeuristicSubnetId $azureSubscriptionId `
            $RsResourceGroupName `
            $RsVnetName `
            $RsSubnetName
        
        if([string]::Empty -eq $selectedSubnetId)
        {
            Write-Host -ForegroundColor Red "ERROR: Failed to create a subnetId for the specified subnet."            
            Return
        }

        Write-Host "Subnet to remove"
        Write-Host -ForegroundColor Cyan (" {0}" -f $selectedSubnetId)

        # loop through the exsiting subnets
        $found = $false 
        Write-Host "Searching for subnet in replica sets... " -NoNewline
        foreach($r in $rs)
        {
            if($true -eq ($selectedSubnetId -ne $r.SubnetId))
            {
                $replicaSetSettingsValue.Add($r) | Out-Null
            }
            else
            {
                $vnetName = Convert-SubnetResourceIdToVnetName($r.subnetId)
                $location = $r.location
                $found = $true                
            }
        }

        # Was the subnet found
        if($false -eq $found)
        {
            Write-Host -ForegroundColor Red "[Not Found!]"
            Write-Host -ForegroundColor Red ("ERROR: A replica set in subnet {0} for the virtual network {1} does not exist." -f $RsSubnetName, $RsVnetName)
            Return
        }
        else
            {Write-Host -ForegroundColor Green "[Found!]"}

    }
    
    Write-host ([string]::Empty)        
    $answer = Read-host -Prompt ("Type 'Yes' to confirm the removal of the replica set from the {0} virtual network in the {1} region" -f $vnetName, $location)

    if("Yes" -ne $answer)
    {
        Write-Host "User canceled."
        Return 
    }

    $replicaSetSettings = @{"replicaSets"=$replicaSetSettingsValue}
    
    
    $actionStart = Get-Date

    Write-Host ([string]::Empty)
    Write-Host "Sending the request to Azure."
    Write-Host ("{0}: This action may take up to 30 minutes to complete. Please wait..." -f [DateTime]::Now.ToLongTimeString())
    Set-AzResource -ResourceId $aadds.ResourceId -Properties  $replicaSetSettings -ApiVersion 2020-01-01 -Force -ErrorAction SilentlyContinue | Out-Null
    if($false -eq $?)
    {
        Write-Host -ForegroundColor Red "[Failed!]"
        Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message)
        Return
    }
    else
        {Write-Host -ForegroundColor Green "Removal complete."}

    Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "false"

    $actionStop = Get-Date

    Write-Host "Elapsed Time: " ($actionStop - $actionStart)
 
}
    
# SIG # Begin signature block
# MIInMwYJKoZIhvcNAQcCoIInJDCCJyACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAw/aonZ4Vi+E5T
# m4s99720QdFlqpryiqjjXSL7YBMt2KCCEW8wggiBMIIHaaADAgECAhM2AAABDBla
# ELMo09izAAEAAAEMMA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH
# QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe
# Fw0yMDAyMDkxMzI1MDFaFw0yMTAyMDgxMzI1MDFaMC8xLTArBgNVBAMTJE1pY3Jv
# c29mdCBBenVyZSBEZXBlbmRlbmN5IENvZGUgU2lnbjCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAJL4kx4D2erD4cliqomE3dMX+gvfMz/ovrjRwJqG80Kl
# kGP+kOn35E80o/Ua/SdfQq3gjLNJSJpa6Yn0ph8FOf7U4NT7a8+zrwBTpZ/7llv9
# /jGf037eKxEWsCtMTRfL1dKBOQhn1lHAZvjKdgIgJAFG7ydg1oKsn0wfGBXSgile
# g1IWbTNpR5luLpuHPWRspqDtXCXif/+rjukP5tvDqZmxYP0tQXER4I1eUXiJIXHf
# 7dFZR7VxjZ4BP1rEUU8Gk+BMGpTJTTB21MjwtEjF2U5WAv1KeUpxxlYPKEYGgr2/
# lCXgkoWmPWqSLMbLjcX5uLfMP9j/IW/UnpoaReR1gVsCAwEAAaOCBYIwggV+MCkG
# CSsGAQQBgjcVCgQcMBowDAYKKwYBBAGCN1sDATAKBggrBgEFBQcDAzA8BgkrBgEE
# AYI3FQcELzAtBiUrBgEEAYI3FQiGkOMNhNW0eITxiz6Fm90Wzp0SgWDigi2HkK4D
# AgFkAgEOMIICdgYIKwYBBQUHAQEEggJoMIICZDBiBggrBgEFBQcwAoZWaHR0cDov
# L2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL0NlcnRzL0JZMlBLSUNTQ0EwMS5B
# TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0
# dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUy
# MENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwyLmFt
# ZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAw
# MSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwzLmFtZS5nYmwvYWlhL0JZ
# MlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYI
# KwYBBQUHMAKGRmh0dHA6Ly9jcmw0LmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5B
# TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwga0GCCsGAQUFBzAChoGg
# bGRhcDovLy9DTj1BTUUlMjBDUyUyMENBJTIwMDEsQ049QUlBLENOPVB1YmxpYyUy
# MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9
# QU1FLERDPUdCTD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlm
# aWNhdGlvbkF1dGhvcml0eTAdBgNVHQ4EFgQUkku2i4tvXu/fb2UHKKZiDd81U7Aw
# DgYDVR0PAQH/BAQDAgeAMFAGA1UdEQRJMEekRTBDMSkwJwYDVQQLEyBNaWNyb3Nv
# ZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEWMBQGA1UEBRMNMjM2MTY5KzQ1Nzc5
# NTCCAdQGA1UdHwSCAcswggHHMIIBw6CCAb+gggG7hjxodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpaW5mcmEvQ1JML0FNRSUyMENTJTIwQ0ElMjAwMS5jcmyGLmh0
# dHA6Ly9jcmwxLmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMS5jcmyGLmh0
# dHA6Ly9jcmwyLmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMS5jcmyGLmh0
# dHA6Ly9jcmwzLmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMS5jcmyGLmh0
# dHA6Ly9jcmw0LmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMS5jcmyGgbps
# ZGFwOi8vL0NOPUFNRSUyMENTJTIwQ0ElMjAwMSxDTj1CWTJQS0lDU0NBMDEsQ049
# Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNv
# bmZpZ3VyYXRpb24sREM9QU1FLERDPUdCTD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25M
# aXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwHwYDVR0j
# BBgwFoAUG2aiGfyb66XahI8YmOkQpMN7kr0wHwYDVR0lBBgwFgYKKwYBBAGCN1sD
# AQYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAFdWLRaOg25JZG+Hm01zB/zB
# oSC3MUJ7lWHPIE44xH/7Ek9n0KnzXthnL345WNBcnW3pNbqHGVeLx7SlYJFbsiLi
# vKm3+FUc71F5AQvySUTOpRvHRmEBgzuZo9t6n211l2GQLWdGMGvzrIaeV81wsP2r
# W0G++acIHvczziw0mDTM3UYNeyxI6rFwsZsdfbvzbmsqcZuK9B699sEQoWQO19Fu
# 0sIkj3WPKlATUk9dAAhHkwl2dcPckrvhBvwa9rYPLPAjWsFTZLdRTBubE9ukikdd
# PDTqTM+9FhlPwo7PGMKyBngj9jp4WsfIyDfVfE1W/LgtDa+0SN7mPPNNbW5SKcMw
# ggjmMIIGzqADAgECAhMfAAAAFLTFH8bygL5xAAAAAAAUMA0GCSqGSIb3DQEBCwUA
# MDwxEzARBgoJkiaJk/IsZAEZFgNHQkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxEDAO
# BgNVBAMTB2FtZXJvb3QwHhcNMTYwOTE1MjEzMzAzWhcNMjEwOTE1MjE0MzAzWjBB
# MRMwEQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRUwEwYD
# VQQDEwxBTUUgQ1MgQ0EgMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDVV4EC1vn60PcbgLndN80k3GZh/OGJcq0pDNIbG5q/rrRtNLVUR4MONKcWGyae
# VvoaQ8J5iYInBaBkaz7ehYnzJp3f/9Wg/31tcbxrPNMmZPY8UzXIrFRdQmCLsj3L
# cLiWX8BN8HBsYZFcP7Y92R2VWnEpbN40Q9XBsK3FaNSEevoRzL1Ho7beP7b9FJlK
# B/Nhy0PMNaE1/Q+8Y9+WbfU9KTj6jNxrffv87O7T6doMqDmL/MUeF9IlmSrl088b
# oLzAOt2LAeHobkgasx3ZBeea8R+O2k+oT4bwx5ZuzNpbGXESNAlALo8HCf7xC3hW
# qVzRqbdnd8HDyTNG6c6zwyf/AgMBAAGjggTaMIIE1jAQBgkrBgEEAYI3FQEEAwIB
# ATAjBgkrBgEEAYI3FQIEFgQUkfwzzkKe9pPm4n1U1wgYu7jXcWUwHQYDVR0OBBYE
# FBtmohn8m+ul2oSPGJjpEKTDe5K9MIIBBAYDVR0lBIH8MIH5BgcrBgEFAgMFBggr
# BgEFBQcDAQYIKwYBBQUHAwIGCisGAQQBgjcUAgEGCSsGAQQBgjcVBgYKKwYBBAGC
# NwoDDAYJKwYBBAGCNxUGBggrBgEFBQcDCQYIKwYBBQUIAgIGCisGAQQBgjdAAQEG
# CysGAQQBgjcKAwQBBgorBgEEAYI3CgMEBgkrBgEEAYI3FQUGCisGAQQBgjcUAgIG
# CisGAQQBgjcUAgMGCCsGAQUFBwMDBgorBgEEAYI3WwEBBgorBgEEAYI3WwIBBgor
# BgEEAYI3WwMBBgorBgEEAYI3WwUBBgorBgEEAYI3WwQBBgorBgEEAYI3WwQCMBkG
# CSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjASBgNVHRMBAf8E
# CDAGAQH/AgEAMB8GA1UdIwQYMBaAFCleUV5krjS566ycDaeMdQHRCQsoMIIBaAYD
# VR0fBIIBXzCCAVswggFXoIIBU6CCAU+GI2h0dHA6Ly9jcmwxLmFtZS5nYmwvY3Js
# L2FtZXJvb3QuY3JshjFodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpaW5mcmEv
# Y3JsL2FtZXJvb3QuY3JshiNodHRwOi8vY3JsMi5hbWUuZ2JsL2NybC9hbWVyb290
# LmNybIYjaHR0cDovL2NybDMuYW1lLmdibC9jcmwvYW1lcm9vdC5jcmyGgapsZGFw
# Oi8vL0NOPWFtZXJvb3QsQ049QU1FUk9PVCxDTj1DRFAsQ049UHVibGljJTIwS2V5
# JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1BTUUs
# REM9R0JMP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFz
# cz1jUkxEaXN0cmlidXRpb25Qb2ludDCCAasGCCsGAQUFBwEBBIIBnTCCAZkwNwYI
# KwYBBQUHMAKGK2h0dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0FNRVJPT1RfYW1lcm9v
# dC5jcnQwRwYIKwYBBQUHMAKGO2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2lp
# bmZyYS9jZXJ0cy9BTUVST09UX2FtZXJvb3QuY3J0MDcGCCsGAQUFBzAChitodHRw
# Oi8vY3JsMi5hbWUuZ2JsL2FpYS9BTUVST09UX2FtZXJvb3QuY3J0MDcGCCsGAQUF
# BzAChitodHRwOi8vY3JsMy5hbWUuZ2JsL2FpYS9BTUVST09UX2FtZXJvb3QuY3J0
# MIGiBggrBgEFBQcwAoaBlWxkYXA6Ly8vQ049YW1lcm9vdCxDTj1BSUEsQ049UHVi
# bGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlv
# bixEQz1BTUUsREM9R0JMP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1j
# ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA0GCSqGSIb3DQEBCwUAA4ICAQAot0qGmo8f
# pAFozcIA6pCLygDhZB5ktbdA5c2ZabtQDTXwNARrXJOoRBu4Pk6VHVa78Xbz0OZc
# 1N2xkzgZMoRpl6EiJVoygu8Qm27mHoJPJ9ao9603I4mpHWwaqh3RfCfn8b/NxNhL
# Gfkrc3wp2VwOtkAjJ+rfJoQlgcacD14n9/VGt9smB6j9ECEgJy0443B+mwFdyCJO
# 5OaUP+TQOqiC/MmA+r0Y6QjJf93GTsiQ/Nf+fjzizTMdHggpTnxTcbWg9JCZnk4c
# C+AdoQBKR03kTbQfIm/nM3t275BjTx8j5UhyLqlqAt9cdhpNfdkn8xQz1dT6hTnL
# iowvNOPUkgbQtV+4crzKgHuHaKfJN7tufqHYbw3FnTZopnTFr6f8mehco2xpU8bV
# KhO4i0yxdXmlC0hKGwGqdeoWNjdskyUyEih8xyOK47BEJb6mtn4+hi8TY/4wvuCz
# cvrkZn0F0oXd9JbdO+ak66M9DbevNKV71YbEUnTZ81toX0Ltsbji4PMyhlTg/669
# BoHsoTg4yoC9hh8XLW2/V2lUg3+qHHQf/2g2I4mm5lnf1mJsu30NduyrmrDIeZ0l
# dqKzHAHnfAmyFSNzWLvrGoU9Q0ZvwRlDdoUqXbD0Hju98GL6dTew3S2mcs+17Dgs
# dargsEPm6I1lUE5iixnoEqFKWTX5j/TLUjGCFRowghUWAgEBMFgwQTETMBEGCgmS
# JomT8ixkARkWA0dCTDETMBEGCgmSJomT8ixkARkWA0FNRTEVMBMGA1UEAxMMQU1F
# IENTIENBIDAxAhM2AAABDBlaELMo09izAAEAAAEMMA0GCWCGSAFlAwQCAQUAoIGu
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDsFkRG3brbR9zJUFEya6HeQAYJQeX3
# 4CjcHhpU4Fyy3DBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBpAGMAcgBvAHMAbwBm
# AHShGoAYaHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3DQEBAQUABIIB
# AEJkkFl968N6wMV4HSIv9nuRy3OdvggRUvz5ngr2DKRykswJzDqDhaqj6YaJVFLa
# vCxKL11Lt3cJjbce6UEJdHrAh0WRQY7o12zFxMQdIuawYKbgqL5ydI6gcYqA/Emt
# WK35V90PVj2eRUb2e1BduJfSaFYUZk+gBbbZYM9OA1tb6vxqczM1fNVteiaCWBOU
# ASsRSLsCHiCyba2VZziCSMASV/ym0wXRFTdQgr1BMDAISaQEG3OxqR0F/CxaT0HQ
# LhKDwwivY8bylUb/pgm+ARMQdLVawDXJMglTL7qlfCZCHCQuGaPb+znN4w1rRcYe
# xji+Qj8SZxV9SHHXkBivfTChghLiMIIS3gYKKwYBBAGCNwMDATGCEs4wghLKBgkq
# hkiG9w0BBwKgghK7MIIStwIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBUQYLKoZIhvcN
# AQkQAQSgggFABIIBPDCCATgCAQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEF
# AAQgNr7HUuU1DIxhdwd/akpe9iPxa6DKL0N2tdiW/UP0NP8CBl8YTfLRyRgTMjAy
# MDA3MjgwNDE4MTkuNDk1WjAEgAIB9KCB0KSBzTCByjELMAkGA1UEBhMCVVMxCzAJ
# BgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlv
# bnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046QTI0MC00QjgyLTEz
# MEUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wggg45MIIE
# 8TCCA9mgAwIBAgITMwAAARENAp7u1O0F1AAAAAABETANBgkqhkiG9w0BAQsFADB8
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0xOTEwMjMyMzE5MjBaFw0y
# MTAxMjEyMzE5MjBaMIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsG
# A1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYD
# VQQLEx1UaGFsZXMgVFNTIEVTTjpBMjQwLTRCODItMTMwRTElMCMGA1UEAxMcTWlj
# cm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
# ADCCAQoCggEBAKMS0oITwRtpi4HuDJbl2ZQ3mwGgxYVZpRv55E/fcwwbne+oeRUP
# 588F15tSuFNbsVdwDkecl7Plzc51nbnoL2DDHA7ReyWVkFZMxWhFMN2wxVXqKo2J
# nY9zughI6XeN0OhRIM5rOgnXi9ATdgrvXMxHj/XxXxn05wxI/xqgaXtpe2eRz+6O
# sCQ2PodNqcdsb+uq8qdPRUUVkDA88qIp4gmVmB/XWhqdjtZ1jIYyH0vEU5Y2fHNp
# cHlaRxWj8B5/HKyoPJMj+DpsWdrHVtdV1lf/D62l6kNP8VBGJuFlTv2GJtCZ5SB7
# 9gHwbhcDHCN91kyZ0x9vjguMtHHVEjZ20y8CAwEAAaOCARswggEXMB0GA1UdDgQW
# BBT6cN5BC6h2WMMQw9AMV1DftvkB8jAfBgNVHSMEGDAWgBTVYzpcijGQ80N7fEYb
# xTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5j
# b20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmww
# WgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNV
# HRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IB
# AQCPhmtdRJiu4gYWlF5XhsGRwwdjtn5xGjSnPnm441k99W0bLkKPDAM1EtRV7t7g
# uNw2jEw/bM9EJevUTTck9ziVA+zXVuEWOyVYDd/M9RavvIEy9lfFl0ysaddoDja0
# wbQouHqzMhMzgFwLhD2aIeAdIL0uEc0+z+ACfcJkZE1jCXGxexgkHrSeq+N4fTzr
# 4ok03UbWc8IVHYhisuDi5l3AlhM4e7ZZTDJmWHXIIpE4rYWR17SUFArxE95TurCq
# ZMJzVhK8s03yI4MldX1RejisFlHmu4lNuUNlrNuRhBNjEOvCwiF76l16zqRu8leX
# LphjiFTBE44jQeDgdBTk8UaDMIIGcTCCBFmgAwIBAgIKYQmBKgAAAAAAAjANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0NjU1WjB8MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
# VGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
# ggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5m
# K1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/xYIiEVEMM1024OAizQt2TrNZzMFcm
# gqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5
# hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/Vm
# wAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaICDXoeByw6ZnNPOcvRLqn9NxkvaQB
# wSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOCAeYwggHiMBAGCSsGAQQBgjcVAQQD
# AgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIE
# DB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
# HSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVo
# dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29D
# ZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAC
# hj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1
# dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMw
# gYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9j
# cy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8A
# UABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQEL
# BQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z66bM9TG+zwXiqf76V20ZMLPCxWbJ
# at/15/B4vceoniXj+bzta1RXCCtRgkQS+7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1
# mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIArzgPF/UveYFl2am1a+THzvbKegBv
# SzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWvL/625Y4zu2JfmttXQOnxzplmkIz/
# amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/fZZqkHimbdLhnPkd/DjYlPTGpQqW
# hqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua
# 2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqwUB5vvfHhAN/nMQekkzr3ZUd46Pio
# SKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqH
# czsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLixqduWsqdCosnPGUFN4Ib5KpqjEWYw
# 07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh0sVV42neV8HR3jDA/czmTfsNv11P
# 6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4Iuto229Nfj950iEkSoYICyzCCAjQC
# AQEwgfihgdCkgc0wgcoxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYD
# VQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNV
# BAsTHVRoYWxlcyBUU1MgRVNOOkEyNDAtNEI4Mi0xMzBFMSUwIwYDVQQDExxNaWNy
# b3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBB7ubtvHon
# z32bk4mWhhsbX590x6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy
# MDEwMA0GCSqGSIb3DQEBBQUAAgUA4soMkjAiGA8yMDIwMDcyODEwMzE0NloYDzIw
# MjAwNzI5MTAzMTQ2WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDiygySAgEAMAcC
# AQACAgGVMAcCAQACAhGoMAoCBQDiy14SAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwG
# CisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEF
# BQADgYEAONJ6xjFgX29BJ6zT4NrwSN9dRTkUPgrpRQTGc/uDtZwNV/KIraF/y0eb
# laXsEEUHkvw2ZmQc+gUdl6iw02vBc0FQunYFrNU7J7qnDRJOw+nq/TMsvqN/Lb7p
# I39Gep+wA4Me2nlOYzykj/FjMT27ZG60PeLS2SRgSAaFniJpFCcxggMNMIIDCQIB
# ATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAARENAp7u1O0F
# 1AAAAAABETANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3
# DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCAolkE1QAZYzb4doWQ/BacM0OmuviLnI8/x
# HPfIuVvAKzCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EII4+Eq+iBR4aQaFr
# G0Jm439S0PVPgP7IPFw7BXPpKLZbMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh
# bXAgUENBIDIwMTACEzMAAAERDQKe7tTtBdQAAAAAAREwIgQgLPOUPg3tA8GPEJLC
# Y9NIYHDCOBFDuStSrrx9OtyngpcwDQYJKoZIhvcNAQELBQAEggEAJo2f18Lz0WNM
# KVhyMvcNC0P5YEMwnyCI9JfDXyUpryFr/1iuDeItT7q1bFQdSgYA6R1Zn+6WLA/7
# bYELCSme28EMFygPILGatBRl08D/pZRSTXWqsS4kYDpjgwkNb3X0/6UYc34TGeFs
# Q60qELmtLss4ux79QfmEnBzTl8qOAmSkrRBaHZ0IYJ8v8FCo7Q+sDs4qoXVhlN8K
# I3AWkZuxM46r6pkjaWAW3nuLjQL1+sFPEqAvgSgZ4nidPJB+23WY2eF74Vno67T7
# B6HMiuI2pso6RoPbvPGo8sZJUZiOpWfZ7/YxZC3mFQ+fTRt0nMt6+Qig0sbaZqX1
# Bq1ZSTnULA==
# SIG # End signature block