Microsoft.Windows.Developer.psm1

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest

enum Ensure {
    Absent
    Present
}

enum Alignment {
    KeepCurrentValue
    Left
    Middle
}

enum ShowHideFeature {
    KeepCurrentValue
    Hide
    Show
}

enum HideTaskBarLabelsBehavior {
    KeepCurrentValue
    Always
    WhenFull
    Never
}

enum SearchBoxMode {
    KeepCurrentValue
    Hide
    ShowIconOnly
    SearchBox
    ShowIconAndLabel
}

enum AdminConsentPromptBehavior {
    KeepCurrentValue
    NoCredOrConsentRequired
    RequireCredOnSecureDesktop
    RequireConsentOnSecureDesktop
    RequireCred
    RequireConsent
    RequireConsentForNonWindowsBinaries
}

enum PowerPlanSettingName {
    DisplayTimeout
    SleepTimeout
}

enum PowerSource {
    # AC
    PluggedIn
    # DC
    Battery
    All
}

enum AdvancedNetworkSharingSettingName {
    NetworkDiscovery
    FileAndPrinterSharing
}

enum Action {
    NotConfigured
    Allow
    Block
}

enum Direction {
    Inbound
    Outbound
}

#region DSCResources
[DSCResource()]
class DeveloperMode {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    [DscProperty(NotConfigurable)]
    [bool] $IsEnabled

    hidden [string] $AppModelUnlockRegistryKeyPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock\'
    hidden [string] $DeveloperModePropertyName = 'AllowDevelopmentWithoutDevLicense'

    [DeveloperMode] Get() {
        function IsDeveloperModeEnabled {
            $regExists = DoesRegistryKeyPropertyExist -Path $this.AppModelUnlockRegistryKeyPath -Name $this.DeveloperModePropertyName

            # If the registry key does not exist, we assume developer mode is not enabled.
            if (-not($regExists)) {
                return $false
            }

            return Get-ItemPropertyValue -Path $this.AppModelUnlockRegistryKeyPath -Name $this.DeveloperModePropertyName
        }

        # 1 == enabled == Present // 0 == disabled == Absent
        $this.IsEnabled = IsDeveloperModeEnabled
        return @{
            Ensure    = $this.IsEnabled ? [Ensure]::Present : [Ensure]::Absent
            IsEnabled = $this.IsEnabled
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        if (!$this.Test()) {
            $windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
            $windowsPrincipal = New-Object -TypeName 'System.Security.Principal.WindowsPrincipal' -ArgumentList @( $windowsIdentity )

            if (-not $windowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
                throw 'Toggling Developer Mode requires this resource to be run as an Administrator.'
            }

            # 1 == enabled == Present // 0 == disabled == Absent
            $value = ($this.Ensure -eq [Ensure]::Present) ? 1 : 0
            Set-ItemProperty -Path $this.AppModelUnlockRegistryKeyPath -Name $this.DeveloperModePropertyName -Value $value
        }
    }
}

[DSCResource()]
class OsVersion {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty(Mandatory)]
    [string] $MinVersion

    [DscProperty(NotConfigurable)]
    [string] $OsVersion

    [OsVersion] Get() {
        $parsedVersion = $null
        if (![System.Version]::TryParse($this.MinVersion, [ref]$parsedVersion)) {
            throw "'$($this.MinVersion)' is not a valid Version string."
        }

        $this.OsVersion = (Get-ComputerInfo | Select-Object OsVersion).OsVersion

        return @{
            MinVersion = $this.MinVersion
            OsVersion  = $this.OsVersion
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return [System.Version]$currentState.OsVersion -ge [System.Version]$currentState.MinVersion
    }

    [void] Set() {
        # This resource is only for asserting the os version requirement.
    }
}

if ([string]::IsNullOrEmpty($env:TestRegistryPath)) {
    $global:ExplorerRegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\'
    $global:PersonalizeRegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\'
    $global:SearchRegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search\'
    $global:UACRegistryPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\'
    $global:RemoteDesktopRegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server'
    $global:LongPathsRegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem\'
} else {
    $global:ExplorerRegistryPath = $global:PersonalizeRegistryPath = $global:SearchRegistryPath = $global:UACRegistryPath = $global:RemoteDesktopRegistryPath = $global:LongPathsRegistryPath = $env:TestRegistryPath
}

[DSCResource()]
class Taskbar {
    [DscProperty()] [Alignment] $Alignment = [Alignment]::KeepCurrentValue
    [DscProperty()] [HideTaskBarLabelsBehavior] $HideLabelsMode = [HideTaskBarLabelsBehavior]::KeepCurrentValue
    [DscProperty()] [SearchBoxMode] $SearchboxMode = [SearchBoxMode]::KeepCurrentValue
    [DscProperty()] [ShowHideFeature] $TaskViewButton = [ShowHideFeature]::KeepCurrentValue
    [DscProperty()] [ShowHideFeature] $WidgetsButton = [ShowHideFeature]::KeepCurrentValue

    [DscProperty()] [bool] $RestartExplorer = $false
    [DscProperty(Key)] [string]$SID

    # Registry key names for the taskbar property that is being modified.
    hidden [string] $TaskbarAl = 'TaskbarAl'
    hidden [string] $TaskbarGlomLevel = 'TaskbarGlomLevel'
    hidden [string] $SearchboxTaskbarMode = 'SearchboxTaskbarMode'
    hidden [string] $ShowTaskViewButton = 'ShowTaskViewButton'
    hidden [string] $TaskbarDa = 'TaskbarDa'

