PowerShellGet.ResourceHelper.psm1 (27387B)
1 # 2 # Copyright (c) Microsoft Corporation. 3 # 4 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 5 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 6 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 7 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 8 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 9 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 10 # THE SOFTWARE. 11 # 12 13 <# 14 Helper functions for PowerShellGet DSC Resources. 15 #> 16 17 # Import localization helper functions. 18 $helperName = 'PowerShellGet.LocalizationHelper' 19 $resourceModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent 20 $dscResourcesFolderFilePath = Join-Path -Path $resourceModuleRoot -ChildPath "Modules\$helperName\$helperName.psm1" 21 Import-Module -Name $dscResourcesFolderFilePath 22 23 # Import Localization Strings 24 $script:localizedData = Get-LocalizedData -ResourceName 'PowerShellGet.ResourceHelper' -ScriptRoot $PSScriptRoot 25 26 <# 27 .SYNOPSIS 28 This is a helper function that extract the parameters from a given table. 29 30 .PARAMETER FunctionBoundParameters 31 Specifies the hash table containing a set of parameters to be extracted. 32 33 .PARAMETER ArgumentNames 34 Specifies a list of arguments you want to extract. 35 #> 36 function New-SplatParameterHashTable { 37 [CmdletBinding()] 38 [OutputType([System.Collections.Hashtable])] 39 param 40 ( 41 [Parameter(Mandatory = $true)] 42 [System.Collections.Hashtable] 43 $FunctionBoundParameters, 44 45 [Parameter(Mandatory = $true)] 46 [System.String[]] 47 $ArgumentNames 48 ) 49 50 Write-Verbose -Message ($script:localizedData.CallingFunction -f $($MyInvocation.MyCommand)) 51 52 $returnValue = @{} 53 54 foreach ($arg in $ArgumentNames) { 55 if ($FunctionBoundParameters.ContainsKey($arg)) { 56 # Found an argument we are looking for, so we add it to return collection. 57 $returnValue.Add($arg, $FunctionBoundParameters[$arg]) 58 } 59 } 60 61 return $returnValue 62 } 63 64 <# 65 .SYNOPSIS 66 This is a helper function that validate that a value is correct and used correctly. 67 68 .PARAMETER Value 69 Specifies the value to be validated. 70 71 .PARAMETER Type 72 Specifies the type of argument. 73 74 .PARAMETER Type 75 Specifies the name of the provider. 76 77 .OUTPUTS 78 None. Throws an error if the test fails. 79 #> 80 function Test-ParameterValue { 81 [CmdletBinding()] 82 param 83 ( 84 [Parameter(Mandatory = $true)] 85 [ValidateNotNullOrEmpty()] 86 [System.String] 87 $Value, 88 89 [Parameter(Mandatory = $true)] 90 [ValidateNotNullOrEmpty()] 91 [System.String] 92 $Type, 93 94 [Parameter(Mandatory = $true)] 95 [ValidateNotNullOrEmpty()] 96 [System.String] 97 $ProviderName 98 ) 99 100 Write-Verbose -Message ($script:localizedData.CallingFunction -f $($MyInvocation.MyCommand)) 101 102 switch ($Type) { 103 'SourceUri' { 104 # Checks whether given URI represents specific scheme 105 # Most common schemes: file, http, https, ftp 106 $scheme = @('http', 'https', 'file', 'ftp') 107 108 $newUri = $Value -as [System.URI] 109 $returnValue = ($newUri -and $newUri.AbsoluteURI -and ($scheme -icontains $newUri.Scheme)) 110 111 if ($returnValue -eq $false) { 112 $errorMessage = $script:localizedData.InValidUri -f $Value 113 New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage 114 } 115 } 116 117 'DestinationPath' { 118 $returnValue = Test-Path -Path $Value 119 120 if ($returnValue -eq $false) { 121 $errorMessage = $script:localizedData.PathDoesNotExist -f $Value 122 New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage 123 } 124 } 125 126 'PackageSource' { 127 # Value can be either the package source Name or source Uri. 128 129 # Check if the source is a Uri. 130 $uri = $Value -as [System.URI] 131 132 if ($uri -and $uri.AbsoluteURI) { 133 # Check if it's a valid Uri. 134 Test-ParameterValue -Value $Value -Type 'SourceUri' -ProviderName $ProviderName 135 } 136 else { 137 # Check if it's a registered package source name. 138 $source = PackageManagement\Get-PackageSource -Name $Value -ProviderName $ProviderName -ErrorVariable ev 139 140 if ((-not $source) -or $ev) { 141 # We do not need to throw error here as Get-PackageSource does already. 142 Write-Verbose -Message ($script:localizedData.SourceNotFound -f $source) 143 } 144 } 145 } 146 147 default { 148 $errorMessage = $script:localizedData.UnexpectedArgument -f $Type 149 New-InvalidArgumentException -ArgumentName $Type -Message $errorMessage 150 } 151 } 152 } 153 154 <# 155 .SYNOPSIS 156 This is a helper function that does the version validation. 157 158 .PARAMETER RequiredVersion 159 Provides the required version. 160 161 .PARAMETER MaximumVersion 162 Provides the maximum version. 163 164 .PARAMETER MinimumVersion 165 Provides the minimum version. 166 #> 167 function Test-VersionParameter { 168 [CmdletBinding()] 169 param 170 ( 171 [Parameter()] 172 [System.String] 173 $RequiredVersion, 174 175 [Parameter()] 176 [System.String] 177 $MinimumVersion, 178 179 [Parameter()] 180 [System.String] 181 $MaximumVersion 182 ) 183 184 Write-Verbose -Message ($localizedData.CallingFunction -f $($MyInvocation.MyCommand)) 185 186 $isValid = $false 187 188 # Case 1: No further check required if a user provides either none or one of these: minimumVersion, maximumVersion, and requiredVersion. 189 if ($PSBoundParameters.Count -le 1) { 190 return $true 191 } 192 193 # Case 2: #If no RequiredVersion is provided. 194 if (-not $PSBoundParameters.ContainsKey('RequiredVersion')) { 195 # If no RequiredVersion, both MinimumVersion and MaximumVersion are provided. Otherwise fall into the Case #1. 196 $isValid = $PSBoundParameters['MinimumVersion'] -le $PSBoundParameters['MaximumVersion'] 197 } 198 199 # Case 3: RequiredVersion is provided. 200 # In this case MinimumVersion and/or MaximumVersion also are provided. Otherwise fall in to Case #1. 201 # This is an invalid case. When RequiredVersion is provided, others are not allowed. so $isValid is false, which is already set in the init. 202 203 if ($isValid -eq $false) { 204 $errorMessage = $script:localizedData.VersionError 205 New-InvalidArgumentException ` 206 -ArgumentName 'RequiredVersion, MinimumVersion or MaximumVersion' ` 207 -Message $errorMessage 208 } 209 } 210 211 <# 212 .SYNOPSIS 213 This is a helper function that retrieves the InstallationPolicy from the given repository. 214 215 .PARAMETER RepositoryName 216 Provides the repository Name. 217 #> 218 function Get-InstallationPolicy { 219 [CmdletBinding()] 220 param 221 ( 222 [Parameter(Mandatory = $true)] 223 [ValidateNotNullOrEmpty()] 224 [System.String] $RepositoryName 225 ) 226 227 Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.MyCommand)) 228 229 $repositoryObject = PackageManagement\Get-PackageSource -Name $RepositoryName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue 230 231 if ($repositoryObject) { 232 return $repositoryObject.IsTrusted 233 } 234 } 235 236 <# 237 .SYNOPSIS 238 This method is used to compare current and desired values for any DSC resource. 239 240 .PARAMETER CurrentValues 241 This is hash table of the current values that are applied to the resource. 242 243 .PARAMETER DesiredValues 244 This is a PSBoundParametersDictionary of the desired values for the resource. 245 246 .PARAMETER ValuesToCheck 247 This is a list of which properties in the desired values list should be checked. 248 If this is empty then all values in DesiredValues are checked. 249 #> 250 function Test-DscParameterState { 251 [CmdletBinding()] 252 param 253 ( 254 [Parameter(Mandatory = $true)] 255 [System.Collections.Hashtable] 256 $CurrentValues, 257 258 [Parameter(Mandatory = $true)] 259 [System.Object] 260 $DesiredValues, 261 262 [Parameter()] 263 [System.Array] 264 $ValuesToCheck 265 ) 266 267 $returnValue = $true 268 269 if (($DesiredValues.GetType().Name -ne 'HashTable') ` 270 -and ($DesiredValues.GetType().Name -ne 'CimInstance') ` 271 -and ($DesiredValues.GetType().Name -ne 'PSBoundParametersDictionary')) { 272 $errorMessage = $script:localizedData.PropertyTypeInvalidForDesiredValues -f $($DesiredValues.GetType().Name) 273 New-InvalidArgumentException -ArgumentName 'DesiredValues' -Message $errorMessage 274 } 275 276 if (($DesiredValues.GetType().Name -eq 'CimInstance') -and ($null -eq $ValuesToCheck)) { 277 $errorMessage = $script:localizedData.PropertyTypeInvalidForValuesToCheck 278 New-InvalidArgumentException -ArgumentName 'ValuesToCheck' -Message $errorMessage 279 } 280 281 if (($null -eq $ValuesToCheck) -or ($ValuesToCheck.Count -lt 1)) { 282 $keyList = $DesiredValues.Keys 283 } 284 else { 285 $keyList = $ValuesToCheck 286 } 287 288 $keyList | ForEach-Object -Process { 289 if (($_ -ne 'Verbose')) { 290 if (($CurrentValues.ContainsKey($_) -eq $false) ` 291 -or ($CurrentValues.$_ -ne $DesiredValues.$_) ` 292 -or (($DesiredValues.GetType().Name -ne 'CimInstance' -and $DesiredValues.ContainsKey($_) -eq $true) -and ($null -ne $DesiredValues.$_ -and $DesiredValues.$_.GetType().IsArray))) { 293 if ($DesiredValues.GetType().Name -eq 'HashTable' -or ` 294 $DesiredValues.GetType().Name -eq 'PSBoundParametersDictionary') { 295 $checkDesiredValue = $DesiredValues.ContainsKey($_) 296 } 297 else { 298 # If DesiredValue is a CimInstance. 299 $checkDesiredValue = $false 300 if (([System.Boolean]($DesiredValues.PSObject.Properties.Name -contains $_)) -eq $true) { 301 if ($null -ne $DesiredValues.$_) { 302 $checkDesiredValue = $true 303 } 304 } 305 } 306 307 if ($checkDesiredValue) { 308 $desiredType = $DesiredValues.$_.GetType() 309 $fieldName = $_ 310 if ($desiredType.IsArray -eq $true) { 311 if (($CurrentValues.ContainsKey($fieldName) -eq $false) ` 312 -or ($null -eq $CurrentValues.$fieldName)) { 313 Write-Verbose -Message ($script:localizedData.PropertyValidationError -f $fieldName) -Verbose 314 315 $returnValue = $false 316 } 317 else { 318 $arrayCompare = Compare-Object -ReferenceObject $CurrentValues.$fieldName ` 319 -DifferenceObject $DesiredValues.$fieldName 320 if ($null -ne $arrayCompare) { 321 Write-Verbose -Message ($script:localizedData.PropertiesDoesNotMatch -f $fieldName) -Verbose 322 323 $arrayCompare | ForEach-Object -Process { 324 Write-Verbose -Message ($script:localizedData.PropertyThatDoesNotMatch -f $_.InputObject, $_.SideIndicator) -Verbose 325 } 326 327 $returnValue = $false 328 } 329 } 330 } 331 else { 332 switch ($desiredType.Name) { 333 'String' { 334 if (-not [System.String]::IsNullOrEmpty($CurrentValues.$fieldName) -or ` 335 -not [System.String]::IsNullOrEmpty($DesiredValues.$fieldName)) { 336 Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` 337 -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose 338 339 $returnValue = $false 340 } 341 } 342 343 'Int32' { 344 if (-not ($DesiredValues.$fieldName -eq 0) -or ` 345 -not ($null -eq $CurrentValues.$fieldName)) { 346 Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` 347 -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose 348 349 $returnValue = $false 350 } 351 } 352 353 { $_ -eq 'Int16' -or $_ -eq 'UInt16'} { 354 if (-not ($DesiredValues.$fieldName -eq 0) -or ` 355 -not ($null -eq $CurrentValues.$fieldName)) { 356 Write-Verbose -Message ($script:localizedData.ValueOfTypeDoesNotMatch ` 357 -f $desiredType.Name, $fieldName, $($CurrentValues.$fieldName), $($DesiredValues.$fieldName)) -Verbose 358 359 $returnValue = $false 360 } 361 } 362 363 default { 364 Write-Warning -Message ($script:localizedData.UnableToCompareProperty ` 365 -f $fieldName, $desiredType.Name) 366 367 $returnValue = $false 368 } 369 } 370 } 371 } 372 } 373 } 374 } 375 376 return $returnValue 377 } 378 379 # SIG # Begin signature block 380 # MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor 381 # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG 382 # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBH3QB1YDOZOOwJ 383 # V+KQVBF6PeRCZ7EOOlwmL67tD15ypKCCDYEwggX/MIID56ADAgECAhMzAAABh3IX 384 # chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD 385 # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy 386 # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p 387 # bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw 388 # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u 389 # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy 390 # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 391 # AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB 392 # znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH 393 # sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d 394 # weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ 395 # itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV 396 # Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE 397 # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw 398 # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 399 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu 400 # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu 401 # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w 402 # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 403 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx 404 # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy 405 # S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K 406 # NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV 407 # BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr 408 # qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx 409 # zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe 410 # yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g 411 # yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf 412 # AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI 413 # 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5 414 # GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea 415 # jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS 416 # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK 417 # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 418 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 419 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla 420 # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS 421 # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT 422 # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB 423 # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG 424 # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S 425 # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz 426 # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 427 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u 428 # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 429 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl 430 # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP 431 # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB 432 # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF 433 # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM 434 # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ 435 # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud 436 # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO 437 # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 438 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y 439 # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p 440 # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y 441 # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB 442 # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw 443 # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA 444 # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY 445 # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj 446 # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd 447 # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ 448 # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf 449 # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ 450 # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j 451 # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B 452 # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 453 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 454 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I 455 # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG 456 # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx 457 # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z 458 # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN 459 # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor 460 # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgAchP/Cco 461 # Y2JAjut9Hy3IC65/Rf67ea66bxFJosTcn0EwQgYKKwYBBAGCNwIBDDE0MDKgFIAS 462 # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN 463 # BgkqhkiG9w0BAQEFAASCAQCA7tKfqWfEy22S/6wr4OyvRkvECIOlgOTLpZGyP7iT 464 # 16UqNis22r/tHfj0nQMVembrz5WOUvHZPrU72+fJAZqMdCB5H0wHmeBOmie166xn 465 # CDvlSHtJr5sPZeRDNQFeJN2nN+I47eFwThr5ndx6Gp548DoyDWBnFQz2tgvVpIWA 466 # TBFrWf8ZulTYcMH3QhzlgEmmgEsU2vT5nbBmmK2QICDzcWA3tIzHSQ7jQxqL+9Oj 467 # 9EVvuJTf0e81f05xNUmunrwWuoHzIYOF7LmpZqWFp4m8rg5Davtum5Rq60TcofSH 468 # gKzh10SD1+hAHm7/aqz640BMXsMJCBHofYDzXY0Un7sWoYIS8TCCEu0GCisGAQQB 469 # gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME 470 # AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB 471 # MDEwDQYJYIZIAWUDBAIBBQAEIJeyBGsDoIyvzKdclhGjO92lMFh4eXEiupSWXMgA 472 # yrYhAgZfYQdYOoMYEzIwMjAwOTIyMjIxOTUwLjk4M1owBIACAfSggdSkgdEwgc4x 473 # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt 474 # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p 475 # Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg 476 # VFNTIEVTTjpGODdBLUUzNzQtRDdCOTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt 477 # U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABL7GnF3lWlBeHAAAA 478 # AAEvMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo 479 # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y 480 # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw 481 # MB4XDTE5MTIxOTAxMTUwNloXDTIxMDMxNzAxMTUwNlowgc4xCzAJBgNVBAYTAlVT 482 # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK 483 # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy 484 # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpGODdB 485 # LUUzNzQtRDdCOTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj 486 # ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKh8VkvVIwXD8sn0zT2n 487 # EdyEZ9UNHY7ACbOZA4obAHvD1hauw9K1Z2lRWG+m8Ars9l35GoMXdPgshM3hZKQW 488 # fhrLnF9/GDZoilhc2LhMqNPXs06rAJ8YODB6i0Cg1CFCYnyOYvywXKY3xGJN09Dg 489 # PXWfczEm2P/a3rmrXMrK5EFc3ahxrC51c+UuAMKV9xJyzJVLShPwPBJl+CjdMDPJ 490 # f24DZXIYec3gCN2xean1DFCI0gaqJprMeL4Om1KY2AZMIgBPEkoY1N7AI5e7ybkI 491 # L8+Mz3inijb4rDTkXk86ztUwy4bdc1MyKe2j2odT+QIDA2+M8cMTIGlKn7EyD2NN 492 # XU8CAwEAAaOCARswggEXMB0GA1UdDgQWBBSml/VRpBNFkAMDiqcoqWi85j/qljAf 493 # BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH 494 # hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU 495 # aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF 496 # BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0 497 # YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG 498 # AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQB4q6ilv2SlGvJD/7dbfoIKZBO2i6YA 499 # wckw57TpCrt2+SAx2dcF7JvRMCPhLCSgqjyNcJRs40cEXPbLdzZMJHzcv73AF7L6 500 # mWZXg2aBjG1Sc5qM4jjE/nwIX+C6/odm5/asU4JIlFCuUZjzqdir18HkRVQve2Hw 501 # V0lCXHQs+V3m9DyyA9b6LSIk3GOFZu7F11Wyx/5dVXisPPTPwh9JXfMD9W173M1+ 502 # ZZycmO03lUc4G1FilgpxWNdgWn/DO9ZhoW5yN6+BUddnJ4cCcCjcg8sB5rktPP8p 503 # VZAQ7aUqkAeqo+FuCkAUAdJRESCpR5wgSPtVvFPMjONE36DbKtfzkfiHMIIGcTCC 504 # BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC 505 # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV 506 # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv 507 # b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN 508 # MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv 509 # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 510 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw 511 # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0 512 # VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw 513 # RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe 514 # dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx 515 # Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G 516 # kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA 517 # AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7 518 # fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC 519 # AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX 520 # zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v 521 # cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI 522 # KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j 523 # b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g 524 # AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93 525 # d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB 526 # BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA 527 # bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh 528 # IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS 529 # +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK 530 # kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon 531 # /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi 532 # PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/ 533 # fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII 534 # YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0 535 # cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a 536 # KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ 537 # cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+ 538 # NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT 539 # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD 540 # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP 541 # cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpG 542 # ODdBLUUzNzQtRDdCOTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy 543 # dmljZaIjCgEBMAcGBSsOAwIaAxUAM/CZCUpclQ9qfr/r3y9osIIPSmSggYMwgYCk 544 # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH 545 # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD 546 # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF 547 # AOMUwAMwIhgPMjAyMDA5MjIyMjI1MDdaGA8yMDIwMDkyMzIyMjUwN1owdzA9Bgor 548 # BgEEAYRZCgQBMS8wLTAKAgUA4xTAAwIBADAKAgEAAgIeewIB/zAHAgEAAgIQ0jAK 549 # AgUA4xYRgwIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB 550 # AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAB7Ib0ORN4cnD/0V 551 # iEDrzl7vxjx6981A8Z/8I+X0n7qQHdeGFJcXGEEO5pDD62VMfd28ZrxPWgMd0Chx 552 # mj5EdvR3U6+gRYzyYY5Vi5srADcWf3pMoYsEQhZuYeohtFQuYFJt2t26GskSlEy3 553 # qXFkFqIoBCjz1SsmfA5nTtE2zXHSMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC 554 # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV 555 # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp 556 # bWUtU3RhbXAgUENBIDIwMTACEzMAAAEvsacXeVaUF4cAAAAAAS8wDQYJYIZIAWUD 557 # BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B 558 # CQQxIgQgDY7vkk/uubZSKGprOnZ2WnFZqhRkEJ7KVJ5R6hogo/AwgfoGCyqGSIb3 559 # DQEJEAIvMYHqMIHnMIHkMIG9BCBC5RecGZvugnvVXg80zlrGv1uV35LNk+H9dBj3 560 # ChFPvTCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u 561 # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp 562 # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB 563 # L7GnF3lWlBeHAAAAAAEvMCIEIAt7o8jjQ4zf04GvFGrnuSSwfsToGMPMzYw+3a3k 564 # vP0dMA0GCSqGSIb3DQEBCwUABIIBABIE9hcJhxcSYL9zQrK7AunfYI2qZBNrD9dB 565 # FIYwBnLNOYAPgpjC5Nxrp/4fSrWPyWFkXzwB6rjofda3zWpOywWKMc4lK0yHRYrO 566 # 7r0FmXd9zxdaJKpbHpc8xG2vb6pI9dh/eXFGNS8KRu+oKZFX2/l5IxRAz4QRMxq6 567 # /heHcZpWjeIknMhP+bMAqaMV9h3jEojCli0hdwawbTpq8Oyvo6wlwNqLvmtBc7Xs 568 # 8of9f6I/zTCn6yhbyDEVXxPhn3qjrQzi790XXe3xvmAKkkEW/NO2ZOS/2EpfjFms 569 # wYhh6tKYg2k2j6mfCGmwvx2cx32zR/m4/ieGClCeKPiRlPvgip0= 570 # SIG # End signature block