ozo-ad-manage-directory-objects.ps1

#Requires -Modules ImportExcel,OZO,OZOLogger -Version 5.1

<#PSScriptInfo
    .VERSION 0.0.1
    .GUID 87eaa283-5e8b-4265-a025-ce1f5791491b
    .AUTHOR Andy Lievertz <alievertz@onezeroone.dev>
    .COMPANYNAME One Zero One
    .COPYRIGHT This script is released under the terms of the GNU General Public License ("GPL") version 2.0.
    .TAGS
    .LICENSEURI https://github.com/onezeroone-dev/OZO-AD-Manage-Directory-Objects/blob/main/LICENSE
    .PROJECTURI https://github.com/onezeroone-dev/OZO-AD-Manage-Directory-Objects
    .ICONURI
    .EXTERNALMODULEDEPENDENCIES
    .REQUIREDSCRIPTS
    .EXTERNALSCRIPTDEPENDENCIES
    .RELEASENOTES https://github.com/onezeroone-dev/OZO-AD-Manage-Directory-Objects/blob/main/CHANGELOG.md
#>


<#
    .SYNOPSIS
    See description.
    .DESCRIPTION
    Creates Active Directory users and groups based on a JSON configuration file.
    .PARAMETER Configuration
    Path to the JSON configuration file. Defaults to "ozo-ad-manage-directory-objects.json" in the same directory as the script.
    .PARAMETER OutDir
    Directory for the Excel report. Defaults to the current directory.
    .LINK
    https://github.com/onezeroone-dev/OZO-AD-Manage-Directory-Objects/blob/main/README.md
#>


# PARAMETERS
[CmdletBinding(SupportsShouldProcess = $true)] Param (
    [Parameter(Mandatory=$false,HelpMessage="Path to the JSON configuration file")][String]$Configuration = (Join-Path -Path $PSScriptRoot -ChildPath "ozo-ad-manage-directory-objects.json"),
    [Parameter(Mandatory=$false,HelpMessage="Path for the Excel report")][String]$OutDir = (Get-Location)
)