    [Taskbar] Get() {
        $currentState = [Taskbar]::new()

        # Alignment
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl)) {
            $currentState.Alignment = [Alignment]::Middle
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl)
            $currentState.Alignment = $value -eq 0 ? [Alignment]::Left : [Alignment]::Middle
        }

        # HideTaskBarLabels
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.TaskbarGlomLevel)) {
            $currentState.HideLabelsMode = [HideTaskBarLabelsBehavior]::Always
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.TaskbarGlomLevel)
            $currentState.HideLabelsMode = switch ($value) {
                0 { [HideTaskBarLabelsBehavior]::Always }
                1 { [HideTaskBarLabelsBehavior]::WhenFull }
                2 { [HideTaskBarLabelsBehavior]::Never }
            }
        }

        # TaskbarSearchboxMode
        if (-not(DoesRegistryKeyPropertyExist -Path $global:SearchRegistryPath -Name $this.SearchboxTaskbarMode)) {
            $currentState.SearchboxMode = [SearchBoxMode]::SearchBox
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:SearchRegistryPath -Name $this.SearchboxTaskbarMode)
            $currentState.SearchboxMode = switch ($value) {
                0 { [SearchBoxMode]::Hide }
                1 { [SearchBoxMode]::ShowIconOnly }
                2 { [SearchBoxMode]::SearchBox }
                3 { [SearchBoxMode]::ShowIconAndLabel }
            }
        }

        # TaskViewButton
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.ShowTaskViewButton)) {
            # Default behavior if registry key not found.
            $currentState.TaskViewButton = [ShowHideFeature]::Show
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.ShowTaskViewButton)
            $currentState.TaskViewButton = $value -eq 0 ? [ShowHideFeature]::Hide : [ShowHideFeature]::Show
        }

        # WidgetsButton
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.TaskbarDa)) {
            # Default behavior if registry key not found.
            $currentState.WidgetsButton = [ShowHideFeature]::Show
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.TaskbarDa)
            $currentState.WidgetsButton = $value -eq 0 ? [ShowHideFeature]::Hide : [ShowHideFeature]::Show
        }

        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()

        if ($this.Alignment -ne [Alignment]::KeepCurrentValue -and $currentState.Alignment -ne $this.Alignment) {
            return $false
        }

        if ($this.HideLabelsMode -ne [HideTaskBarLabelsBehavior]::KeepCurrentValue -and $currentState.HideLabelsMode -ne $this.HideLabelsMode) {
            return $false
        }

        if ($this.SearchboxMode -ne [SearchBoxMode]::KeepCurrentValue -and $currentState.SearchboxMode -ne $this.SearchboxMode) {
            return $false
        }

        if ($this.TaskViewButton -ne [ShowHideFeature]::KeepCurrentValue -and $currentState.TaskViewButton -ne $this.TaskViewButton) {
            return $false
        }

        if ($this.WidgetsButton -ne [ShowHideFeature]::KeepCurrentValue -and $currentState.WidgetsButton -ne $this.WidgetsButton) {
            return $false
        }

        return $true
    }

    [void] Set() {
        if ($this.Alignment -ne [Alignment]::KeepCurrentValue) {
            $desiredAlignment = $this.Alignment -eq [Alignment]::Left ? 0 : 1
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl -Value $desiredAlignment
        }

        if ($this.HideLabelsMode -ne [HideTaskBarLabelsBehavior]::KeepCurrentValue) {
            $desiredHideLabelsBehavior = switch ($this.HideLabelsMode) {
                Always { 0 }
                WhenFull { 1 }
                Never { 2 }
            }

            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.TaskbarGlomLevel -Value $desiredHideLabelsBehavior
        }

        if ($this.SearchboxMode -ne [SearchBoxMode]::KeepCurrentValue) {
            $desiredSearchboxMode = switch ([SearchBoxMode]($this.SearchboxMode)) {
                Hide { 0 }
                ShowIconOnly { 1 }
                SearchBox { 2 }
                ShowIconAndLabel { 3 }
            }

            Set-ItemProperty -Path $global:SearchRegistryPath -Name $this.SearchboxTaskbarMode -Value $desiredSearchboxMode
        }

        if ($this.TaskViewButton -ne [ShowHideFeature]::KeepCurrentValue) {
            $desiredTaskViewButtonState = $this.TaskViewButton -eq [ShowHideFeature]::Show ? 1 : 0
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.ShowTaskViewButton -Value $desiredTaskViewButtonState
        }

        if ($this.WidgetsButton -ne [ShowHideFeature]::KeepCurrentValue) {
            $desiredWidgetsButtonState = $this.WidgetsButton -eq [ShowHideFeature]::Show ? 1 : 0
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.TaskBarDa -Value $desiredWidgetsButtonState
        }

        if ($this.RestartExplorer) {
            # Explorer needs to be restarted to enact the changes for HideLabelsMode.
            taskkill /F /IM explorer.exe
            Start-Process explorer.exe
        }
    }
}

[DSCResource()]
class WindowsExplorer {
    [DscProperty()] [ShowHideFeature] $FileExtensions = [ShowHideFeature]::KeepCurrentValue
    [DscProperty()] [ShowHideFeature] $HiddenFiles = [ShowHideFeature]::KeepCurrentValue
    [DscProperty()] [ShowHideFeature] $ItemCheckBoxes = [ShowHideFeature]::KeepCurrentValue

    [DscProperty()] [bool] $RestartExplorer = $false
    [DscProperty(Key)] [string]$SID

    # Registry key names for the taskbar property that is being modified.
    hidden [string] $HideFileExt = 'HideFileExt'
    hidden [string] $Hidden = 'Hidden'
    hidden [string] $AutoCheckSelect = 'AutoCheckSelect'

