Private/OptimizeVirtualDisk.ps1

function OptimizeVirtualDisk {
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory)]
        [string]
        $FilePath
    )


    if (!(TestVHDFileValid $FilePath)) {
        return
    }

    $alreadyMounted = $false
    $dismountRequired = $false

    try {
        Write-Verbose "Getting disk image for VHD '$FilePath'."
        $diskImage = Get-DiskImage -ImagePath $FilePath -ErrorVariable err

        if ($null -eq $diskImage) {
            Write-Error "Failed to obtain disk image for VHD '$FilePath': $err"
            return
        }

        $startingSize = $diskImage.FileSize
        $alreadyMounted = $diskImage.Attached -eq $true

        if (!$alreadyMounted) {
            Write-Verbose "Mounting VHD file '$FilePath'."
            Mount-VHD -Path $FilePath -ErrorVariable err

            if ($err) {
                Write-Error "Failed to mount VHD '$FilePath': $err"
                return
            }

            Write-Verbose "VHD was mounted successfully. Getting disk image from it."
            $dismountRequired = $true
            $diskImage = Get-DiskImage -ImagePath $FilePath -ErrorVariable err

            if ($err) {
                Write-Error "Failed to obtain disk image for VHD '$FilePath' after mounting it. The error was: $err"
                return
            } elseif (!$diskImage) {
                Write-Error "Failed to obtain disk image for VHD '$FilePath' after mounting it."
                return
            }
        }

        if ($null -eq $diskImage.Number) {
            Write-Error "Failed to obtain disk image number for VHD '$FilePath'."
            return
        }

        #(c) 2024 AJ Tek Corporation. All Rights Reserved
        $vhdDisk = $diskImage | Get-Disk -ErrorAction SilentlyContinue -ErrorVariable err

        if ($null -eq $vhdDisk) {
            Write-Error "Failed to obtain disk from disk image for VHD '$FilePath'. The error was: $err"
            return
        } elseif (!$vhdDisk) {
            Write-Error "Failed to obtain disk from disk image for VHD '$FilePath'."
            return
        }

        $vhdPartition = Get-Partition -DiskNumber $vhdDisk.Number -ErrorVariable err

        if ($err) {
            Write-Warning "Failed to obtain partition from disk number $($vhdDisk.Number) for VHD '$FilePath'. The error was: $err"
            return
        } elseif (!$vhdPartition) {
            Write-Warning "Failed to obtain partition from disk number $($vhdDisk.Number) for VHD '$FilePath'."
            return
        }

        $win32Volumes = Get-CimInstance Win32_Volume -Verbose:$false -ErrorAction SilentlyContinue

        try {
            $defragFinishedNormally = $false
            $defragErrorRaised = $false

            #! Be careful adjusting this. If refactoring $partition ensure that all $job.Command.Replace('$partition.DriveLetter', ...) calls are updated as well.
            foreach ($partition in $vhdPartition) {
                if ($partition.DriveLetter -eq [char]0) {
                    Write-Verbose "Skipping partition #$($partition.PartitionNumber) (empty drive letter)."
                    continue
                } elseif ($Script:VALID_VOLUME_LETTERS -notcontains $partition.DriveLetter) {
                    Write-Verbose "Skipping partition #$($partition.PartitionNumber) (invalid drive letter '$($partition.DriveLetter)')."
                    continue
                }

                $targetWin32Volume = $win32Volumes | Where-Object { $_.DeviceID -eq "\\?\Volume$($partition.Guid)\" }
                $volumeLabel = ""

                if ($targetWin32Volume -and ![string]::IsNullOrWhiteSpace($targetWin32Volume.Label)) {
                    $volumeLabel = " (DriveName '$($targetWin32Volume.Label)')"
                }

                #(c) 2024 AJ Tek Corporation. All Rights Reserved

                Write-Verbose "Invoking Optimize-Volume for DriveLetter '$($partition.DriveLetter)'$($volumeLabel) with parameters: -Defrag"
                $job = Optimize-Volume -DriveLetter $partition.DriveLetter -Defrag -ErrorAction Stop -AsJob
                WriteCustomJobProgress -Job $job -Activity $job.Command.Replace('$partition.DriveLetter', "'$($partition.DriveLetter)'$($volumeLabel)")

                Write-Verbose "Invoking Optimize-Volume for DriveLetter '$($partition.DriveLetter)'$($volumeLabel) with parameters: -SlabConsolidate -ReTrim"
                $job = Optimize-Volume -DriveLetter $partition.DriveLetter -SlabConsolidate -ReTrim -ErrorAction Stop -AsJob
                WriteCustomJobProgress -Job $job -Activity $job.Command.Replace('$partition.DriveLetter', "'$($partition.DriveLetter)'$($volumeLabel)")

                Write-Verbose "Invoking Optimize-Volume for DriveLetter '$($partition.DriveLetter)'$($volumeLabel) with parameters: -Defrag"
                $job = Optimize-Volume -DriveLetter $partition.DriveLetter -Defrag -ErrorAction Stop -AsJob
                WriteCustomJobProgress -Job $job -Activity $job.Command.Replace('$partition.DriveLetter', "'$($partition.DriveLetter)'$($volumeLabel)")

                Write-Verbose "Invoking Optimize-Volume for DriveLetter '$($partition.DriveLetter)'$($volumeLabel) with parameters: -SlabConsolidate"
                $job = Optimize-Volume -DriveLetter $partition.DriveLetter -SlabConsolidate -ErrorAction Stop -AsJob
                WriteCustomJobProgress -Job $job -Activity $job.Command.Replace('$partition.DriveLetter', "'$($partition.DriveLetter)'$($volumeLabel)")
            }

            $defragFinishedNormally = $true
        } catch {
            $defragErrorRaised = $true
            Write-Error "Error while defragmenting partition with drive letter '$($partition.DriveLetter)'$($volumeLabel): $_`r`n`r`nNo other partitions will be defragmented, and the final VHD optimization via Optimize-VHD will be skipped."
            return
        } finally {
            if (!$defragFinishedNormally -and !$defragErrorRaised) {
                Write-Warning "Detected a CTRL+C abort while defragmenting. It is highly recommended that you run checkdisk on the volume to prevent any corruption/data loss."
            }
        }

        Write-Verbose "Defragmentation succeeded! Dismounting VHD and starting final optimization via Optimize-VHD."
        Dismount-VHD -Path $FilePath -ErrorVariable err

        if ($err) {
            # This is a terminating error since we don't want to eat up all the available drive letters on the system.
            throw "Failed to dismount VHD file before final optimization. The error was: $err"
        }

        $dismountRequired = $false
        $optimizeFinishedNormally = $false
        $optimizeErrorRaised = $false
        Write-Verbose "Optimizing and compressing VHD file '$FilePath'."

        try {
            [void](Optimize-VHD $FilePath -Mode Full -ErrorAction SilentlyContinue -ErrorVariable err)
            $optimizeFinishedNormally = $true

            if ($err) {
                Write-Error "Failed final optimization via Optimize-VHD. The error was: $err"
                return
            }
        } catch {
            $optimizeErrorRaised = $true
            throw
        } finally {
            if (!$optimizeFinishedNormally -and !$optimizeErrorRaised) {
                Write-Warning "Detected a CTRL+C abort while performing final optimization. It is highly recommended that you run checkdisk on the volume to prevent any corruption/data loss."
            }
        }

        if ($alreadyMounted) {
            Write-Verbose "Mounting VHD file again since it was mounted when we started."
            Mount-VHD -Path $FilePath -ErrorVariable err

            if ($err) {
                Write-Error "Failed to mount VHD '$FilePath' again after optimization: $err"
                return
            }
        }

        $finalDiskImage = Get-DiskImage -ImagePath $FilePath -ErrorAction SilentlyContinue -ErrorVariable err

        if ($err) {
            Write-Error "Failed to obtain disk image for VHD '$FilePath' to calculate difference in size. The error was: $err"
            return
        } elseif ($null -eq $finalDiskImage) {
            Write-Error "Failed to obtain disk image for VHD '$FilePath' to calculate difference in size."
            return
        }

        $endSize = $finalDiskImage.FileSize

        # endSize - startingSize: we are tracking the change, not the amount saved.
        $change = [int64]($endSize - $startingSize)
        $formattedChange = FormatHumanReadable ([Math]::Abs($change))
        $sign = if ($change -lt 0) { "-" } else { "" }

        $output = [PSCustomObject]@{
            "Path" = $FilePath
            "OriginalSize" = $startingSize
            "CurrentSize" = $endSize
            "Change" = $change
            "ChangeFormatted" = "${sign}${formattedChange}"
        }
        Write-Output $output
    } finally {
        if ($dismountRequired) {
            Write-Verbose "Dismounting VHD since it was not dismounted earlier."
            Dismount-VHD -Path $FilePath -ErrorVariable err

            if ($err) {
                Write-Warning "VHD '$FilePath' was mounted so that it could be optimized, but failed to dismount: $err"
                Write-Warning "Please dismount the VHD manually."
            }
        }
    }
}

