Lib/Internal.ps1
function NewDirectory { <# .SYNOPSIS Creates a filesystem directory. .DESCRIPTION The New-Directory cmdlet will create the target directory if it doesn't already exist. If the target path already exists, the cmdlet does nothing. #> [CmdletBinding(DefaultParameterSetName = 'ByString', SupportsShouldProcess)] [OutputType([System.IO.DirectoryInfo])] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess','')] param ( # Target filesystem directory to create [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'ByDirectoryInfo')] [ValidateNotNullOrEmpty()] [System.IO.DirectoryInfo[]] $InputObject, # Target filesystem directory to create [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'ByString')] [ValidateNotNullOrEmpty()] [Alias('PSPath')] [System.String[]] $Path ) process { Write-Debug -Message ("Using parameter set '{0}'." -f $PSCmdlet.ParameterSetName); switch ($PSCmdlet.ParameterSetName) { 'ByString' { foreach ($directory in $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)) { Write-Debug -Message ("Testing target directory '{0}'." -f $directory); if (!(Test-Path -Path $directory -PathType Container)) { if ($PSCmdlet.ShouldProcess($directory, "Create directory")) { WriteVerbose ($localized.CreatingDirectory -f $directory); New-Item -Path $directory -ItemType Directory; } } else { Write-Debug -Message ($localized.DirectoryExists -f $directory); Get-Item -Path $directory; } } #end foreach directory } #end byString 'ByDirectoryInfo' { foreach ($directoryInfo in $InputObject) { Write-Debug -Message ("Testing target directory '{0}'." -f $directoryInfo.FullName); if (!($directoryInfo.Exists)) { if ($PSCmdlet.ShouldProcess($directoryInfo.FullName, "Create directory")) { WriteVerbose ($localized.CreatingDirectory -f $directoryInfo.FullName); New-Item -Path $directoryInfo.FullName -ItemType Directory; } } else { Write-Debug -Message ($localized.DirectoryExists -f $directoryInfo.FullName); $directoryInfo; } } #end foreach directoryInfo } #end byDirectoryInfo } #end switch } #end process } #end function NewDirectory function ResolvePathEx { <# .SYNOPSIS Resolves the wildcard characters in a path, and displays the path contents, ignoring non-existent paths. .DESCRIPTION The Resolve-Path cmdlet interprets the wildcard characters in a path and displays the items and containers at the location specified by the path, such as the files and folders or registry keys and subkeys. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory)] [System.String] $Path ) process { try { $expandedPath = [System.Environment]::ExpandEnvironmentVariables($Path); $resolvedPath = Resolve-Path -Path $expandedPath -ErrorAction Stop; $Path = $resolvedPath.ProviderPath; } catch [System.Management.Automation.ItemNotFoundException] { $Path = [System.Environment]::ExpandEnvironmentVariables($_.TargetObject); $Error.Remove($Error[-1]); } return $Path; } #end process } #end function ResolvePathEx function InvokeExecutable { <# .SYNOPSIS Runs an executable and redirects StdOut and StdErr. #> [CmdletBinding()] [OutputType([System.Int32])] param ( # Executable path [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [System.String] $Path, # Executable arguments [Parameter(Mandatory)] [ValidateNotNull()] [System.Array] $Arguments, # Redirected StdOut and StdErr log name [Parameter()] [ValidateNotNullOrEmpty()] [System.String] $LogName = ('{0}.log' -f $Path) ) process { $processArgs = @{ FilePath = $Path; ArgumentList = $Arguments; Wait = $true; RedirectStandardOutput = '{0}\{1}-StdOut.log' -f $env:temp, $LogName; RedirectStandardError = '{0}\{1}-StdErr.log' -f $env:temp, $LogName; NoNewWindow = $true; PassThru = $true; } Write-Debug -Message ($localized.RedirectingOutput -f 'StdOut', $processArgs.RedirectStandardOutput); Write-Debug -Message ($localized.RedirectingOutput -f 'StdErr', $processArgs.RedirectStandardError); WriteVerbose ($localized.StartingProcess -f $Path, [System.String]::Join(' ', $Arguments)); $process = Start-Process @processArgs; if ($process.ExitCode -ne 0) { WriteWarning ($localized.ProcessExitCode -f $Path, $process.ExitCode) } else { WriteVerbose ($localized.ProcessExitCode -f $Path, $process.ExitCode); } ##TODO: Should this actually return the exit code?! } #end process } #end function InvokeExecutable function GetFormattedMessage { <# .SYNOPSIS Generates a formatted output message. #> [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [System.String] $Message ) process { if (($labDefaults.CallStackLogging) -and ($labDefaults.CallStackLogging -eq $true)) { $parentCallStack = (Get-PSCallStack)[1]; # store the parent Call Stack $functionName = $parentCallStack.FunctionName; $lineNumber = $parentCallStack.ScriptLineNumber; $scriptName = ($parentCallStack.Location -split ':')[0]; $formattedMessage = '[{0}] [Script:{1}] [Function:{2}] [Line:{3}] {4}' -f (Get-Date).ToLongTimeString(), $scriptName, $functionName, $lineNumber, $Message; } else { $formattedMessage = '[{0}] {1}' -f (Get-Date).ToLongTimeString(), $Message; } return $formattedMessage; } #end process } #end function GetFormattedMessage function WriteVerbose { <# .SYNOPSIS Wrapper around Write-Verbose that adds a timestamp and/or call stack information to the output. #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [AllowNull()] [System.String] $Message ) process { if (-not [System.String]::IsNullOrEmpty($Message)) { $verboseMessage = GetFormattedMessage -Message $Message; Write-Verbose -Message $verboseMessage; } } } #end function WriteVerbose function WriteWarning { <# .SYNOPSIS Wrapper around Write-Warning that adds a timestamp and/or call stack information to the output. #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [AllowNull()] [System.String] $Message ) process { if (-not [System.String]::IsNullOrEmpty($Message)) { $warningMessage = GetFormattedMessage -Message $Message; Write-Warning -Message $warningMessage; } } } #end function WriteWarning function ConvertPSObjectToHashtable { <# .SYNOPSIS Converts a PSCustomObject's properties to a hashtable. #> [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( ## Object to convert to a hashtable [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [System.Management.Automation.PSObject[]] $InputObject, ## Do not add empty/null values to the generated hashtable [Parameter(ValueFromPipelineByPropertyName)] [System.Management.Automation.SwitchParameter] $IgnoreNullValues ) process { foreach ($object in $InputObject) { $hashtable = @{ } foreach ($property in $object.PSObject.Properties) { if ($IgnoreNullValues) { if ([System.String]::IsNullOrEmpty($property.Value)) { ## Ignore empty strings continue; } } if ($property.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject') { ## Convert nested custom objects to hashtables $hashtable[$property.Name] = ConvertPSObjectToHashtable -InputObject $property.Value -IgnoreNullValues:$IgnoreNullValues; } else { $hashtable[$property.Name] = $property.Value; } } #end foreach property Write-Output $hashtable; } } #end proicess } #end function ConvertPSObjectToHashtable function CopyDirectory { <# .SYNOPSIS Copies a directory structure with progress. #> [CmdletBinding()] param ( ## Source directory path [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.IO.DirectoryInfo] $SourcePath, ## Destination directory path [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNull()] [System.IO.DirectoryInfo] $DestinationPath, [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNull()] [System.Management.Automation.SwitchParameter] $Force ) begin { if ((Get-Item $SourcePath) -isnot [System.IO.DirectoryInfo]) { throw ($localized.CannotProcessArguentError -f 'CopyDirectory', 'SourcePath', $SourcePath, 'System.IO.DirectoryInfo'); } elseif (Test-Path -Path $SourcePath -PathType Leaf) { throw ($localized.InvalidDestinationPathError -f $DestinationPath); } } process { $activity = $localized.CopyingResource -f $SourcePath.FullName, $DestinationPath; $status = $localized.EnumeratingPath -f $SourcePath; Write-Progress -Activity $activity -Status $status -PercentComplete 0; $fileList = Get-ChildItem -Path $SourcePath -File -Recurse; $currentDestinationPath = $SourcePath; for ($i = 0; $i -lt $fileList.Count; $i++) { if ($currentDestinationPath -ne $fileList[$i].DirectoryName) { ## We have a change of directory $destinationDirectoryName = $fileList[$i].DirectoryName.Substring($SourcePath.FullName.Trim('\').Length); $destinationDirectoryPath = Join-Path -Path $DestinationPath -ChildPath $destinationDirectoryName; [ref] $null = New-Item -Path $destinationDirectoryPath -ItemType Directory -ErrorAction Ignore; $currentDestinationPath = $fileList[$i].DirectoryName; } if (($i % 5) -eq 0) { [System.Int16] $percentComplete = (($i + 1) / $fileList.Count) * 100; $status = $localized.CopyingResourceStatus -f $i, $fileList.Count, $percentComplete; Write-Progress -Activity $activity -Status $status -PercentComplete $percentComplete; } $targetPath = Join-Path -Path $DestinationPath -ChildPath $fileList[$i].FullName.Replace($SourcePath, ''); Copy-Item -Path $fileList[$i].FullName -Destination $targetPath -Force:$Force; } #end for Write-Progress -Activity $activity -Completed; } #end process } #end function CopyDirectory function TestComputerName { <# .SYNOPSIS Validates a computer name is valid. #> [CmdletBinding()] [OutputType([System.Boolean])] param ( ## Source directory path [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] [System.String] $ComputerName ) process { $invalidMatch = '[~!@#\$%\^&\*\(\)=\+_\[\]{}\\\|;:.''",<>\/\?\s]'; return ($ComputerName -inotmatch $invalidMatch); } } #end function TestComputerName function ValidateTimeZone { <# .SYNOPSIS Validates a timezone string. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [System.String] $TimeZone ) process { try { $TZ = [TimeZoneInfo]::FindSystemTimeZoneById($TimeZone) return $TZ.StandardName; } catch [System.TimeZoneNotFoundException] { throw $_; } } #end process } #end function ValidateTimeZone function ResolveProgramFilesFolder { <# .SYNOPSIS Resolves known localized %ProgramFiles% directories. .LINK https://en.wikipedia.org/wiki/Program_Files #> [CmdletBinding(DefaultParameterSetName = 'Path')] [OutputType([System.IO.DirectoryInfo])] param ( ## Root path to check [Parameter(Mandatory, ParameterSetName = 'Path')] [ValidateNotNullOrEmpty()] [System.String] $Path, ## Drive letter [Parameter(Mandatory, ParameterSetName = 'Drive')] [ValidateLength(1,1)] [System.String] $Drive ) begin { if ($PSCmdlet.ParameterSetName -eq 'Drive') { $Path = '{0}:\' -f $Drive; } } process { $knownFolderNames = @( "Program Files", "Programmes", "Archivos de programa", "Programme", "Programfájlok", "Programmi", "Programmer", "Program", "Programfiler", "Arquivos de Programas", "Programas" "Αρχεία Εφαρμογών" ) Get-ChildItem -Path $Path -Directory | Where-Object Name -in $knownFolderNames | Select-Object -First 1; } #end process } #end function ResolveProgramFilesFolder # SIG # Begin signature block # MIIXtwYJKoZIhvcNAQcCoIIXqDCCF6QCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQULb/3qJR4y3M2cE7xP76bmIXe # bnCgghLqMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B # AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG # A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh # d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg # Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV # UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu # dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q # WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC # i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4 # ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3 # +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI # fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd # BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG # CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB # Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro # YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV # HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y # MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf # plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y # 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq # IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3 # DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh # dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD # QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE # BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT # eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow # mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0 # jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu # ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh # d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz # C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB # o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO # BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw # Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90 # cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx # oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy # bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV # HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa # 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH # bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73 # BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR # EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW # yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu # e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw # ggUZMIIEAaADAgECAhADViTO4HBjoJNSwH9//cwJMA0GCSqGSIb3DQEBCwUAMHIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ # RCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTUwNTE5MDAwMDAwWhcNMTcwODIzMTIwMDAw # WjBgMQswCQYDVQQGEwJHQjEPMA0GA1UEBxMGT3hmb3JkMR8wHQYDVQQKExZWaXJ0 # dWFsIEVuZ2luZSBMaW1pdGVkMR8wHQYDVQQDExZWaXJ0dWFsIEVuZ2luZSBMaW1p # dGVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqLQmabdimcQtYPTQ # 9RSjv3ThEmFTRJt/MzseYYtZpBTcR6BnSfj8RfkC4aGZvspFgH0cGP/SNJh1w67b # iX9oT5NFL9sUJHUsVdyPBA1LhpWcF09PP28mGGKO3oQHI4hTLD8etiIlF9qFantd # 1Pmo0jdqT4uErSmx0m4kYGUUTa5ZPAK0UZSuAiNX6iNIL+rj/BPbI3nuPJzzx438 # oHYkZGRtsx11+pLA6hIKyUzRuIDoI7JQ0nZ0MkCziVyc6xGfS54JVLaVCEteTKPz # Gc4yyvCqp6Tfe9gs8UuxJiEMdH5fvllTU4aoXbm+W8tonkE7i/19rv8S1A2VPiVV # xNLbpwIDAQABo4IBuzCCAbcwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1 # DlgwHQYDVR0OBBYEFP2RNOWYipdNCSRVb5jIcyRp9tUDMA4GA1UdDwEB/wQEAwIH # gDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYv # aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmww # QgYDVR0gBDswOTA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 # d3cuZGlnaWNlcnQuY29tL0NQUzCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2ln # bmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCclXHR # DhDyJr81eiD0x+AL04ryDwdKT+PooKYgOxc7EhRn59ogxNO7jApQPSVo0I11Zfm6 # zQ6K6RPWhxDenflf2vMx7a0tIZlpHhq2F8praAMykK7THA9F3AUxIb/lWHGZCock # yD/GQvJek3LSC5NjkwQbnubWYF/XZTDzX/mJGU2DcG1OGameffR1V3xODHcUE/K3 # PWy1bzixwbQCQA96GKNCWow4/mEW31cupHHSo+XVxmjTAoC93yllE9f4Kdv6F29H # bRk0Go8Yn8WjWeLE/htxW/8ruIj0KnWkG+YwmZD+nTegYU6RvAV9HbJJYUEIfhVy # 3DeK5OlY9ima2sdtMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkq # hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB # c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAw # WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL # ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy # ZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB # CgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6 # kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQj # ZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5w # MWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp # 6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH # 5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgw # BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYI # KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6 # Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww # OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ # RFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUH # AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYD # VR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuC # MS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2 # qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4Q # pO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEp # KBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/Dm # ZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9 # CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHv # MYIENzCCBDMCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNl # cnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQA1YkzuBwY6CTUsB/ # f/3MCTAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkq # hkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGC # NwIBFTAjBgkqhkiG9w0BCQQxFgQUWU6FoPDPWKWl5f6oTrGR/TtT/fkwDQYJKoZI # hvcNAQEBBQAEggEAoMpODFg1MzLVBQZmI1AmxHC1BLRrIBp4d/kObMgUIwQTBQyi # c2QmcNdQaDLvhzMuqMc6GOIAsqVVK3krHKtxhB4KGWc5SYyRqB5RhaOy9pZQcR/O # FHMLKGVpYw6LGY712hnKiFgYKuY89nMVtL6pZUDrO6Mes8l792mwQJTCQ846lLss # iFZ8NlZSchzZcL/pTP38wRsnwnrDDesQ5n4PBFV12NWF3h9Lviui142gSVXRzCva # BWgi71Yj3tMdLBxksjbe+ct9CWgvmOC3vLBMVPKY+eWk/GiiQbzODnWK513pE6He # qqJaj6KcZzbT/32IAjgTeSUkbghWg4OhTjMMRqGCAgswggIHBgkqhkiG9w0BCQYx # ggH4MIIB9AIBATByMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBD # b3Jwb3JhdGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2 # aWNlcyBDQSAtIEcyAhAOz/Q4yP6/NW4E2GqYGxpQMAkGBSsOAwIaBQCgXTAYBgkq # hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNzAzMTIyMTAz # MzZaMCMGCSqGSIb3DQEJBDEWBBQw2+9gEjiKSRpwT1AAwSppsVArDjANBgkqhkiG # 9w0BAQEFAASCAQAnez4d04NWg1rRURt25IeX018GOFtWLn9andIybaLDI7TDpJ3r # IDln1Nxi/5UXqYHUingNnSY51XGW0qe5SW/m2jB8NBokFq1UzmE4JK2oQHo7FBjR # X3q2R0ZidOlV46qimFZ9LbqvxthTD7HVVYSOJ8kTYU/GgfAJ3hnTnlAxB//tyIVR # JzKxNAKxCV7IdKYKAKO8BDwJ5UYJJvaSQjqGqiO1EoJZFzhE/HTs0NkgiB4W80nX # XViRcR5l8wJu4dKfr3f6DZ5DC3YhARFlqE6TCYZ86JkOXDg92Rha3N4EZ5lnW7lt # eacfwV3SNgz6EdD2N6FaMWiiMKxtluTCZ4pW # SIG # End signature block |