    [WindowsExplorer] Get() {
        $currentState = [WindowsExplorer]::new()

        # FileExtensions
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.HideFileExt)) {
            $currentState.FileExtensions = [ShowHideFeature]::Show
        } else {
            $value = Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.HideFileExt
            $currentState.FileExtensions = $value -eq 1 ? [ShowHideFeature]::Hide : [ShowHideFeature]::Show
        }

        # HiddenFiles
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.Hidden)) {
            $currentState.HiddenFiles = [ShowHideFeature]::Show
        } else {
            $value = Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.Hidden
            $currentState.HiddenFiles = $value -eq 1 ? [ShowHideFeature]::Show : [ShowHideFeature]::Hide
        }

        # ItemCheckboxes
        if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.AutoCheckSelect)) {
            $currentState.ItemCheckBoxes = [ShowHideFeature]::Show
        } else {
            $value = Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.AutoCheckSelect
            $currentState.ItemCheckBoxes = $value -eq 1 ? [ShowHideFeature]::Show : [ShowHideFeature]::Hide
        }


        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()

        if ($this.FileExtensions -ne [ShowHideFeature]::KeepCurrentValue -and $currentState.FileExtensions -ne $this.FileExtensions) {
            return $false
        }

        if ($this.HiddenFiles -ne [ShowHideFeature]::KeepCurrentValue -and $currentState.HiddenFiles -ne $this.HiddenFiles) {
            return $false
        }

        if ($this.ItemCheckBoxes -ne [ShowHideFeature]::KeepCurrentValue -and $currentState.ItemCheckBoxes -ne $this.ItemCheckBoxes) {
            return $false
        }

        return $true
    }

    [void] Set() {
        if ($this.FileExtensions -ne [ShowHideFeature]::KeepCurrentValue) {
            $desiredFileExtensions = $this.FileExtensions -eq [ShowHideFeature]::Show ? 0 : 1
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.HideFileExt -Value $desiredFileExtensions
        }

        if ($this.HiddenFiles -ne [ShowHideFeature]::KeepCurrentValue) {
            $desiredHiddenFiles = $this.HiddenFiles -eq [ShowHideFeature]::Show ? 1 : 0
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.Hidden -Value $desiredHiddenFiles
        }

        if ($this.ItemCheckBoxes -ne [ShowHideFeature]::KeepCurrentValue) {
            $desiredItemCheckBoxes = $this.ItemCheckBoxes -eq [ShowHideFeature]::Show ? 1 : 0
            Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.AutoCheckSelect -Value $desiredItemCheckBoxes
        }

        if ($this.RestartExplorer) {
            # Explorer needs to be restarted to enact the changes.
            taskkill /F /IM explorer.exe
            Start-Process explorer.exe
        }
    }
}

[DSCResource()]
class UserAccessControl {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [AdminConsentPromptBehavior] $AdminConsentPromptBehavior = [AdminConsentPromptBehavior]::KeepCurrentValue

    hidden [string] $ConsentPromptBehaviorAdmin = 'ConsentPromptBehaviorAdmin'

    # NOTE: 'EnableLUA' is another registry key that disables UAC prompts, but requires a reboot and opens everything in admin mode.

    [UserAccessControl] Get() {
        $currentState = [UserAccessControl]::new()

        if (-not(DoesRegistryKeyPropertyExist -Path $global:UACRegistryPath -Name $this.ConsentPromptBehaviorAdmin)) {
            $currentState.AdminConsentPromptBehavior = [AdminConsentPromptBehavior]::RequireConsentForNonWindowsBinaries
        } else {
            $value = [int](Get-ItemPropertyValue -Path $global:UACRegistryPath -Name $this.ConsentPromptBehaviorAdmin)
            $currentState.AdminConsentPromptBehavior = switch ($value) {
                0 { [AdminConsentPromptBehavior]::NoCredOrConsentRequired }
                1 { [AdminConsentPromptBehavior]::RequireCredOnSecureDesktop }
                2 { [AdminConsentPromptBehavior]::RequireConsentOnSecureDesktop }
                3 { [AdminConsentPromptBehavior]::RequireCred }
                4 { [AdminConsentPromptBehavior]::RequireConsent }
                5 { [AdminConsentPromptBehavior]::RequireConsentForNonWindowsBinaries }
            }
        }

        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()

        if ($this.AdminConsentPromptBehavior -ne [AdminConsentPromptBehavior]::KeepCurrentValue -and $currentState.AdminConsentPromptBehavior -ne $this.AdminConsentPromptBehavior) {
            return $false
        }

        return $true
    }

    [void] Set() {
        if ($this.AdminConsentPromptBehavior -ne [AdminConsentPromptBehavior]::KeepCurrentValue) {
            $desiredState = switch ([AdminConsentPromptBehavior]($this.AdminConsentPromptBehavior)) {
                NoCredOrConsentRequired { 0 }
                RequireCredOnSecureDesktop { 1 }
                RequireConsentOnSecureDesktop { 2 }
                RequireCred { 3 }
                RequireConsent { 4 }
                RequireConsentForNonWindowsBinaries { 5 }
            }

            Set-ItemProperty -Path $global:UACRegistryPath -Name $this.ConsentPromptBehaviorAdmin -Value $desiredState
        }
    }
}

[DSCResource()]
class EnableDarkMode {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    [DscProperty()]
    [bool] $RestartExplorer = $false

    hidden [string] $AppsUseLightTheme = 'AppsUseLightTheme'
    hidden [string] $SystemUsesLightTheme = 'SystemUsesLightTheme'