# CLASSES
Class OZOMain {
    # PROPERTIES: Strings
    [String] $jsonPath  = $null
    [String] $excelPath = $null
    # PROPERTIES: PSCustomObjects
    [PSCustomObject] $adDomain  = $null
    [PSCustomObject] $Json      = $null
    [PSCustomObject] $ozoLogger = $null
    # PROPERTIES: PSCustomObject Lists
    [System.Collections.Generic.List[PSCustomObject]] $adOUs       = @()
    [System.Collections.Generic.List[PSCustomObject]] $adComputers = @()
    [System.Collections.Generic.List[PSCustomObject]] $adContacts  = @()
    [System.Collections.Generic.List[PSCustomObject]] $adGroups    = @()
    [System.Collections.Generic.List[PSCustomObject]] $adGPOs      = @()
    [System.Collections.Generic.List[PSCustomObject]] $adUsers     = @()
    # METHODS: Constructor method
    OZOMain($Configuration,$OutDir) {
        # Create a logger object
        $this.ozoLogger = (New-OZOLogger)
        # Log a process start message
        $this.ozoLogger.Write("Starting process.","Information")
        # Determine if the configuation is valid
        If (($this.ValidateConfiguration($Configuration) -And $this.ValidateEnvironment($OutDir)) -eq $true) {
            # Iterate through the JSON OU objects
            ForEach ($adOU in $this.Json.ADOrganizationalUnits) {
                # Add an OZOADOrganizationalUnit object to the adOUs list
                $this.adOUs.Add(([OZOADOU]::new($adOU)))
            }
            # Iterate through the JSON Computer objects
            ForEach ($adComputer in $this.Json.ADComputers) {
                # Add an OZOADComputer object to the adComputers list
                $this.adComputers.Add(([OZOADComputer]::new($adComputer)))
            }
            # Iterate through the JSON Contacts objects
            ForEach ($adContact in $this.Json.ADContacts) {
                # Add an OZOADOContact object to the adContacts list
                $this.adContacts.Add(([OZOADContact]::new($adContact)))
            }
            # Iterate through the JSON Group objects
            ForEach ($adGroup in $this.Json.ADGroups) {
                # Add an OZOADGroup object to the adGroups list
                $this.adGroups.Add(([OZOADGroup]::new($adGroup)))
            }
            # Iterate through the JSON Group Policy objects
            ForEach ($adGPO in $this.Json.ADGroupPolicyObjects) {
                # Add an OZOADGroupPolicyObject object to the adGPOs list
                $this.adGPOs.Add(([OZOADGPO]::new($adGPO)))
            }
            # Iterate through the JSON User objects
            ForEach($adUser in $this.Json.ADUsers) {
                # Add an OZOADUser object to the adUsers list
                $this.adUsers.Add(([OZOADUser]::new($adUser,($this.adDomain).Name)))
            }
            # Manage default objects
            $this.ManageDefaultObjects()
        }
        # Report
        $this.Report()
        # Log a process end message
        $this.ozoLogger.Write(("Process complete."),"Information")
    }
    # METHODS: JSON validation method
    Hidden [Boolean] ValidateConfiguration($Configuration) {
        # Control variable
        [Boolean] $Return = $true
        # Determine if the JSON path is valid
        If ([Boolean](Test-Path -Path $Configuration -ErrorAction SilentlyContinue) -eq $true) {
            # JSON path is valid; try to get the JSON content
            Try {
                $this.Json = (Get-Content $Configuration -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop)
                # Success
            } Catch {
                # Failure
                $this.ozoLogger.Write(("Invalid JSON in " + $Configuration + "."),"Error")
                $Return = $false
            }
        } Else {
            # JSON path is invalid
            $this.ozoLogger.Write(("Could not read configuration file " + $Configuration + "."),"Error")
            $Return = $false
        }
        # Return
        return $Return
    }
    # METHODS: Environment validation method
    Hidden [Boolean] ValidateEnvironment($OutDir) {
        # Control variable
        [Boolean] $Return = $true
        # Determine if the outDir exists
        If ([Boolean](Test-Path -Path $OutDir -ErrorAction SilentlyContinue) -eq $true) {
            # Output directory exists; set the Excel path
            $this.excelPath = (Join-Path -Path $OutDir -ChildPath ((Get-OZO8601Date -Time) + "-ozo-ad-manage-directory-objects.xlsx"))
        } Else {
            # Output directory does not exist; report
            $this.ozoLogger.Write(("Output directory is invalid or inaccessible."),"Error")
            $Return = $false
        }
        # Try to get the domain information
        Try {
            $this.adDomain = Get-ADDomain -ErrorAction Stop
            # Success
        } Catch {
            # Failure
            $this.ozoLogger.Write("Failed to get AD domain information.")
            $Return = $false
        }
        # Return
        return $Return
    }
    # METHODS: Manage default objects method
    Hidden [Void] ManageDefaultObjects() {
        # Iterate over the objects in the Users container
        ForEach ($adObject in (Get-ADObject -Filter * -SearchBase $this.adDomain.UsersContainer)) {
            # Switch on object class
            Switch($adObject.ObjectClass) {
                "user" {
                    # Object class is user; move object to default users OU
                    Move-ADObject -Identity $adObject.DistinguishedName -TargetPath $this.Json.ADDefaultObjectsOUs.Users
                }
                "group" {
                    # Object class is group; move object to default groups OU
                    Move-ADObject -Identity $adObject.DistinguishedName -TargetPath $this.Json.ADDefaultObjectsOUs.Groups
                }
            }
        }
    }
    # METHODS: Report method
    Hidden [Void] Report() {
        # Determine that at least one object was processed
        If (($this.adComputers + $this.adContacts + $this.adGroups + $this.adGPOs + $this.adOUs + $this.adUsers).Count -gt 0) {
            # At least one object was processed; Produce Excel output
            $this.adComputers | Select-Object -Property @{Name="Computer Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "Computers" -Path $this.excelPath
            $this.adContacts | Select-Object -Property @{Name="Contact Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "Contacts" -Path $this.excelPath
            $this.adGroups | Select-Object -Property @{Name="Group Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "Groups" -Path $this.excelPath
            $this.adGPOs | Select-Object -Property @{Name="GPO Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "GPOs" -Path $this.excelPath
            $this.adOUs | Select-Object -Property @{Name="OU";Expression={$_.adOUDN}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "OUs" -Path $this.excelPath
            $this.adUsers | Select-Object -Property @{Name="User Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "Users" -Path $this.excelPath
            # Determine if session is interactive
            If ([Environment]::UserInteractive -eq $true) {
                # Session is interactive; produce output for the operator
                $this.adComputers | Select-Object -Property @{Name="Computer Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
                $this.adContacts | Select-Object -Property @{Name="Contact Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
                $this.adGroups | Select-Object -Property @{Name="Group Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
                $this.adGPOs | Select-Object -Property @{Name="GPO Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
                $this.adOUs | Select-Object -Property @{Name="OU";Expression={$_.adOUDN}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
                $this.adUsers | Select-Object -Property @{Name="User Name";Expression={$_.Name}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Format-Table | Out-Host
            }
            # Determine if Excel was created
            If ([Boolean](Test-Path -Path $this.excelPath -ErrorAction SilentlyContinue) -eq $true) {
                # Excel was created
                $this.ozoLogger.Write(("For additional information, please see " + $this.excelPath + "."),"Information")
            } Else {
                $this.ozoLogger.Write("No Excel results report generated.","Warning")
            }
        } Else {
            # No objects were processed
            $this.ozoLogger.Write("No objects were processed.","Warning")
        }
    }
}

Class OZOADComputer {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $Name = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADComputer($adComputer) {
        # Set properties
        $this.Name = $adComputer.ComputerName
        # Define parameters
        $Parameters = @{
            DisplayName = $adComputer.ComputerName
            Enabled = $true
            Name = $adComputer.ComputerName
            Path = $adComputer.Path
        }
        # Determine if the computer does not already exist
        If ([Boolean](Get-ADComputer -Identity $adComputer.Name -ErrorAction SilentlyContinue) -eq $false) {
            # Computer object does not already exist; try to create it
            Try {
                New-ADComputer @Parameters -ErrorAction Stop
                # Success
            } Catch {
                # Failure
                $this.Messages.Add(("Computer creation failed with error " + $_))
                $this.Success = $false
            }
        } Else {
            # Computer object already exists; skip
            $this.Messages.Add("Computer already exists; skipping")
        }
    }
}

Class OZOADContact {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $Name = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADContact($adContact) {
        # Local variables
        $this.Name = ($adContact.FirstName + " " + $adContact.LastName)
        # Define parameters
        $Parameters = @{
            Name = $this.Name
            Type = "contact"
            Path = $adContact.Path
            OtherAttributes = @{
                DisplayName = $this.Name
                Mail = $adContact.EmailAddress
                TelephoneNumber = $adContact.TelephoneNumber
            }
        }
        # Determine if the contact does not already exist
        If ([Boolean](Get-ADObject -Filter { Name -eq $this.Name -And ObjectClass -eq "contact" } -ErrorAction SilentlyContinue) -eq $false) {
            # Contact does not already exist; try to create it
            Try {
                New-ADObject @Parameters -ErrorAction Stop
                # Success
            } Catch {
                # Failure
                $this.Messages.Add(("Contact creation failed with error " + $_))
                $this.Success = $false
            }
        } Else {
            # Contact exists; skip
            $this.Messages.Add("Contact already exists; skipping")
        }
    }
}

Class OZOADGroup {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $Name = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADGroup($adGroup) {
        # Set properties
        $this.Name = $adGroup.Name
        # Define parameters
        $Parameters = @{
            Name = $adGroup.Name
            Path = $adGroup.Path
            GroupScope = $adGroup.Scope
        }
        # Try to get the group
        Try {
            Get-ADGroup -Identity $adGroup.Name -ErrorAction Stop | Out-Null
            # Success
        } Catch {
            # Failure; try to create the group
            Try {
                New-ADGroup @Parameters -ErrorAction Stop
                # Success; iterate over parent groups
                ForEach ($Group in $adGroup.Groups) {
                    # Try to add group to parent group
                    Try {
                        Add-ADGroupMember -Identity $Group -Members $adGroup.Name -ErrorAction Stop
                        # Success
                    } Catch {
                        # Failure
                        $this.Messages.Add(("Adding to parent group " + $Group + " failed with " + $_))
                        $this.Success = $false
                    }
                }
            } Catch {
                # Failure
                $this.Messages.Add(("Group creation failed with error " + $_))
                $this.Success = $false
            }
        }
    }
}

Class OZOADGPO {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $Name = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADGPO($adGPO) {
        # Set properties
        $this.Name = $adGPO.Name
        # Determine if the GPO does not already exist
        If ([Boolean](Get-GPO -Name $adGPO.Name -ErrorAction SilentlyContinue) -eq $false) {
            # GPO does not already exist; try to create it
            Try {
                New-GPO -Name $adGPO.Name -ErrorAction Stop
                # Success; iterate over the Links
                ForEach ($OU in $adGPO.Links) {
                    # Try to link GPO to OU
                    Try {
                        New-GPLink -Name $adGPO.Name -Target $OU -ErrorAction Stop
                        # Success
                    } Catch {
                        # Failure
                        $this.Messages.Add(("Linking GPO to " + $OU + " failed with error " + $_))
                    }
                }
            } Catch {
                # Failure
                $this.Messages.Add(("Group Policy Object creation failed with error " + $_))
                $this.Success = $false
            }
        } Else {
            # GPO already exists
            $this.Messages.Add("Group Policy Object already exists; skipping")
        }
    }
}

Class OZOADOU {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $adOUDN = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADOU($adOU) {
        # Generate DN
        [String] $this.adOUDN = ("OU=" + $adOU.Name + "," + $adOU.Path)
        # Define parameters
        $Parameters = @{
            Name = $adOU.Name
            Path = $adOU.Path
        }
        # Try to get the Organizational Unit
        Try {
            Get-ADOrganizationalUnit -Identity $this.adOUDN -ErrorAction Stop | Out-Null
            # Success
        } Catch {
            # Failure; create the OU
            Try {
                New-ADOrganizationalUnit @Parameters -ErrorAction Stop
                # Success
            } Catch {
                # Failure
                $this.Messages.Add(("Organizational Unit creation failed with error " + $_))
                $this.Success = $false
            }
            
        }
    }
}

Class OZOADUser {
    # PROPERTIES: Booleans
    [Boolean] $Success = $true
    # PROPERTIES: Strings
    [String] $Name = $null
    # PROPERTIES: String lists
    [System.Collections.Generic.List[String]] $Messages = @()
    # METHODS: Constructor method
    OZOADUser($adUser,$adDomainName) {
        # Set properties
        $this.Name = ($adUser.GivenName + " " + $adUser.Surname)
        # Define parameters
        $Parameters = @{
            Name = $this.Name
            SamAccountName = $adUser.SamAccountName
            UserPrincipalName = ($adUser.SamAccountName + "@" + $adDomainName)
            AccountPassword = (ConvertTo-SecureString -AsPlainText -String $adUser.Password -Force)
            Enabled = $true
            Path = $adUser.Path
        }
        # Try to get the user
        Try {
            Get-ADUser -Identity $adUser.SamAccountName -ErrorAction Stop | Out-Null
            # Success
        } Catch {
            # Failure; try to create the user
            Try {
                New-ADUser @Parameters -ErrorAction Stop
                # Success; iterate through the groups
                ForEach ($adGroup in $adUser.Groups) {
                    # Try to create the group
                    Try {
                        Add-AdGroupMember -Identity $adGroup -Members $adUser.SamAccountName -ErrorAction Stop
                    } Catch {
                        # Failure
                        $this.Messages.Add(("Adding user to the " + $adGroup + " group failed with error " + $_))
                    }
                }
            } Catch {
                # Failure
                $this.Messages.Add(("User creation failed with error " + $_))
                $this.Success = $false
            }
        }
    }
}

# Create a Main object
[OZOMain]::new($Configuration,$OutDir) | Out-Null

# SIG # Begin signature block
# MIIvsAYJKoZIhvcNAQcCoIIvoTCCL50CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBJB3DZUCQmDMLT
# LPmJhPxoOKcgiKjgCpYZcEMshXBCAaCCEgUwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M
# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5
# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp
# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G
# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI
# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV
# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3
# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw
# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm
# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe
# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4
# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM
# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY
# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU
# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV
# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG
# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG
# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl
# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0
# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh
# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd
# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj
# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc
# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO
# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs
# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7
# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J
# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH
# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2
# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/
# L9Uo2bC5a4CH2RwwggZwMIIE2KADAgECAhAbV4ef7ZvUwZ6AKRT0hWSAMA0GCSqG
# SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0
# ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw
# HhcNMjYwOTE0MDAwMDAwWhcNMjcwOTE0MjM1OTU5WjBiMQswCQYDVQQGEwJVUzER
# MA8GA1UECAwIQ29sb3JhZG8xHzAdBgNVBAoMFkxpZXZlcnR6IEFuZHJldyBIdWJl
# cnQxHzAdBgNVBAMMFkxpZXZlcnR6IEFuZHJldyBIdWJlcnQwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQCZl/Kqmb1yMMbn0868VlBqxo7LGu/SDy7bO3wz
# D6jMoxzh2UT4iFxNnIEpHJq9SzxkhNgy60Lhzr0kGxBXypLJVGKP3JpS9inmF3zn
# e/DWJcOFkQPkwYAsqEoJ6xt/klQlJqnwaN7AJUwUIgZ/72j37//UcWxltCMxnwT2
# wVUQ357c3GOafCKfBMUN9dEgUhwxt4x5GZ6Re/WSGKlh+eFtP1wNBsBXoT6Hme5E
# u2L5vTYl0fmKVAsTGJ9k7eHvLE7IUWXOD6NI548uxFQ2FeISOdCRt0WmYmpWgi6S
# j1Aoh1zLhsMaLgUPP+BXcOy0cO3zDJ+SZky+S4AB37Y0UBqy9hNvX0WbfQh3BF+2
# uWYGxHYc3FtefKKAbhQGNo9EO4pB0SBh/19a/EbbUpv67CRlO8PmGf8hEk6ic8O6
# 28OjkFi5ByIB7y/XKPKCZmeS/TWDrkyMpu8h9NGqHyWONE5oxpqCYMm3a0L92kfd
# zY5e6vSLDuZZjlANRUm3VLnbxZcD8znUvaDbR+ALdJeSZryev8NVMnfOzwZM6vKz
# fTPbYpFRBo0owFluKK85CKeZ8z+NyKQfvWh5gYXZw0JFZwdE4SE46fnNLJ3z9loF
# Qly+7Dn2zUd/+CxwlRgkuEO1ng6EJ1OAAeA7PixyZob0gjg7ob7YzSK2v4AV/QdQ
# oXa04QIDAQABo4IBrjCCAaowHwYDVR0jBBgwFoAUDyrLIIcouOxvSK4rVKYpqhek
# zQwwHQYDVR0OBBYEFMiE5GpeP6V7hsDSdHBbSjojZscBMA4GA1UdDwEB/wQEAwIH
# gDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMEoGA1UdIARDMEEw
# NQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5j
# b20vQ1BTMAgGBmeBDAEEATBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLnNl
# Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNybDB5Bggr
# BgEFBQcBAQRtMGswRAYIKwYBBQUHMAKGOGh0dHA6Ly9jcnQuc2VjdGlnby5jb20v
# U2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3J0MCMGCCsGAQUFBzABhhdo
# dHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAjBgNVHREEHDAagRhhbGlldmVydHpAb25l
# emVyb29uZS5kZXYwDQYJKoZIhvcNAQEMBQADggGBACvVVz+HNOH8p+CBcwmrYBVx
# mlWNkTz84gmJZ/57FF5XK4kHeo6+QFalQkBSkiDheZa13+FdwUYf1zcJu5hfymkZ
# 9zmBhLlIkdluT1llv9GKr/tQaJFd2NXoLiJ7ysqRDbu47U1RR7XGU42HZHLUHa00
# Ha8KDHKYeRcCBMhltjpBK4Hw5daTzT+5fLhMHaOy3ZuWn4Fgx8zEcH1/cdEqnWNn
# NxxCWbKcp4sRI0v9uStoUYGpvX8LkYtMUUuWPr7tZAAZiPws6ctOrdROmdEwfyah
# IMt2drMfTXZVPpL/5okl37qOYhzV+u6vEvbc3xeAicAgsgOYkvvx5L2iUyFfGdLb
# JN4ioPTCKcvN7oXFPwHfyGqwBxARyJy3so2OAFvY4AGY/9DwQVE8KZuplrkktC7Y
# MzjB9SjEtvqnyW+h0fHd3H85B8GJiL8slRmIb5f+jJDvmu5RgoaoaMAYeX/V4HXY
# gpSD92Hq5AwUjjUvj1WPk+AagPBupA+J4OM2S6eO0DGCHQEwghz9AgEBMGgwVDEL
# MAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UEAxMi
# U2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENBIFIzNgIQG1eHn+2b1MGegCkU
# 9IVkgDANBglghkgBZQMEAgEFAKB8MBAGCisGAQQBgjcCAQwxAjAAMBkGCSqGSIb3
# DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV
# MC8GCSqGSIb3DQEJBDEiBCAb8lkd0nm2Yy6DnlmQakfzFGGWD0KopfQml+UZhpma
# IzANBgkqhkiG9w0BAQEFAASCAgBV32FzdUy8OAl77Af1jtqkhORG+8IE6KNgLAqX
# 06OJyV9WmI68Dbn6fJe6rAHXdoxEoYePCW/yGf49J2EmvkXuYhUIdYaFaWGzGtNe
# DcqduUAOCheQke3ASqnarIvTLncjIfQ2q81r8ZUOSwYrPDS1EIgniuO13T9rkeOo
# siIa9yImGIrDGAC9sRM4cp8X1SvmB9YK29S+ScC6zZec+0mjiDDrtOMyIm88rtfK
# PwyAGu1plYMU7hr7K1MsnjxDG1nMYAyKU6wMSTBlI4SEJtSHeFHNzU/L5cny2UkV
# YBWb7xywKwOsn0NHXibjaXc7QUk7mS6fKg3YdfLol4gWNPpyOWReWpNa2IzErx5e
# 7z7Ul1C7KtjJriI3m8/e1YODm//z93prbDCvsv2zLknI4OmQlpFiHZXWRlMWy++T
# S1DUTJitHKIX/TtncUxgTljGBnYc/lweEWTXlJs6sXjEskdWGCvZ6JR/p8osDWqA
# Uv1lWyg7oRGpmqxcS422H67jMIvotIGuHgVGGY+deqrpSIvn8msYgXd7o99USJWD
# OcFx/AlLAmaPOvK/JnFj5PT7OV5nPCCkzfrv9gcliGqR/2os/rUA0oyXJGmTkrcn
# dfTMF+yuvn5XMGT1zKzH5ZTJQ7YwZ2q2RRRTyJBe5myQqfcvTTgFMALt+V53Nkwi
# DuF7q6GCGewwghnoBgorBgEEAYI3AwMBMYIZ2DCCGdQGCSqGSIb3DQEHAqCCGcUw
# ghnBAgEDMQ8wDQYJYIZIAWUDBAICBQAwgfgGCyqGSIb3DQEJEAEEoIHoBIHlMIHi
# AgEBBgorBgEEAbIxAgEBMDEwDQYJYIZIAWUDBAIBBQAEINpYPU4truDrbk/GSHxV
# n0lBh2VGAcraWrs1eSI5iy4zAhUAqu/b1pwHvyTTtkms4TmLsX+ykRIYDzIwMjYw
# OTI4MDc1NDE2WqB2pHQwcjELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkdyZWF0ZXIg
# TG9uZG9uMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxMDAuBgNVBAMTJ1NlY3Rp
# Z28gUHVibGljIFRpbWUgU3RhbXBpbmcgU2lnbmVyIFIzN6CCFBcwggbiMIIEyqAD
# AgECAhEA507yVbBQT/rbpt/3/IujFTANBgkqhkiG9w0BAQwFADBVMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDEyNTZWN0aWdv
# IFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0MTAeFw0yNjAzMjUwMDAwMDBaFw0z
# NzA2MjQyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRcwFQYDVQQIEw5HcmVhdGVyIExv
# bmRvbjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTAwLgYDVQQDEydTZWN0aWdv
# IFB1YmxpYyBUaW1lIFN0YW1waW5nIFNpZ25lciBSMzcwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCy/8NtS9xQ2UUtBRF32bj7VK3n4m50Uqjk/zTciSzi
# YV40H1LKah0/oEklYG42E4VCP3DvsBUB6DmpCkDZ0jCnZBPIEevaH15ZJOQwFWP2
# ZXr5YjlJpb68Nlbs+ElNvKx32/1YHde3qqUSLybjulxPLz6T85+HOIqK7M1Bep8L
# spyhEP/q6nw5kGxTSrGvufmeH+JF8CnVBcVMFA40FlIYh0cDJVFhhfTfdWgLy/vW
# uLMQoKkf3s/FvByf16r0rtbyHm/iemwxSioJL9zyZDDKUNAbHXl0dhXo2VxUV2Nc
# PXWXuoKsjL+6cfk6Vm2DHnxAlFdFsaBDIF1JOkSnC6PeLlBznZn2buF3vIIYJcq6
# N/zeFRCk4/HXDz7zgRsRRMdUB+rhyk5FoZaBjw0nLq3GZ3fClLUx5es5pUAxzNOD
# MBn7JkFYip2BAGBPER5eV0ROhk6tGTG+fUiMiV+vgjg1YnP5FvnYWyEtWeQD/B2h
# p3vz0RvtdkM0p3igyadzrfpOBq5ppVk/YsuhTQkP99ivneHAGfi5e7lmxJ+meoBP
# rRLuzMmb81rzzbESjJHMsn5RVtc6Ucs7rcMqQC13PUIO7BbGBETV2ufCmV6lPTp3
# P7XJOvmnUCRTPbVvMTpxP/z+SOHg4/OCBhiqs4FA9+4oQvlkk9w32NGASli9GWrm
# 5wIDAQABo4IBjjCCAYowHwYDVR0jBBgwFoAUOnSlDGfGQlDC/bX8x7spNIL0erkw
# HQYDVR0OBBYEFGEQ6XoSr1HEhdTyz6R0D1DNIK/4MA4GA1UdDwEB/wQEAwIGwDAM
# BgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMEoGA1UdIARDMEEw
# CAYGZ4EMAQQCMDUGDCsGAQQBsjEBAgEDCDAlMCMGCCsGAQUFBwIBFhdodHRwczov
# L3NlY3RpZ28uY29tL0NQUzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLnNl
# Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVI0MS5jcmwwegYI
# KwYBBQUHAQEEbjBsMEUGCCsGAQUFBzAChjlodHRwOi8vY3J0LnNlY3RpZ28uY29t
# L1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVI0MS5jcnQwIwYIKwYBBQUHMAGG
# F2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAD6j2N
# 0azN+hl6k6bKB5/U6VuSOs93ZBb3Pczy9VtBIKu4947Z5GwL0aFngIxl+GSuLFrJ
# gPruBCRvKJEJsm7kv+LQ1COVCEG9tZ+IRtr4ocUoa53lgdFaENlS0N4wgkZkbQEP
# v+x+1lSjYh+T4JeL9mUznT7Erc6Sp5dWLka5sMP/m3GZi6oJPdPcsCKWagH7m2H2
# xDGIyHJC5PdH9phvi/KmhkktiSVTNNqVeV5bWdX2zhRE6UTfz0IcMoCL996lFIyd
# XxOCE4MNDHDM0as4lnTiT/KHMccO6l8c9TnUVgmpci9ar1IABZ2U1XUkYjGGSn9M
# C3EHDP9V39VuBVvZ33/BEV/EWSRrf07T7jFplKX+gQr/UOqPGMlE7ZJ72UaUkNJy
# 7bVl3bcLKzdpjIHzLkf/4MVa1V7w8wqCv5W4gOnRGTlud5UMARbRM8BPxR/CXYXo
# MmIOD8pmTk2axgRL4LG8XtuchISdCHRmtacAmLGq5XSYSVTHTXADlO48iDKh3HM2
# r98LSF6f0sG12d8V9Jn7C3wDUieOxuKj4MdWrW+hiJU2kF87v6eH00HgCFFc2V0+
# CvfOCMn7juzS41jLaINcBlKWQ/fKb/uDLfWOW73z1I2lFY7Xj8tQ1XYtK5eREjWI
# tM8jpl1cbQOc88btR+0XS2TmboE/141+va2PWzCCBqcwggSPoAMCAQICEQCQrAhy
# IP3Fp8RrXMcN9z0GMA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRp
# bWUgU3RhbXBpbmcgUm9vdCBSNDYwHhcNMjYwMzI1MDAwMDAwWhcNNDEwMzI0MjM1
# OTU5WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww
# KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0MTCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7kSqIBrYIcYvlmLVuaA8zw1RfB
# hkn4G1CoemzjcYtML6yNUvKmwGH7y6/5MuSC1UYP/+9KYDSqvMQt/1hEKHYxMAD9
# oZpBkoaDQFEKbOJHelsKe+BaO0ZcENTKfePcraVkA7wrGAW2XHA5gQCQv4IKori/
# 3PNOXxnDMOk8yIMgVrlMeTxqfWJ4XkjT1xc2s9DD7URHWWJOFobTPoWs6mrDFlaY
# 9FlAHDYTfbzvxQHVsvRmn3W+5ZmCwyk02I8KgGPT/UX4sTz41GiR+ppwUjQXa1+2
# tEHZbsdAKUtH3OPEVtZvlt7atx4h83IdRR8oYi8wjY3OjFKXFecWpQbzzsPxbUKP
# wMWiTrzwkrFa8dH/1pDKRJt371W62PfqKPayCr/XbnBOlRn8CALSmHnRtGzuAWtT
# JpcT3BKw6oy8IIL6wSbu938F6ZIbRNIc1dKbIJtr4ULN6R5ZfTdNEhwXctqp3RHD
# bg4fuOl6LjNoaFwjud92EEDhzxFJzE1jqN4csceZIwxOT1aqfsfh0uFQE/lgTBuB
# s3i6/WL2W1OceWLy3XEdXRK1f0EWCuea6dNfX2RRdjUfk5EltFnJkN2+bWhnK14O
# PRKcyjOv5hKZ0iV4NRNd1+hjtva1rPyzb5Bs7EvFxqEQhgZbOq7qH3nm0rBwA0dx
# niBOYCFPdu246JCxAgMBAAGjggFuMIIBajAfBgNVHSMEGDAWgBT2d2rdP/0BE/8W
# oWyCAi/QCj0UJTAdBgNVHQ4EFgQUOnSlDGfGQlDC/bX8x7spNIL0erkwDgYDVR0P
# AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUH
# AwgwIwYDVR0gBBwwGjAIBgZngQwBBAIwDgYMKwYBBAGyMQECAQMIMEwGA1UdHwRF
# MEMwQaA/oD2GO2h0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1Rp
# bWVTdGFtcGluZ1Jvb3RSNDYuY3JsMHwGCCsGAQUFBwEBBHAwbjBHBggrBgEFBQcw
# AoY7aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1w
# aW5nUm9vdFI0Ni5wN2MwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28u
# Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQAy3lJHZvGeA2b43yhzoarvobHVzbfl+Rfu
# PDwej0wCQkYAN6scTt2GwFe22qbOCv/tllqFlLKQZE+E9jVyuPTbyQHwrM7R0oLa
# pAEDC1+CowsqSRf/ptira5Pfd4PoHICnb9coPQtyZmHSQp5y9IGvqWf1qNfq7V2f
# HZ8DvEQrLUzeoGF9BJRYu2OzacW3QQtUum3NOVf0gPRwv6I4991uhncJ6VP4lcpU
# pHZKB7R3hiIUC09mR9KjzPVnXHvL9n2bAwiUECfK5Zezhiw27F2tgi39DETfU8M4
# n0N6xLgFzsf05M5GURX8C9+IX9V6kpmmKtrUzMti4LD66gtmf+mSm934K81NL6YQ
# eMEk1rpYrWPypcW76Mir6wb1AgseLIHqn/GkeuQm7zOTDf3f5WoX14qVNjZWNHF3
# JxkutV6ZnhinfCLfdv5bnwKWUfceqOajCVntI6uCbHxjBg6SCsexc5AfIGno7gVF
# vwifT4XONPsSUaJ71XsJ+EvciVUVnjOO4qxm0fWJTd8a7jP8mc4ZPqwJvQFtOp7+
# 6G+kUJAF0fnE8YgD8uttBReNTa1YmAeFMiqc38e8fI4eLm0zjM/eeGCHasnoqqrb
# GwcF41iz9HXzFDwN4iD5z3QShp6HRiU3UpTwDJiiXcr0z6pjl7PyzJ3/tmWtGehV
# 7CAfc/WlyzCCBoIwggRqoAMCAQICEDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcN
# AQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYD
# VQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3Jr
# MS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
# MB4XDTIxMDMyMjAwMDAwMFoXDTM4MDExODIzNTk1OVowVzELMAkGA1UEBhMCR0Ix
# GDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEuMCwGA1UEAxMlU2VjdGlnbyBQdWJs
# aWMgVGltZSBTdGFtcGluZyBSb290IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
# ADCCAgoCggIBAIid2LlFZ50d3ei5JoGaVFTAfEkFm8xaFQ/ZlBBEtEFAgXcUmanU
# 5HYsyAhTXiDQkiUvpVdYqZ1uYoZEMgtHES1l1Cc6HaqZzEbOOp6YiTx63ywTon43
# 4aXVydmhx7Dx4IBrAou7hNGsKioIBPy5GMN7KmgYmuu4f92sKKjbxqohUSfjk1mJ
# lAjthgF7Hjx4vvyVDQGsd5KarLW5d73E3ThobSkob2SL48LpUR/O627pDchxll+b
# TSv1gASn/hp6IuHJorEu6EopoB1CNFp/+HpTXeNARXUmdRMKbnXWflq+/g36NJXB
# 35ZvxQw6zid61qmrlD/IbKJA6COw/8lFSPQwBP1ityZdwuCysCKZ9ZjczMqbUcLF
# yq6KdOpuzVDR3ZUwxDKL1wCAxgL2Mpz7eZbrb/JWXiOcNzDpQsmwGQ6Stw8tTCqP
# umhLRPb7YkzM8/6NnWH3T9ClmcGSF22LEyJYNWCHrQqYubNeKolzqUbCqhSqmr/U
# dUeb49zYHr7ALL8bAJyPDmubNqMtuaobKASBqP84uhqcRY/pjnYd+V5/dcu9ieER
# jiRKKsxCG1t6tG9oj7liwPddXEcYGOUiWLm742st50jGwTzxbMpepmOP1mLnJskv
# ZaN5e45NuzAHteORlsSuDt5t4BBRCJL+5EZnnw0ezntk9R8QJyAkL6/bAgMBAAGj
# ggEWMIIBEjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E
# FgQU9ndq3T/9ARP/FqFsggIv0Ao9FCUwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB
# /wQFMAMBAf8wEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAA
# MFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VS
# VHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDA1BggrBgEFBQcBAQQp
# MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI
# hvcNAQEMBQADggIBAA6+ZUHtaES45aHF1BGH5Lc7JYzrftrIF5Ht2PFDxKKFOct/
# awAEWgHQMVHol9ZLSyd/pYMbaC0IZ+XBW9xhdkkmUV/KbUOiL7g98M/yzRyqUOZ1
# /IY7Ay0YbMniIibJrPcgFp73WDnRDKtVutShPSZQZAdtFwXnuiWl8eFARK3PmLqE
# m9UsVX+55DbVIz33Mbhba0HUTEYv3yJ1fwKGxPBsP/MgTECimh7eXomvMm0/GPxX
# 2uhwCcs/YLxDnBdVVlxvDjHjO1cuwbOpkiJGHmLXXVNbsdXUC2xBrq9fLrfe8IBs
# A4hopwsCj8hTuwKXJlSTrZcPRVSccP5i9U28gZ7OMzoJGlxZ5384OKm0r568Mo9T
# YrqzKeKZgFo0fj2/0iHbj55hc20jfxvK3mQi+H7xpbzxZOFGm/yVQkpo+ffv5gdh
# p+hv1GDsvJOtJinJmgGbBFZIThbqI+MHvAmMmkfb3fTxmSkop2mSJL1Y2x/955S2
# 9Gu0gSJIkc3z30vU/iXrMpWx2tS7UVfVP+5tKuzGtgkP7d/doqDrLF1u6Ci3TpjA
# ZdeLLlRQZm867eVeXED58LXd1Dk6UvaAhvmWYXoiLz4JA5gPBcz7J311uahxCweN
# xE+xxxR3kT0WKzASo5G/PyDez6NHdIUKBeE3jDPs2ACc6CkJ1Sji4PKWVT0/MYIE
# kzCCBI8CAQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p
# dGVkMSwwKgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0
# MQIRAOdO8lWwUE/626bf9/yLoxUwDQYJYIZIAWUDBAICBQCgggH6MBoGCSqGSIb3
# DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwOTI4MDc1NDE2
# WjA/BgkqhkiG9w0BCQQxMgQwkK3phXr2s5FKbJ9pnVblth8Lbq7WxKKx2B/enHto
# oMxhxu9+R01U5wdhsMHZjoDJMIIBewYLKoZIhvcNAQkQAgwxggFqMIIBZjCCAWIw
# FgQU6XgYqSjaFQqf4b+czHqruaAO7qwwgYgEFGXDKGlvfU5QLP0Dx8IGlxjK+/dP
# MHAwW6RZMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQx
# LjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUgU3RhbXBpbmcgUm9vdCBSNDYC
# EQCQrAhyIP3Fp8RrXMcN9z0GMIG8BBSFPWMtk4KCYXzQkDXEkd6SwULaxzCBozCB
# jqSBizCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNV
# BAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx
# LjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkC
# EDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcNAQEBBQAEggIAVbsgrro//Uq7Z1M7
# h7Auh4k779WU+sbtk8Icf7FCIUw+Xy/4LOx/eiMRvpmp5n8dkKqjxUCW9bG88Z+W
# BKrgWIH6Y/YA2FRRkKEF8mCyLbW+hSlGgx0T/Ol8qv6f2kkGbYBjrj7s2/0j2HIH
# Aw/jVz6cJDZVA+X2duyYmA1hx2qb2tUfXbtxSaSpIHPsskJGrD8jA+Lfl/xva/c3
# cgStynxOM98THHG/kQdkqRuzVrDx/cpM7P/9YGPU3Wm3qSKWwOz4TLj9/mxYxSqj
# 2aD3jiuqyx6AgC22tS0fDGEreeMuMlp+1tzvKCMliLkOnrRMfdrc2Imy792iraXr
# wlTtd2GOVGgzbSKooYiQ92+uOff3+14DIT2kN4jU9X/GCtx2ox0gV7ku3RWYmzjq
# W/MT2H5BmquRu/I32kZD6QhzwToq5z0kxgE4iddXVXUDgvxDalU+uDS5UsE12Vsb
# wNbR2yEO4RLjVfMC8szdFksg/phD7PA9fHUxRot5QYMHnG390pk3hGy8H8Rv+bJM
# RDQx83LtXYWcOOUs7+QFDCWeevyy5gg3C9wvzogbp1I9YFdgXBrm6/mzYIgM/UeZ
# CSZeKmJCTR/AifTUyB9WbCIrRC1WCuDSgLjIU7y9SJztA5zHNA43BNhM5FNhGR+Z
# 1hsGViIYK9SjVOqBeawllSFQI+I=
# SIG # End signature block