PsFCIV.psm1
#region helper functions # internal function which reads the XML file (if exist). function __readXml ($xml) { # reading existing XML file and selecting required properties if (!(Test-Path -LiteralPath $XML)) { New-Object PsFCIV.Support.FcivRootNode return } try { [PsFCIV.Support.FcivRootNode]::ReadFromFile($XML) } catch { __finalize Write-Error -Category InvalidData -Message "Input XML file is not valid FCIV XML file." -ErrorAction Stop } } # internal xml writer function __writeXml ($root) { if ($root.Entries.Count -eq 0) { Write-Verbose "There is no data to write to XML database." Write-Debug "There is no data to write to XML database." } else { Write-Debug "Preparing to DataBase file creation..." $root.SaveToFile($XML) } } # lightweight proxy function for Get-ChildItem cmdlet function dirx ([string]$Path, [string]$Filter, [string[]]$Exclude, $Recurse, [switch]$Force) { Get-ChildItem @PSBoundParameters -File -ErrorAction SilentlyContinue } # internal function that will check whether the file is locked. All locked files are added to a group with 'Unknown' status. function __testFileLock ($file) { $locked = $false trap {Set-Variable -name locked -value $true -scope 1; continue} $inputStream = New-Object IO.StreamReader $file.FullName if ($inputStream) {$inputStream.Close()} if ($locked) { Write-Verbose "File $($file.Name) is locked. Skipping this file.." Write-Debug "File $($file.Name) is locked. Skipping this file.." __addStatCounter $filename Locked } $locked } # internal function to generate UI window with results by using Out-GridView cmdlet. function __showGridView ($props, $max) { $total = @($input) foreach ($property in $props) { $(for ($n = 0; $n -lt $max; $n++) { $total[0] | Select-Object @{n=$property; e={$_.$property[$n]}} }) | Out-GridView -Title "File list by category: $property" } } # internal function to create XML entry object for a file. function __newFileEntry ($file, [switch]$NoHash, [switch]$hex) { Write-Debug "Starting object creation for '$($file.FullName)'..." $object = New-Object PsFCIV.Support.FcivFileEntry $file $object.Name = $file.FullName -replace [regex]::Escape($($pwd.ProviderPath + "\")) if (!$NoHash) { # calculating appropriate hash and convert resulting byte array to a Base64 string foreach ($hash in "MD5", "SHA1", "SHA256", "SHA384", "SHA512") { if ($HashAlgorithm -contains $hash) { Write-Debug "Calculating '$hash' hash..." $hashBytes = [PsFCIV.Support.CryptUtils]::HashFile($file, $hash) if ($hex) { $object.$hash = [PsFCIV.Support.CryptUtils]::FormatBytes($hashBytes, "Hex") } else { Write-Debug ("Calculated hash value: " + (-join ($hashBytes | Foreach-Object {"{0:X2}" -f $_}))) $object.$hash = [PsFCIV.Support.CryptUtils]::FormatBytes($hashBytes, "Base64") } } } } Write-Debug "Object created!" $object } # internal function that calculates current file hash and formats it to an octet string (for example, B926D7416E8235E6F94F756E9F3AE2F33A92B2C4). function __selectHAlg ($entry, $file, $HashAlgorithm) { if ($HashAlgorithm.Length -gt 0) { $SelectedHash = $HashAlgorithm } else { :outer foreach ($hash in "SHA512", "SHA384", "SHA256", "SHA1", "MD5") { if ($entry.$hash) {$SelectedHash = $hash; break outer} } } $hex = [PsFCIV.Support.CryptUtils]::FormatBytes([PsFCIV.Support.CryptUtils]::HashFile($file, $SelectedHash), "Hex") Write-Debug "Selected hash name : $SelectedHash" Write-Debug "Selected hash value: $hex" New-Object psobject -Property @{ HashName = $SelectedHash HashValue = $hex } } # process -Action parameter to perform an action against bad file (if actual file properties do not match the record in XML). function __takeAction ($file, $Action) { switch ($Action) { "Rename" {Rename-Item $file $($file.FullName + ".bad")} "Delete" {Remove-Item $file -Force} } } # core file verification function. function __checkfiles ($entry, $file, $Action, $Strict) { if (__testFileLock $file) {return} if ($Strict -and (($file.Length -ne $entry.Size) -or ("$($file.LastWriteTime.ToUniversalTime())" -ne $entry.TimeStamp))) { Write-Verbose "File '$($file.FullName)' size or Modified Date/Time mismatch." Write-Debug "Expected file size is: $($entry.Size) byte(s), actual size is: $($file.Length) byte(s)." Write-Debug "Expected file modification time is: $($entry.TimeStamp), actual file modification time is: $($file.LastWriteTime.ToUniversalTime())" __addStatCounter $entry.Name Bad __takeAction $file $Action } else { $hexhash = __selectHAlg $entry $file $HashAlgorithm $ActualHash = [PsFCIV.Support.CryptUtils]::FormatBytes([Convert]::FromBase64String($entry.($hexhash.HashName)), "Hex") if (!$ActualHash) { Write-Verbose "XML database entry does not contain '$($hexhash.HashName)' hash value for the entry '$($entry.Name)'." __addStatCounter $entry.Name Unknown return } elseif ($ActualHash -eq $hexhash.HashValue) { Write-Debug "File hash: $ActualHash" Write-Verbose "File '$($file.Name)' is ok." __addStatCounter $entry.Name Ok return } else { Write-Debug "File '$($file.Name)' failed hash verification. Expected hash: $hexhash.HashValue Actual hash: $ActualHash" __addStatCounter $entry.Name Bad __takeAction $file $Action } } } function __finalize { # do nothing at this moment } #endregion #region global variables $oldpath = "" $stats = New-Object PsFCIV.Support.StatTable $statcount = New-Object PsFCIV.Support.IntStatTable #endregion # dot-source all function files Get-ChildItem -Path $PSScriptRoot -Include *.ps1 -Recurse -File | Foreach-Object { . $_.FullName } # SIG # Begin signature block # MIIcnwYJKoZIhvcNAQcCoIIckDCCHIwCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA2A/JW3zeasPK4 # Tssyx0/4JfFWo90t4aQ7+fFqbOMEYqCCFn4wggT+MIID5qADAgECAhANQkrgvjqI # /2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwHhcN # MjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQswCQYDVQQGEwJVUzEXMBUG # A1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFt # cCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwuZhhGfFivUN # CKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMlucaXEjvROW/m2HNFZFiWrj/ # ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofpir34hF0edsnkxnZ2OlPR # 0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG3JMjjfdQJehk5t3Tjy9X # tYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkUrxVfbENJCf0mI1P2jWPo # GqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y+tZji06lchzun3oBc/gZ # 1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQC # MAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0gBDowODA2BglghkgBhv1s # BwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB8G # A1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQWBBQ2RIaOpLqw # Zr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0cDovL2NybDQu # ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsGAQUFBwEBBHkw # dzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME8GCCsGAQUF # BzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNz # dXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBIHNy1 # 6ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUngaVNFBUZB3nw0QTDhtk7 # vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1DnnvntN1BIon7h6JGA078 # 9P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6e9oMvD0y0BvL9WH8dQgA # dryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0Uvtc4GEkJU+y38kpqHND # Udq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6nv1bPull2YYlffqe0jmd4 # +TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXaNpfCFTANBgkq # hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB # c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEwMTA3MTIwMDAw # WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL # ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy # ZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB # CgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1NaH7ntqD0jbOI # 5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vjRkcGGlV+Cyd+ # wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOoCXFr4M8iEA91 # z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe/WZuVmEnKYmE # UeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG7z3N1k3vBkL9 # olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYDVR0OBBYEFPS2 # 4SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3z # bcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQM # MAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8E # ejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 # cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v # RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcwOAYKYIZIAYb9 # bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT # MAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGHVmnN793afKpj # erN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqumfgnoma/Capg # 33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuByx5jWPGTlH0gQ # GF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraSZ/tTYYmo9WuW # wPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh5Fhgm7oMLStt # osR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2skuiSpXY9aaO # UjCCBfUwggPdoAMCAQICEB2iSDBvmyYY0ILgln0z02owDQYJKoZIhvcNAQEMBQAw # gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK # ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD # VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 # MTEwMjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowfDELMAkGA1UEBhMCR0IxGzAZBgNV # BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE # ChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdvIFJTQSBDb2RlIFNp # Z25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCGIo0yhXoY # n0nwli9jCB4t3HyfFM/jJrYlZilAhlRGdDFixRDtsocnppnLlTDAVvWkdcapDlBi # pVGREGrgS2Ku/fD4GKyn/+4uMyD6DBmJqGx7rQDDYaHcaWVtH24nlteXUYam9Cfl # fGqLlR5bYNV+1xaSnAAvaPeX7Wpyvjg7Y96Pv25MQV0SIAhZ6DnNj9LWzwa0VwW2 # TqE+V2sfmLzEYtYbC43HZhtKn52BxHJAteJf7wtF/6POF6YtVbC3sLxUap28jVZT # xvC6eVBJLPcDuf4vZTXyIuosB69G2flGHNyMfHEo8/6nxhTdVZFuihEN3wYklX0P # p6F8OtqGNWHTAgMBAAGjggFkMIIBYDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dib # wJ3ysgNmyzAdBgNVHQ4EFgQUDuE6qFM6MdWKvsG7rWcaA4WtNA4wDgYDVR0PAQH/ # BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwMG # CCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9o # dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlv # bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw # Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQw # JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN # AQEMBQADggIBAE1jUO1HNEphpNveaiqMm/EAAB4dYns61zLC9rPgY7P7YQCImhtt # EAcET7646ol4IusPRuzzRl5ARokS9At3WpwqQTr81vTr5/cVlTPDoYMot94v5JT3 # hTODLUpASL+awk9KsY8k9LOBN9O3ZLCmI2pZaFJCX/8E6+F0ZXkI9amT3mtxQJmW # unjxucjiwwgWsatjWsgVgG10Xkp1fqW4w2y1z99KeYdcx0BNYzX2MNPPtQoOCwR/ # oEuuu6Ol0IQAkz5TXTSlADVpbL6fICUQDRn7UJBhvjmPeo5N9p8OHv4HURJmgyYZ # SJXOSsnBf/M6BZv5b9+If8AjntIeQ3pFMcGcTanwWbJZGehqjSkEAnd8S0vNcL46 # slVaeD68u28DECV3FTSK+TbMQ5Lkuk/xYpMoJVcp+1EZx6ElQGqEV8aynbG8HAra # fGd+fS7pKEwYfsR7MUFxmksp7As9V1DSyt39ngVR5UR43QHesXWYDVQk/fBO4+L4 # g71yuss9Ou7wXheSaG3IYfmm8SoKC6W59J7umDIFhZ7r+YMp08Ysfb06dy6LN0Kg # aoLtO0qqlBCk4Q34F8W2WnkzGJLjtXX4oemOCiUe5B7xn1qHI/+fpFGe+zmAEc3b # tcSnqIBv5VPU4OOiwtJbGvoyJi1qV3AcPKRYLqPzW0sH3DJZ84enGm1YMIIGSjCC # BTKgAwIBAgIQF0FLo4fb8T/ESzcF/lyStzANBgkqhkiG9w0BAQsFADB8MQswCQYD # VQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdT # YWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxJDAiBgNVBAMTG1NlY3Rp # Z28gUlNBIENvZGUgU2lnbmluZyBDQTAeFw0xOTA4MTMwMDAwMDBaFw0yMjA4MTIy # MzU5NTlaMIGZMQswCQYDVQQGEwJVUzEOMAwGA1UEEQwFOTcyMTkxDzANBgNVBAgM # Bk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxHDAaBgNVBAkMEzE3MTAgU1cgTWls # aXRhcnkgUmQxGzAZBgNVBAoMElBLSSBTb2x1dGlvbnMgSW5jLjEbMBkGA1UEAwwS # UEtJIFNvbHV0aW9ucyBJbmMuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEA0L1qj5TDs7BrGL6/kUXX54oYim9CcoEW7rVWygcXKi0nzKh4Ly2JGOYeCBFu # ZCbSxMB0BfDbdGPllbqd0xaADbnxxqtrr6hYHTvV7dy2wehq9zs2QOgKQpLa6Hm1 # OapyU0yDrFpTUgin0hYWrTQrWOR5d7EcgUuNMXYADZIS14k7pVjTwSI3qS0A5rU/ # g1sHR9NFSZxrSPdbnnaG9TkiDwbQMm1vggMwye7paWU27F+rI0mJQ5iQMRPWnnZf # O+EwUwWeFuwf0k9xHggDs+njFzWZGF4P24T4pXHVqy0D8a9a2Sl5nL959tow7Fjh # W5Nb2R2Bzy0HhU9qZBCmhWYPdQuxo/OK/xw66bQIytO3AoD+Z5qzbQDr27fGDwp6 # 4PDETSvKxPhrryVeMVlWLIdBBDN5mLjACJ+TdREgAG4rLoNB1DgUlGMi8BeHk8PZ # Zq1jtoknD2dzRuIQHtsSMM1i58ng4v0z2JtWpDGkvPRWb0P5oIPUIkXJIJwg6DtV # FYI3JOq0PEOVZ3ojsfWzZDCyIRYg4IQy06W976tmL1GAmG2t2gg2CaBI80f6UhN7 # EIys0O+kTNjGCCxMtwSziOrpfOgP9tEb2C9K/93kOLwmzSCNqqnANlsuw+uh1EVf # QCUBE5qtNVbSb2epUdw/ijQtz+MoInrzTveSE75ow4kpb/0CAwEAAaOCAagwggGk # MB8GA1UdIwQYMBaAFA7hOqhTOjHVir7Bu61nGgOFrTQOMB0GA1UdDgQWBBR31gKB # zWLrup1S1jqN5GdPRjOxUDAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAT # BgNVHSUEDDAKBggrBgEFBQcDAzARBglghkgBhvhCAQEEBAMCBBAwQAYDVR0gBDkw # NzA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdv # LmNvbS9DUFMwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5zZWN0aWdvLmNv # bS9TZWN0aWdvUlNBQ29kZVNpZ25pbmdDQS5jcmwwcwYIKwYBBQUHAQEEZzBlMD4G # CCsGAQUFBzAChjJodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FDb2Rl # U2lnbmluZ0NBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5j # b20wIAYDVR0RBBkwF4EVaW5mb0Bwa2lzb2x1dGlvbnMuY29tMA0GCSqGSIb3DQEB # CwUAA4IBAQBrghkGUdTVXoPL5q2OvBJi6Av6vK/NHV4Yfn6fNvDECLiHchqSdAEi # 5bOhqZH6FFSBr39F3iOsFtcZOCSozsC2fNc/s/k1k6bE50U6XVR+A0i/kx8k0/Oy # +fnhufH2uApYmWmYo8KvXG1+PYRGWEB/oAM59TIJxOdLCUGLUFqLrTCqoM+6PXNw # NoPZcZ11WapWumXHXM2hfu+HISsDtX2mxFZBgh+VhjQvnyCmiwRRUwozpMlFGOd2 # JtGc7YIj2mVcMHPiPdxOeLd9cYzdS4FUicpJ4L6ZOy8lVhMeMGjBaiGHEwF2oPTE # VVvKyhEoa1ZInASt0CiaMwKtjarqhhzHMYIFdzCCBXMCAQEwgZAwfDELMAkGA1UE # BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2Fs # Zm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdv # IFJTQSBDb2RlIFNpZ25pbmcgQ0ECEBdBS6OH2/E/xEs3Bf5ckrcwDQYJYIZIAWUD # BAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMx # DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq # hkiG9w0BCQQxIgQghf6TqhFOFJQYha7H0Qd0P1jR4oF/4aEHG2jmu8nmBlQwDQYJ # KoZIhvcNAQEBBQAEggIAGg8l8dO6Rcs2y8N82muP1puw3sXRlSvxCkrHZGn3YbgN # JbGbKoeCaTgbK9o8UtBzzH/8yLNnwj5uZkpFDQB42iSeUbVMSvenxlc6K+DaP1NX # /k7sxyaXydO3ZwaEXTdZiwRcna/wx40W+f9xFJL0SRZJpuWd11z+1Llu6bLilifp # RSmqJ7FvYrxMXJfVVby0UR1bUYrO+R+kb4FTkGXllP8G/yYMFlZ+r8pM/Z468o0f # 9pAm9LGCE56p6NwfKI7e/OW/pE+E3tVZ5UBM0EKhl6MTi2a/MeMx5FtG6xfO1uNx # PD01Lv7lmSZVdnW142TnL4dGqDFsl02tjJ6fTn6qXw6DA0dQznEU3MRcK637okbx # txhD1Xau/j06EIjArOMN6nq834ugelvp6mM1UQJUA4WIPTAN4EWj58IvNsBr6Hx1 # tx5xWRvyrAPgh4V5mHL0W4hHfVXkOhKSH/uJkEpLbBPZ/EgTgzm28hnUYW+f+tth # fNCaAKaxPyQrELgzswd5PxYlbcSxwtrCu9gn/iScSPFOc6beqja/RoaNxbKcsCer # yPcgrXEbhcbYz++xTC+9wmZ5C6ZLMGlHMKVj731QbCU7ANlwlmiFk1mzcy0UM6lj # v+JsLZPy7thKMl4RUCySkI8bgZZE1NyFeJmYZAC2KZUBRXXGwcopTa+lHAh/bmWh # ggIwMIICLAYJKoZIhvcNAQkGMYICHTCCAhkCAQEwgYYwcjELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGlu # ZyBDQQIQDUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3 # DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIyMDExMjA5MjkwMlow # LwYJKoZIhvcNAQkEMSIEILE24DrWdGPvNoKti9UJClC1U+tbwmG5drPxj/Gh/vq3 # MA0GCSqGSIb3DQEBAQUABIIBAKywznm1T3wGYCQQOUUYvqzrQ6lc2lR5he3Ui9iM # fmytD8VPgobllpTPO25Oisyx1i5ZLeSBdSoM7vgtzH8V31J1LKv12OHwyHup5uOs # v7PlVwubSiakWUsEQWNOdSeOL80J1cp+spPbm4BPQ08HdtOMZMN3AYsn9O164g4A # 470mVd6lsCj8joPLfZVaiFr01jjLf9X4v1gNA4Y+Ww4SkFfLwsOwIK+WKUz886Kt # NEu5nCaZnLlHSmHaZGt4EVcTJknF8PZG35pmaJQX1MwUA/AxWEXkC//hIw2uCTrF # SG37u/0urf41p3YZneUIO4ZOzBNTB9mmjYtzE+jP0DDa+ZQ= # SIG # End signature block |