    [EnableDarkMode] Get() {
        $exists = (DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme) -and (DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme)
        if (-not($exists)) {
            return @{
                Ensure = [Ensure]::Absent
            }
        }

        $appsUseLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme
        $systemUsesLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme

        $isDarkModeEnabled = if ($appsUseLightModeValue -eq 0 -and $systemUsesLightModeValue -eq 0) { [Ensure]::Present } else { [Ensure]::Absent }

        return @{
            Ensure = $isDarkModeEnabled
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        $value = if ($this.Ensure -eq [Ensure]::Present) { 0 } else { 1 }
        Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme -Value $value
        Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme -Value $value

        if ($this.RestartExplorer) {
            # Explorer needs to be restarted to enact the changes.
            Stop-Process -ProcessName Explorer
        }
    }
}

[DSCResource()]
class ShowSecondsInClock {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    hidden [string] $ShowSecondsInSystemClock = 'ShowSecondsInSystemClock'

    [ShowSecondsInClock] Get() {
        $exists = DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.ShowSecondsInSystemClock
        if (-not($exists)) {
            return @{
                Ensure = [Ensure]::Absent
            }
        }

        $registryValue = Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.ShowSecondsInSystemClock

        return @{
            Ensure = $registryValue ? [Ensure]::Present : [Ensure]::Absent
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        $value = ($this.Ensure -eq [Ensure]::Present) ? 1 : 0
        Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.ShowSecondsInSystemClock -Value $value
    }
}

[DSCResource()]
class EnableRemoteDesktop {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    hidden [string] $RemoteDesktopKey = 'fDenyTSConnections'

    [EnableRemoteDesktop] Get() {
        $exists = DoesRegistryKeyPropertyExist -Path $global:RemoteDesktopRegistryPath -Name $this.RemoteDesktopKey
        if (-not($exists)) {
            return @{
                Ensure = [Ensure]::Absent
            }
        }

        $registryValue = Get-ItemPropertyValue -Path $global:RemoteDesktopRegistryPath -Name $this.RemoteDesktopKey

        # Since the key is a 'deny' type key, 0 == enabled == Present // 1 == disabled == Absent
        return @{
            Ensure = $registryValue ? [Ensure]::Absent : [Ensure]::Present
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        # Since the key is a 'deny' type key, 0 == enabled == Present // 1 == disabled == Absent
        $value = ($this.Ensure -eq [Ensure]::Present) ? 0 : 1
        Set-ItemProperty -Path $global:RemoteDesktopRegistryPath -Name $this.RemoteDesktopKey -Value $value
    }
}

[DSCResource()]
class EnableLongPathSupport {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    hidden [string] $LongPathsKey = 'LongPathsEnabled'

    [EnableLongPathSupport] Get() {
        $exists = DoesRegistryKeyPropertyExist -Path $global:LongPathsRegistryPath -Name $this.LongPathsKey

        # If the registry key does not exist, we assume long path support is not enabled.
        if (-not($exists)) {
            return @{
                Ensure = [Ensure]::Absent
            }
        }

        $registryValue = Get-ItemPropertyValue -Path $global:LongPathsRegistryPath -Name $this.LongPathsKey

        # 1 == enabled == Present // 0 == disabled == Absent
        return @{
            Ensure = $registryValue ? [Ensure]::Present : [Ensure]::Absent
        }
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        # 1 == enabled == Present // 0 == disabled == Absent
        $value = ($this.Ensure -eq [Ensure]::Present) ? 1 : 0
        Set-ItemProperty -Path $global:LongPathsRegistryPath -Name $this.LongPathsKey -Value $value
    }
}

[DSCResource()]
class PowerPlanSetting {
    [DscProperty(Key, Mandatory)]
    [PowerPlanSettingName]$Name

    [DscProperty(Mandatory)]
    [PowerSource]$PowerSource

    [DscProperty(Mandatory)]
    [int]$SettingValue

    [DscProperty(NotConfigurable)]
    [int] $PluggedInValue

    [DscProperty(NotConfigurable)]
    [int] $BatteryValue