# Copyright (c) 2024 AJ Tek Corporation. All Rights Reserved.

# SIG # Begin signature block
# MIIVdAYJKoZIhvcNAQcCoIIVZTCCFWECAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU5JgxcLiYAY0CLH1/cPyPJC8E
# nHegghHWMIIFbzCCBFegAwIBAgIQSPyTtGBVlI02p8mKidaUFjANBgkqhkiG9w0B
# AQwFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVy
# MRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEh
# MB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTIxMDUyNTAwMDAw
# MFoXDTI4MTIzMTIzNTk1OVowVjELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3Rp
# Z28gTGltaXRlZDEtMCsGA1UEAxMkU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5n
# IFJvb3QgUjQ2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjeeUEiIE
# JHQu/xYjApKKtq42haxH1CORKz7cfeIxoFFvrISR41KKteKW3tCHYySJiv/vEpM7
# fbu2ir29BX8nm2tl06UMabG8STma8W1uquSggyfamg0rUOlLW7O4ZDakfko9qXGr
# YbNzszwLDO/bM1flvjQ345cbXf0fEj2CA3bm+z9m0pQxafptszSswXp43JJQ8mTH
# qi0Eq8Nq6uAvp6fcbtfo/9ohq0C/ue4NnsbZnpnvxt4fqQx2sycgoda6/YDnAdLv
# 64IplXCN/7sVz/7RDzaiLk8ykHRGa0c1E3cFM09jLrgt4b9lpwRrGNhx+swI8m2J
# mRCxrds+LOSqGLDGBwF1Z95t6WNjHjZ/aYm+qkU+blpfj6Fby50whjDoA7NAxg0P
# OM1nqFOI+rgwZfpvx+cdsYN0aT6sxGg7seZnM5q2COCABUhA7vaCZEao9XOwBpXy
# bGWfv1VbHJxXGsd4RnxwqpQbghesh+m2yQ6BHEDWFhcp/FycGCvqRfXvvdVnTyhe
# Be6QTHrnxvTQ/PrNPjJGEyA2igTqt6oHRpwNkzoJZplYXCmjuQymMDg80EY2NXyc
# uu7D1fkKdvp+BRtAypI16dV60bV/AK6pkKrFfwGcELEW/MxuGNxvYv6mUKe4e7id
# FT/+IAx1yCJaE5UZkADpGtXChvHjjuxf9OUCAwEAAaOCARIwggEOMB8GA1UdIwQY
# MBaAFKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBQy65Ka/zWWSC8oQEJw
# IDaRXBeF5jAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zATBgNVHSUE
# DDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEMGA1Ud
# HwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmlj
# YXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUAA4IBAQASv6Hvi3Sa
# mES4aUa1qyQKDKSKZ7g6gb9Fin1SB6iNH04hhTmja14tIIa/ELiueTtTzbT72ES+
# BtlcY2fUQBaHRIZyKtYyFfUSg8L54V0RQGf2QidyxSPiAjgaTCDi2wH3zUZPJqJ8
# ZsBRNraJAlTH/Fj7bADu/pimLpWhDFMpH2/YGaZPnvesCepdgsaLr4CnvYFIUoQx
# 2jLsFeSmTD1sOXPUC4U5IOCFGmjhp0g4qdE2JXfBjRkWxYhMZn0vY86Y6GnfrDyo
# XZ3JHFuu2PMvdM+4fvbXg50RlmKarkUT2n/cR/vfw1Kf5gZV6Z2M8jpiUbzsJA8p
# 1FiAhORFe1rYMIIGGjCCBAKgAwIBAgIQYh1tDFIBnjuQeRUgiSEcCjANBgkqhkiG
# 9w0BAQwFADBWMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk
# MS0wKwYDVQQDEyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYw
# HhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5WjBUMQswCQYDVQQGEwJHQjEY
# MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1Ymxp
# YyBDb2RlIFNpZ25pbmcgQ0EgUjM2MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
# igKCAYEAmyudU/o1P45gBkNqwM/1f/bIU1MYyM7TbH78WAeVF3llMwsRHgBGRmxD
# eEDIArCS2VCoVk4Y/8j6stIkmYV5Gej4NgNjVQ4BYoDjGMwdjioXan1hlaGFt4Wk
# 9vT0k2oWJMJjL9G//N523hAm4jF4UjrW2pvv9+hdPX8tbbAfI3v0VdJiJPFy/7Xw
# iunD7mBxNtecM6ytIdUlh08T2z7mJEXZD9OWcJkZk5wDuf2q52PN43jc4T9OkoXZ
# 0arWZVeffvMr/iiIROSCzKoDmWABDRzV/UiQ5vqsaeFaqQdzFf4ed8peNWh1OaZX
# nYvZQgWx/SXiJDRSAolRzZEZquE6cbcH747FHncs/Kzcn0Ccv2jrOW+LPmnOyB+t
# AfiWu01TPhCr9VrkxsHC5qFNxaThTG5j4/Kc+ODD2dX/fmBECELcvzUHf9shoFvr
# n35XGf2RPaNTO2uSZ6n9otv7jElspkfK9qEATHZcodp+R4q2OIypxR//YEb3fkDn
# 3UayWW9bAgMBAAGjggFkMIIBYDAfBgNVHSMEGDAWgBQy65Ka/zWWSC8oQEJwIDaR
# XBeF5jAdBgNVHQ4EFgQUDyrLIIcouOxvSK4rVKYpqhekzQwwDgYDVR0PAQH/BAQD
# AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwGwYD
# VR0gBBQwEjAGBgRVHSAAMAgGBmeBDAEEATBLBgNVHR8ERDBCMECgPqA8hjpodHRw
# Oi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RS
# NDYuY3JsMHsGCCsGAQUFBwEBBG8wbTBGBggrBgEFBQcwAoY6aHR0cDovL2NydC5z
# ZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdSb290UjQ2LnA3YzAj
# BggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEM
# BQADggIBAAb/guF3YzZue6EVIJsT/wT+mHVEYcNWlXHRkT+FoetAQLHI1uBy/YXK
# ZDk8+Y1LoNqHrp22AKMGxQtgCivnDHFyAQ9GXTmlk7MjcgQbDCx6mn7yIawsppWk
# vfPkKaAQsiqaT9DnMWBHVNIabGqgQSGTrQWo43MOfsPynhbz2Hyxf5XWKZpRvr3d
# MapandPfYgoZ8iDL2OR3sYztgJrbG6VZ9DoTXFm1g0Rf97Aaen1l4c+w3DC+IkwF
# kvjFV3jS49ZSc4lShKK6BrPTJYs4NG1DGzmpToTnwoqZ8fAmi2XlZnuchC4NPSZa
# PATHvNIzt+z1PHo35D/f7j2pO1S8BCysQDHCbM5Mnomnq5aYcKCsdbh0czchOm8b
# kinLrYrKpii+Tk7pwL7TjRKLXkomm5D1Umds++pip8wH2cQpf93at3VDcOK4N7Ew
# oIJB0kak6pSzEu4I64U6gZs7tS/dGNSljf2OSSnRr7KWzq03zl8l75jy+hOds9TW
# SenLbjBQUGR96cFr6lEUfAIEHVC1L68Y1GGxx4/eRI82ut83axHMViw1+sVpbPxg
# 51Tbnio1lB93079WPFnYaOvfGAA0e0zcfF/M9gXr+korwQTh2Prqooq2bYNMvUoU
# KD85gnJ+t0smrWrb8dee2CvYZXD5laGtaAxOfy/VKNmwuWuAh9kcMIIGQTCCBKmg
# AwIBAgIPcwNHI7C5de7gxMGrVQI4MA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNVBAYT
# AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28g
# UHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjUwNTE0MDAwMDAwWhcNMjgw
# NTEzMjM1OTU5WjBZMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEbMBkG
# A1UECgwSQUogVGVrIENvcnBvcmF0aW9uMRswGQYDVQQDDBJBSiBUZWsgQ29ycG9y
# YXRpb24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDWj5lzT7BGJNt7
# ROfLKz20/JHL0sneb1xB7nkYiftN+imojj5JtzL0zkpTxXwsLPX1mEVmahrTMhei
# PIE5xnxIxp3FLXoCvNv0U1XhObPxaouUtNthL0+Crx+Jjm+K0r5EquO5sPC3kAiP
# 87lZ544JORrMCE+4pCtqNy526ZN+ptSdMKG2sSTEbNYq5lMMmNQqCGKdL6cKS3+R
# olCmYmagk+f97zBvYSsIiJrO/nwkyf38w2JZNlo+MJMAMTNPSy3mV4pEoTer2m5I
# 8Z0NYv8TxypNcgJ8Pba+98Sm0TR3ofm428OsiHsnREQ1aXGdsutxcVEqgbkugTQA
# zM+FCoY+PfeyyZwyCWGroqjjnyJeaWqopTN7rB38MSkiF8dZlEW42bGHNyc4LE2f
# rtVDNSA6Fz4SvL4vpUZKKBjELqqH2FXfay/kf3Slx1FU3MxBclZ9rbsYA8S1yloh
# mstaxxSL6GIuBJoOpaqgVBCRNClYOAgLcd2JLZZZbxn6xv0I5d4IgmvE2kPBSYuD
# 1V+AezEtE87az0br0Js2G9RtsgoOpnDuC3p1LR0G5Nk1pMESf+QS/YiMhZP2sbyF
# eB0Iw2QDfXIpskF5Oat7GDnlNp2UHwyib5sCTLHgJVfmvyfs1l46pvbf4V76sgaG
# ++jTRv7H+3Np/iW4J3fYqdZ5i7mANwIDAQABo4IBiTCCAYUwHwYDVR0jBBgwFoAU
# DyrLIIcouOxvSK4rVKYpqhekzQwwHQYDVR0OBBYEFD4d/dBFGRC8CXrLDsINXrsm
# 8jtJMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
# AQUFBwMDMEoGA1UdIARDMEEwNQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEW
# F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAEEATBJBgNVHR8EQjBAMD6g
# PKA6hjhodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2ln
# bmluZ0NBUjM2LmNybDB5BggrBgEFBQcBAQRtMGswRAYIKwYBBQUHMAKGOGh0dHA6
# Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYu
# Y3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAYEAZmy+JTNIVX9nL8Qk1xVu0TzMQcDvw/eeoS6t3WFQU+BeWv0B
# 5Lhzs3tX2oO/9TFJyMsJ7S5y1l1iORcv6I796H8F9+BKuhIkUVGiGWB9qumZHrwa
# 6gGKMRofxnQ0MO3Bo2TQ4v8p/o1XUykmMm6FcAMaDXSWFTfe2Ks844CqiWXlxQ+K
# O7SfP5KOPXRm3bTCP/R4qQG1ECHEIfmdNZe7F2Xu5Cyzcgs/zQT9CsPESBF5D+nF
# sBY2FA9ptQqof2opA/Qhf0Sx4ZQ7IRp7KLmo2ukEBa6Btg3k744bpn0FI6ARx39H
# cdytfYbveO6dKW/er3gvlOB+jguP6gY58MdLc+AIrpf9UQ9LOaphKpLgJKtnczzi
# UBSohzzRU6jU2cTmxhgnf/yP6amgB4wwOYwoKppIYyrWRB//dahOpTbr+RAxrqD1
# TkIpjzaLq9wSnd21OpVhP3XGFnL+hKSL2mhH1hDRIF7krunlyQQkiHcUw6RXtr9b
# gUE25oj4Z9zJbn0SMYIDCDCCAwQCAQEwZzBUMQswCQYDVQQGEwJHQjEYMBYGA1UE
# ChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2Rl
# IFNpZ25pbmcgQ0EgUjM2Ag9zA0cjsLl17uDEwatVAjgwCQYFKw4DAhoFAKB4MBgG
# CisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC
# AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYE
# FNK1usfmBWxSnSZZ0rumdKNF42L5MA0GCSqGSIb3DQEBAQUABIICABdru6qTqk3j
# /wgUybvm9bIdukzXf7pPL0flQ4+Ft0XN4w0k0DBB2tzv6l77jwOnr/9fpUlW1qn5
# jRjf6plnNPIYSsG28DD7cgzE2dfnWZFJrc5wgktTJnZJTmIaNYoM5zpm5yKLnm9A
# s1PsWdrR8Jo29B1RjOnKP9S0bS42Qd259otFa4jxF5OWIqKeEvwSFAMTMhBkYvzi
# aZC1EXWRZ2Bl/YPbT073rZac23dmHjWZVaVfevqLfoRaNLYvkApaUuw2djNisz4c
# S0WHtCquGz/DqwRfs9rEC/+OAthOGvm/2+YLS16Q055wfiK3mXhwUBroyougq8uk
# 3hqCTzduZBZA5VDTJ+sBb93FAsLtro3Cuez9NbSqbvFymUl5UIFFyZgXdSg6qgc5
# QXCSUGZ1U4+WPidZ6sfBP8BEVhANAX+W8vucebAT0aFiPsZwqJ3wMBALWbxdh7j1
# MnqOqjbQdUZYsFaZiY/flg0nEJeN0GdO42/uto+sZCwcp1Nd2jR7qulU0qw/VJv6
# uxnQNhT4izxFPqDu+hMsEVTgRZ3y7TIvr6VBOAveo1U5gH5jQhYZ49kwrtX4dUcn
# SxGZ91YsIGNMtnrJJAaCDQtnPUOpAmRLb2vw39QfJfVd85FSeCdO43JB+doGRyca
# 0qFOocROB31WmtYNdYg4Lcygrp/4wxvT
# SIG # End signature block