    [PowerPlanSetting] Get() {

        function Get-PowerPlanSetting ([PowerPlanSettingName] $SettingName) {
            Begin {
                # If a power plan group policy is set, the power settings cannot be obtained, so temporarily disable it.
                $GPReg = Backup-GroupPolicyPowerPlanSetting
                if ($GPReg) {
                    Disable-GroupPolicyPowerPlanSetting
                }
            }

            Process {
                $SettingGUID = ($SettingName -eq [PowerPlanSettingName]::DisplayTimeout) ? $DisplayTimeoutSettingGUID : $SleepTimeoutSettingGUID
                $PowerPlan = Get-ActivePowerPlan
                $planID = $PowerPlan.InstanceId.Split('\')[1] -replace '[{}]'

                $ReturnValue = @{
                    PlanGuid    = $planID
                    SettingGuid = $SettingGUID
                    ACValue     = ''
                    DCValue     = ''
                }

                foreach ($Power in ('AC', 'DC')) {
                    $Key = ('{0}Value' -f $Power)
                    $InstanceId = ('Microsoft:PowerSettingDataIndex\{{{0}}}\{1}\{{{2}}}' -f $planID, $Power, $SettingGUID)
                    $Instance = (Get-CimInstance -Name root\cimv2\power -Class Win32_PowerSettingDataIndex | Where-Object { $_.InstanceID -eq $InstanceId })
                    # error state
                    if (-not $Instance) { return }
                    $ReturnValue.$Key = [int]$Instance.SettingIndexValue
                }

                return $ReturnValue
            }

            End {
                if ($GPReg) {
                    # Restore the group policies
                    Restore-GroupPolicyPowerPlanSetting -GPRegArray $GPReg
                }
            }
        }

        $Setting = Get-PowerPlanSetting -SettingName $this.Name
        $this.PluggedInValue = $Setting.ACValue
        $this.BatteryValue = $Setting.DCValue

        $currentState = [PowerPlanSetting]::new()
        $currentState.Name = $this.Name
        $currentState.SettingValue = $this.SettingValue
        $currentState.PluggedInValue = $this.PluggedInValue
        $currentState.BatteryValue = $this.BatteryValue
        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()

        # User can only specify a single setting value
        $pluggedInTest = ($currentState.PluggedInValue -eq $this.SettingValue)
        $batteryTest = ($currentState.BatteryValue -eq $this.SettingValue)

        if ($this.PowerSource -eq [PowerSource]::All) {
            return ($pluggedInTest -and $batteryTest)
        } elseif ($this.PowerSource -eq [PowerSource]::PluggedIn) {
            return $pluggedInTest
        } else {
            return $batteryTest
        }
    }

    [void] Set() {
        function Set-PowerPlanSetting ([PowerPlanSettingName] $PowerPlanSettingName, [PowerSource]$PowerSource, [int]$Value) {
            Begin {
                # If a power plan group policy is set, the power settings cannot be obtained, so temporarily disable it.
                $GPReg = Backup-GroupPolicyPowerPlanSetting
                if ($GPReg) {
                    Disable-GroupPolicyPowerPlanSetting
                }
            }
            Process {
                $SettingGUID = ($PowerPlanSettingName -eq [PowerPlanSettingName]::DisplayTimeout) ? $DisplayTimeoutSettingGUID : $SleepTimeoutSettingGUID
                $PowerPlan = Get-ActivePowerPlan
                $planID = $PowerPlan.InstanceId.Split('\')[1] -replace '[{}]'

                if ($PowerSource -eq [PowerSource]::All) {
                    [string[]]$Target = ('AC', 'DC')
                } elseif ($PowerSource -eq [PowerSource]::PluggedIn) {
                    [string[]]$Target = ('AC')
                } else {
                    [string[]]$Target = ('DC')
                }

                foreach ($Power in $Target) {
                    $InstanceId = ('Microsoft:PowerSettingDataIndex\{{{0}}}\{1}\{{{2}}}' -f $planID, $Power, $SettingGUID)
                    $Instance = Get-CimInstance -Name root\cimv2\power -Class Win32_PowerSettingDataIndex | Where-Object { $_.InstanceID -eq $InstanceId }
                    # error state
                    if (-not $Instance) { return }
                    $Instance | ForEach-Object { $_.SettingIndexValue = $Value }
                    Set-CimInstance -CimInstance $Instance
                }
            }
            End {
                if ($GPReg) {
                    # Restore the group policies
                    Restore-GroupPolicyPowerPlanSetting -GPRegArray $GPReg
                }
            }
        }

        if (!$this.Test()) {
            Set-PowerPlanSetting -PowerPlanSettingName $this.Name -PowerSource $this.PowerSource -Value $this.SettingValue
        }
    }
}

[DSCResource()]
class WindowsCapability {
    [DscProperty(Key, Mandatory)]
    [string] $Name

    [DscProperty()]
    [Ensure] $Ensure = [Ensure]::Present

    [WindowsCapability] Get() {
        $currentState = [WindowsCapability]::new()
        $windowsCapability = Get-WindowsCapability -Online -Name $this.Name

        # If Name is not set in windowsCapability then the specified capability was not found
        if ([System.String]::IsNullOrEmpty($windowsCapability.Name)) {
            throw  (New-Object -TypeName System.ArgumentException -ArgumentList "$this.Name")
        } else {
            $currentState.Name = $windowsCapability.Name

            if ($windowsCapability.State -eq 'Installed') {
                $currentState.Ensure = [Ensure]::Present
            } else {
                $currentState.Ensure = [Ensure]::Absent
            }
        }

        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.Ensure -eq $this.Ensure
    }

    [void] Set() {
        # Only make changes if changes are needed
        if (-not $this.Test()) {
            if ($this.Ensure -eq [Ensure]::Present) {
                Add-WindowsCapability -Online -Name $this.Name
            } else {
                Remove-WindowsCapability -Online -Name $this.Name
            }
        }
    }
}

[DSCResource()]
class NetConnectionProfile {
    # Key required. Do not set.
    [DscProperty(Key)]
    [string]$SID

    [DscProperty(Mandatory)]
    [string]$InterfaceAlias

    [DscProperty(Mandatory)]
    [string]$NetworkCategory

    [NetConnectionProfile] Get() {
        $currentState = [NetConnectionProfile]::new()

        $netConnectionProfile = Get-NetConnectionProfile -InterfaceAlias $this.InterfaceAlias -ErrorAction SilentlyContinue
        if ($null -eq $netConnectionProfile) {
            throw "No network profile found for interface alias '$($this.InterfaceAlias)'"
        }

        $currentState.InterfaceAlias = $this.InterfaceAlias
        $currentState.NetworkCategory = $netConnectionProfile.NetworkCategory
        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()
        return $currentState.NetworkCategory -eq $this.NetworkCategory
    }

    [void] Set() {
        if (-not $this.Test()) {
            Set-NetConnectionProfile -InterfaceAlias $this.InterfaceAlias -NetworkCategory $this.NetworkCategory
        }
    }
}

[DSCResource()]
class AdvancedNetworkSharingSetting {
    [DscProperty(Key, Mandatory)]
    [AdvancedNetworkSharingSettingName]$Name

    [DscProperty()]
    [string[]]$Profiles = @()

    [DscProperty(NotConfigurable)]
    [string[]]$EnabledProfiles

    # Official group names for the firewall rules
    hidden [string] $NetworkDiscoveryGroup = '@FirewallAPI.dll,-32752'
    hidden [string] $FileAndPrinterSharingGroup = '@FirewallAPI.dll,-28502'

    [AdvancedNetworkSharingSetting] Get() {
        $currentState = [AdvancedNetworkSharingSetting]::new()
        $currentState.Name = $this.Name
        $currentState.Profiles = $this.Profiles

        if ($this.Name -eq [AdvancedNetworkSharingSettingName]::NetworkDiscovery) {
            $group = $this.NetworkDiscoveryGroup
        } else {
            $group = $this.FileAndPrinterSharingGroup
        }

        # The group is enabled if all of its sub-rules are enabled and none are disabled.
        $this.EnabledProfiles = Get-NetFirewallRule -Group $group | Group-Object Profile | ForEach-Object {
            $enabled = ($_.Group.Enabled | Where-Object { $_ -eq 'true' } | Measure-Object).Count
            $disabled = ($_.Group.Enabled | Where-Object { $_ -eq 'false' } | Measure-Object).Count
            [PSCustomObject]@{
                Profile  = $_.Name
                Count    = $_.Count
                Enabled  = $enabled
                Disabled = $disabled
            }
        } | Where-Object { ($_.Enabled -gt 0) -and ($_.Disabled -eq 0) -and ($_.Enabled -eq $_.Count) } | Select-Object -Unique -CaseInsensitive -ExpandProperty Profile

        $currentState.EnabledProfiles = $this.EnabledProfiles

        return $currentState
    }

    [bool] Test() {
        $currentState = $this.Get()

        # Compare-object is case insensitive by default and does not take null arguments
        $difference = Compare-Object -ReferenceObject @( $this.Profiles | Select-Object) -DifferenceObject @( $currentState.EnabledProfiles | Select-Object)
        return -not $difference
    }

    [void] Set() {
        if (!$this.Test()) {
            if ($this.Name -eq [AdvancedNetworkSharingSettingName]::NetworkDiscovery) {
                $group = $this.NetworkDiscoveryGroup
            } else {
                $group = $this.FileAndPrinterSharingGroup
            }

            #Enable, no harm in enabling profiles if they are already enabled
            foreach ($profile in $this.Profiles) {
                Set-NetFirewallRule -Group $group -Profile $profile -Enabled True
            }

            #Disable needed if at least one profile is enabled
            $profilesToDisable = Get-NetFirewallRule -Group $group | Where-Object { ($_.Enabled -eq 'True') -and (-not $this.Profiles -Contains $_.Profile ) } | Select-Object -Unique -CaseInsensitive -ExpandProperty Profile
            foreach ($profile in $profilesToDisable) {
                Set-NetFirewallRule -Group $group -Profile $profile -Enabled False
            }
        }
    }
}

[DSCResource()]
class FirewallRule {
    [DscProperty(Key, Mandatory)]
    [string]$Name

    [DscProperty()]
    [string]$DisplayName

    [DscProperty()]
    [Action]$Action

    [DscProperty()]
    [string]$Description

    [DscProperty()]
    [Direction]$Direction

    [DscProperty()]
    [bool]$Enabled

    [DscProperty()]
    [Ensure]$Ensure = [Ensure]::Present

    [DscProperty()]
    [string[]]$LocalPort

    [DscProperty()]
    [string[]]$Profiles

    [DscProperty()]
    [string]$Protocol

    [FirewallRule] Get() {
        $rule = Get-NetFirewallRule -Name $this.Name -ErrorAction SilentlyContinue

        if (-not $rule) {
            return @{
                Ensure = [Ensure]::Absent
                Name   = $this.Name
            }
        }

        $properties = $rule | GetNetFirewallPortFilter
        return @{
            Ensure      = [Ensure]::Present
            Name        = $rule.Name
            DisplayName = $rule.DisplayName
            Action      = $rule.Action
            Description = $rule.Description
            Direction   = $rule.Direction
            Enabled     = $rule.Enabled
            LocalPort   = $properties.LocalPort
            # Split the profiles string into an array
            Profiles    = ($rule.Profile -split ',') | ForEach-Object { $_.Trim() }
            Protocol    = $properties.Protocol
        }
    }

    [bool] Test() {
        $currentState = $this.Get()

        if ($this.Ensure -eq [Ensure]::Absent) {
            return $currentState.Ensure -eq [Ensure]::Absent
        }

        # Check each property only if it is specified
        if ($this.DisplayName -and ($currentState.DisplayName -ne $this.DisplayName)) {
            return $false
        }

        if ($currentState.Action -ne $this.Action) {
            return $false
        }

        if ($this.Description -and ($currentState.Description -ne $this.Description)) {
            return $false
        }

        if ($currentState.Direction -ne $this.Direction) {
            return $false
        }

        if ($currentState.Enabled -ne $this.Enabled) {
            return $false
        }

        if ($this.LocalPort -and (Compare-Object $currentState.LocalPort $this.LocalPort)) {
            return $false
        }

        if ($this.Profiles -and (Compare-Object $currentState.Profiles $this.Profiles)) {
            return $false
        }

        if ($this.Protocol -and ($currentState.Protocol -ne $this.Protocol)) {
            return $false
        }

        return $true
    }

    [void] Set() {
        # Only make changes if changes are needed
        if (-not $this.Test()) {
            if ($this.Ensure -eq [Ensure]::Absent) {
                Remove-NetFirewallRule -Name $this.Name -ErrorAction SilentlyContinue
            } else {
                $firewallRule = Get-NetFirewallRule -Name $this.Name
                $exists = ($null -ne $firewallRule)

                $params = @{
                    # Escape firewall rule name to ensure that wildcard update is not used
                    Name        = ConvertTo-FirewallRuleNameEscapedString -Name $this.Name
                    DisplayName = $this.DisplayName
                    Action      = $this.Action.ToString()
                    Description = $this.Description
                    Direction   = $this.Direction.ToString()
                    Enabled     = $this.Enabled.ToString()
                    Profile     = $this.Profiles
                    Protocol    = $this.Protocol
                    LocalPort   = $this.LocalPort
                }

                if ($exists) {
                    <#
                        If the DisplayName is provided then need to remove it
                        And change it to NewDisplayName if it is different.
                    #>

                    if ($params.ContainsKey('DisplayName')) {
                        $null = $params.Remove('DisplayName')
                        if ($this.DisplayName -ne $FirewallRule.DisplayName) {
                            $null = $params.Add('NewDisplayName', $this.DisplayName)
                        }
                    }

                    Set-NetFirewallRule @params
                } else {
                    New-NetFirewallRule @params
                }
            }
        }
    }
}
#endregion DSCResources

#region Functions
function DoesRegistryKeyPropertyExist {
    param (
        [Parameter(Mandatory)]
        [string]$Path,

        [Parameter(Mandatory)]
        [string]$Name
    )

    # Get-ItemProperty will return $null if the registry key property does not exist.
    $itemProperty = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
    return $null -ne $itemProperty
}

function Get-ActivePowerPlan {
    Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan | Where-Object { $_.IsActive }
}

$SleepTimeoutSettingGUID = '29f6c1db-86da-48c5-9fdb-f2b67b1f44da'
$DisplayTimeoutSettingGUID = '3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e'

$GroupPolicyPowerPlanRegistryKeyPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Power\PowerSettings'

function Backup-GroupPolicyPowerPlanSetting {
    if (Test-Path $GroupPolicyPowerPlanRegistryKeyPath) {
        $Array = @()
        Get-ChildItem $GroupPolicyPowerPlanRegistryKeyPath | ForEach-Object {
            $Path = $_.PSPath
            foreach ($Prop in $_.Property) {
                $Array += @{
                    Path  = $Path
                    Name  = $Prop
                    Value = Get-ItemPropertyValue -Path $Path -Name $Prop
                }
            }
        }
        $Array
    }
}

function Restore-GroupPolicyPowerPlanSetting([HashTable[]]$GPRegArray) {
    foreach ($Item in $GPRegArray) {
        if (-not (Test-Path $Item.Path)) {
            New-Item -Path $Item.Path -ItemType Directory -Force | Out-Null
        }
        New-ItemProperty @Item -Force | Out-Null
    }
}

function Disable-GroupPolicyPowerPlanSetting {
    Remove-Item $GroupPolicyPowerPlanRegistryKeyPath -Recurse -Force | Out-Null
}

# Convert Firewall Rule name to Escape Wildcard Characters. It will append '[', ']' and '*' with a backtick.
function ConvertTo-FirewallRuleNameEscapedString {
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        $Name
    )

    return $Name.Replace('[', '`[').Replace(']', '`]').Replace('*', '`*')
}

# Workaround mock issue for Get-NetFirewallPortFilter
function GetNetFirewallPortFilter {
    process {
        return $_ | Get-NetFirewallPortFilter
    }
}
#endregion Functions

# SIG # Begin signature block
# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAu9xpRBi5P/SFC
# GSBVG6QOlQfe0H33DHfT7koOZFFrj6CCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIIR66r+MRTFXnHkogr0QSgz1
# 2gDsaOYcupuwvbVr6Lr3MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAkb+RDq4hTEqLbsQxP1Cdt8OMapq22HA/2x1jhkv4OkWxRRWU1F4OADJe
# +xWJEO39CeV+d1qked0eFOoR4W4PJ8Qsxuo/YVo0Hrsmj4hhCaF2hE9c50PAzyJX
# eWoNkot90z9xjlzZ+6C2/Lg0WLOTu24Tg3iOY4hicxCtQ4p+aYSzLs4vHIhIg03i
# NrDd64EtwiPIi2YGrOZgPIemTpc13hR06Vcr3YCv2U1L2W3I+950spEeqBKaLFkw
# zKNByz+rghi/F7HgkjdAf+eAJMOpgt/sdswkanCss8FrDwnWzHts5wNvC9wPTHVy
# IbD9xKB24Mc2C1GW3Bp/H6UojZMzm6GCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCC3oF6wCfXka584eOIsMi7yB/b2BO7lEWOPTZMS7t2b8AIGaCZINlWR
# GBMyMDI1MDUyODIwMjYxMC42MjFaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzcwMy0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHtMIIHIDCCBQigAwIBAgITMwAAAgpHshTZ7rKzDwABAAACCjANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQy
# NTdaFw0yNjA0MjIxOTQyNTdaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzcwMy0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCy7NzwEpb7BpwAk9LJ00Xq30TcTjcwNZ80TxAtAbhS
# aJ2kwnJA1Au/Do9/fEBjAHv6Mmtt3fmPDeIJnQ7VBeIq8RcfjcjrbPIg3wA5v5MQ
# flPNSBNOvcXRP+fZnAy0ELDzfnJHnCkZNsQUZ7GF7LxULTKOYY2YJw4TrmcHohkY
# 6DjCZyxhqmGQwwdbjoPWRbYu/ozFem/yfJPyjVBql1068bcVh58A8c5CD6TWN/L3
# u+Ny+7O8+Dver6qBT44Ey7pfPZMZ1Hi7yvCLv5LGzSB6o2OD5GIZy7z4kh8UYHdz
# jn9Wx+QZ2233SJQKtZhpI7uHf3oMTg0zanQfz7mgudefmGBrQEg1ox3n+3Tizh0D
# 9zVmNQP9sFjsPQtNGZ9ID9H8A+kFInx4mrSxA2SyGMOQcxlGM30ktIKM3iqCuFEU
# 9CHVMpN94/1fl4T6PonJ+/oWJqFlatYuMKv2Z8uiprnFcAxCpOsDIVBO9K1vHeAM
# iQQUlcE9CD536I1YLnmO2qHagPPmXhdOGrHUnCUtop21elukHh75q/5zH+OnNekp
# 5udpjQNZCviYAZdHsLnkU0NfUAr6r1UqDcSq1yf5RiwimB8SjsdmHll4gPjmqVi0
# /rmnM1oAEQm3PyWcTQQibYLiuKN7Y4io5bJTVwm+vRRbpJ5UL/D33C//7qnHbeoW
# BQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFAKvF0EEj4AyPfY8W/qrsAvftZwkMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCwk3PW0CyjOaqXCMOusTde7ep2CwP/xV1J
# 3o9KAiKSdq8a2UR5RCHYhnJseemweMUH2kNefpnAh2Bn8H2opDztDJkj8OYRd/KQ
# ysE12NwaY3KOwAW8Rg8OdXv5fUZIsOWgprkCQM0VoFHdXYExkJN3EzBbUCUw3yb4
# gAFPK56T+6cPpI8MJLJCQXHNMgti2QZhX9KkfRAffFYMFcpsbI+oziC5Brrk3361
# cJFHhgEJR0J42nqZTGSgUpDGHSZARGqNcAV5h+OQDLeF2p3URx/P6McUg1nJ2gMP
# YBsD+bwd9B0c/XIZ9Mt3ujlELPpkijjCdSZxhzu2M3SZWJr57uY+FC+LspvIOH1O
# pofanh3JGDosNcAEu9yUMWKsEBMngD6VWQSQYZ6X9F80zCoeZwTq0i9AujnYzzx5
# W2fEgZejRu6K1GCASmztNlYJlACjqafWRofTqkJhV/J2v97X3ruDvfpuOuQoUtVA
# wXrDsG2NOBuvVso5KdW54hBSsz/4+ORB4qLnq4/GNtajUHorKRKHGOgFo8DKaXG+
# UNANwhGNxHbILSa59PxExMgCjBRP3828yGKsquSEzzLNWnz5af9ZmeH4809fwItt
# I41JkuiY9X6hmMmLYv8OY34vvOK+zyxkS+9BULVAP6gt+yaHaBlrln8Gi4/dBr2y
# 6Srr/56g0DCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM3MDMtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDR
# AMVJlA6bKq93Vnu3UkJgm5HlYaCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6+HpLTAiGA8yMDI1MDUyODE5NTcz
# M1oYDzIwMjUwNTI5MTk1NzMzWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDr4ekt
# AgEAMAoCAQACAiNsAgH/MAcCAQACAhJGMAoCBQDr4zqtAgEAMDYGCisGAQQBhFkK
# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
# KoZIhvcNAQELBQADggEBAHf+DL4nEd8AFS+zDS7EnvZ0iFUfRyyUGgGijYcQ2RY5
# uOytO96I3TPDi62YeuD+CEF7lnzCNuwbWpcyQZNNj1qkoYGfAZvZz8CcK06j+oFw
# sTGa0qK8NAECtbTlzwCmUNNFHM/THyeqtvttcWg/RFwiMhjbzjWmXs04XTG4LkFy
# TYgTGrDNpJ7SItsWROLJAyylaqvBvq8TVpg8RocmI3owMhJRK7VunoJkIys9tFC6
# RgTpeNEEQlKiWYDZ6YzS/jaT0bH9ycwN6bE9PuQIr0XLng1Tq28Sga+1xLOuo6WE
# tKZXvi/bGRje8bCmYaf6dwSZSZDOHCKrVxg9PSiD/lQxggQNMIIECQIBATCBkzB8
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgpHshTZ7rKzDwABAAAC
# CjANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
# MC8GCSqGSIb3DQEJBDEiBCCdknraO6u6+I+vbXUMOUWw8udj+D+gOyBIo8AWET1B
# PzCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIE2ay/y0epK/X3Z03KTcloqE
# 8u9IXRtdO7Mex0hw9+SaMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAIKR7IU2e6ysw8AAQAAAgowIgQgUJxVXjypXSAPbKLX2gOcOvfR
# T0zMu67yBMEoQq1k3UswDQYJKoZIhvcNAQELBQAEggIAqXOcYkDPDJ5mAQYskqKr
# 0+/s0wQFbBh0gQqe9J8heQf4dkMlH2DKuZ5BshkA/4hFZgb6xQjcnZoEh6V4fWYG
# QYxKkIZ92Zhgtwty8RmVO/Qky1F2fn9KdYnGk5wKZ0ZBNl0B72vzSFjpbFZ0XojY
# rwT2qmfOVWmItKiZbsRdPxf1rG45WcvWKG8E/wKhoyt21H/GbYb09CFjc41X/d3b
# yM2C3IPPZICgofkfUTWpGM2eUk0pt6rq2MXXPwcss8AkyAtGnQMvYjOEqyh3rU7A
# ag8NXMicL1h8PCaKe6m5z19YFrdawama+cP7AlLjo2MnviSH2rFBMDdmDxLEcSgD
# HKBFUbWluaMMJBSalFGbcVRzii7gwVW4XC3CHLyhYQ/zWz7KdbPw+x9IP4/JVWRC
# WfRhOMAT8x8l+pWHihHKwjZJNWWfIPD1Yv0xRctSSoMHiQktphIkozEg+ckTTduG
# tmI62EzPwyhvtWvKrCmqLVrKQFGLe3qAWRZtJ8APM5IgkEqpnGm5Nhc6ptBZzsuh
# GvmEmlyXxOXJ8LnQzqN56RsmT5oqt1ffB7YQhePmg34j7+hfBBYRxzmys4/Csi8W
# UAW7MuVoX4QxJHdyBMI7DrTw37AEpv96QAND5oJl94C8/NfoDoEW9g7l9b6LnE8I
# s1mXbChTjDURZ326clhQ7VQ=
# SIG # End signature block