typedata/enumerable.ps1
<#############################################################################
The TypePx module adds properties and methods to the most commonly used types to make common tasks easier. Using these type extensions together can provide an enhanced syntax in PowerShell that is both easier to read and self-documenting. TypePx also provides commands to manage type accelerators. Type acceleration also contributes to making scripting easier and they help produce more readable scripts, particularly when using a library of .NET classes that belong to the same namespace. Copyright 2014 Kirk Munro Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. #############################################################################> $commonlyUsedGenericTypeParameters = @( [System.Management.Automation.PSObject] [System.Object] [System.String] [System.Int32] [System.Int64] ) $typeNames = @() foreach ($assembly in [System.AppDomain]::CurrentDomain.GetAssemblies()) { foreach ($type in $assembly.GetTypes()) { # If the type is not public or if it is an interface, skip it if ((-not $type.IsPublic) -or $type.IsInterface) { continue } # If the type is String or XmlNode, skip it (these are exceptions in PowerShell) if (@([System.String],[System.Xml.XmlNode]) -contains $type) { continue } # If the type does not implement IEnumerable or it implements IDictionary, skip it $interfaces = $type.GetInterfaces() if (($interfaces -notcontains [System.Collections.IEnumerable]) -or ($interfaces -contains [System.Collections.IDictionary])) { continue } # If the base type is not Object, MarshalByRefObject, or ValueType, skip it if (@([System.Object],[System.MarshalByRefObject],[System.ValueType]) -notcontains $type.BaseType) { continue } # If the type definition is generic, add a collection of common generic types to our # enumerable type collection; otherwise, just add the type if ($type.IsGenericTypeDefinition) { foreach ($typeParameter in $commonlyUsedGenericTypeParameters) { $typeNames += "$($type.FullName)[[$($typeParameter.AssemblyQualifiedName)]]" } } else { $typeNames += $type.FullName } } } if ($PSVersionTable.PSVersion -lt [System.Version]'4.0') { Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName foreach -ScriptBlock { [System.Diagnostics.DebuggerStepThrough()] param( # A script block (expression), type (conversion type), or string (property or method name) [Parameter(Position=0, Mandatory=$true)] [ValidateNotNull()] [System.Object] $Object ) # Create an array to hold the results $results = @() if ($Object -is [System.Management.Automation.ScriptBlock]) { # Process as if we used ForEach-Object # I would love to make this more efficient for 3.0, but it is too difficult to work around the # limitation of being unable to invoke a script block in its scope while passing it parameters # without using a pipeline. $passThruParameters = @{ Process = $Object } if ($args) { $passThruParameters['ArgumentList'] = $args } $results = $this | ForEach-Object @passThruParameters } elseif ($Object -is [System.Type]) { # Convert the items in the collection to the type specified foreach ($item in $this) { $results += $item -as $Object } } elseif ($Object -is [System.String]) { foreach ($item in $this) { if ($member = $item.PSObject.Members[$Object -as [System.String]]) { if ($member -is [System.Management.Automation.PSMethodInfo]) { # Invoke the method on objects in the collection if ($result = $member.Invoke($args)) { $results += $result } } elseif ($member -is [System.Management.Automation.PSPropertyInfo]) { if ($args) { # Set the property on objects in the collection $member.Value = $args } else { # Get the property on objects in the collection $results += $member.Value } } } } } # Return the results in an objectmodel collection to the caller if ($results) { $results = $results -as [System.Collections.ObjectModel.Collection`1[System.Object]] ,$results } } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName where -ScriptBlock { [System.Diagnostics.DebuggerStepThrough()] param( # The conditional expression that we are evaluating [Parameter(Position=0, Mandatory=$true)] [ValidateNotNull()] [System.Management.Automation.ScriptBlock] $Expression, # The evaluation mode [Parameter(Position=1)] [ValidateNotNullOrEmpty()] [ValidateSet('Default','First','Last','SkipUntil','Until','Split')] [System.String] $Mode = 'Default', # The number of objects to return [Parameter(Position=2)] [ValidateNotNull()] [ValidateRange(0,[System.Int32]::MaxValue)] [System.Int32] $NumberToReturn = 0 ) # Create an array to hold the results $results = @() switch ($Mode) { 'First' { # Return the first N objects matching the expression (default to 1) if ($NumberToReturn -eq 0) { $NumberToReturn = 1 } $results = $this | Where-Object -FilterScript $Expression | Select-Object -First $NumberToReturn break } 'Last' { # Return the last N objects matching the expression (default to 1) if ($NumberToReturn -eq 0) { $NumberToReturn = 1 } $results = $this | Where-Object -FilterScript $Expression | Select-Object -Last $NumberToReturn break } 'SkipUntil' { # Skip until an object matches the expression, then return the first N objects (default to all) $outputCount = 0 if ($NumberToReturn -eq 0) { $NumberToReturn = $this.Count } foreach ($item in $this) { if (($outputCount -eq 0) -and -not (Where-Object -InputObject $item -FilterScript $Expression)) { continue } if ($outputCount -lt $NumberToReturn) { $outputCount++ $results += $item } if ($outputCount -eq $NumberToReturn) { break } } break } 'Until' { # Return the first N objects until an object matches the expression (default to all) $outputCount = 0 if ($NumberToReturn -eq 0) { $NumberToReturn = $this.Count } foreach ($item in $this) { if (Where-Object -InputObject $item -FilterScript $Expression) { break } if ($outputCount -lt $NumberToReturn) { $outputCount++ $results += $item } if ($outputCount -eq $NumberToReturn) { break } } break } 'Split' { # Split based on condition, to a maximum count if one was provided (default to all) $collection0 = @() $collection1 = @() if ($NumberToReturn -eq 0) { $NumberToReturn = $this.Count } foreach ($item in $this) { if (($collection0.Count -lt $NumberToReturn) -and (Where-Object -InputObject $item -FilterScript $Expression)) { $collection0 += $item } else { $collection1 += $item } } $collection0 = $collection0 -as [System.Collections.ObjectModel.Collection`1[System.Object]] $collection1 = $collection1 -as [System.Collections.ObjectModel.Collection`1[System.Object]] $results = @($collection0,$collection1) break } default { # Filter using the expression, to a maximum count if one was provided (default to all) if ($NumberToReturn -eq 0) { $results = $this | Where-Object -FilterScript $Expression } else { $results = $this | Where-Object -FilterScript $Expression | Select-Object -First $NumberToReturn } break } } # Return the results in an objectmodel collection to the caller if ($results) { $results = $results -as [System.Collections.ObjectModel.Collection`1[System.Object]] ,$results } } } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName MatchAny -ScriptBlock { [System.Diagnostics.DebuggerHidden()] param( # The regular expressions to compare the collection against [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String[]] $Values ) # Add remaining arguments to the value collection for easier invocation if ($args) { $Values += $args } # Return any items in the collection matching the values provided ,($this.where({([string]$_).MatchAny($Values)}) -as $this.GetType()) } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName LikeAny -ScriptBlock { [System.Diagnostics.DebuggerHidden()] param( # The wildcard strings to compare the collection against [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String[]] $Values ) # Add remaining arguments to the value collection for easier invocation if ($args) { $Values += $args } # Return any items in the collection like the values provided ,($this.where({([string]$_).LikeAny($Values)}) -as $this.GetType()) } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName ContainsAny -ScriptBlock { [System.Diagnostics.DebuggerHidden()] param( # The values to compare the collection against [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.Object[]] $Values ) # Add remaining arguments to the value collection for easier invocation if ($args) { $Values += $args } # Return true if the collection contains any of the values; false otherwise $matchFound = $false foreach ($item in $Values) { if ($this -contains $item) { $matchFound = $true break } } $matchFound } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName ContainsAll -ScriptBlock { [System.Diagnostics.DebuggerHidden()] param( # The values to compare the collection against [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.Object[]] $Values ) # Add remaining arguments to the value collection for easier invocation if ($args) { $Values += $args } # Return true if the collection contains all of the values; false otherwise foreach ($item in $Values) { if ($this -notcontains $item) { $false break } } $true } Add-ScriptMethodData -TypeName $typeNames -ScriptMethodName Sum -ScriptBlock { [System.Diagnostics.DebuggerHidden()] param( # The property to use when calculating the sum [Parameter(Position=0)] [ValidateNotNull()] [System.String] $Property ) # Calculate the sum of the collection or of the values of a specific property # in the collection $total = $null if ($PSVersionTable.PSVersion -lt [System.Version]'4.0') { foreach ($item in $this) { if ($Property) { $total += $item.$Property } else { $total += $item } } } elseif ($Property) { $this.foreach({$total += $_.$Property}) } else { $this.foreach({$total += $_}) } $total } # SIG # Begin signature block # MIIZIAYJKoZIhvcNAQcCoIIZETCCGQ0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUHeQBZD8KbydtEk53W7blljz4 # roGgghRWMIID7jCCA1egAwIBAgIQfpPr+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 # ggUSMIID+qADAgECAhAN//fSWE4vjemplVn1wnAjMA0GCSqGSIb3DQEBBQUAMG8x # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xLjAsBgNVBAMTJURpZ2lDZXJ0IEFzc3VyZWQgSUQgQ29k # ZSBTaWduaW5nIENBLTEwHhcNMTQxMDAzMDAwMDAwWhcNMTUxMDA3MTIwMDAwWjBo # MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEPMA0GA1UEBxMGT3R0YXdh # MRowGAYDVQQKExFLaXJrIEFuZHJldyBNdW5ybzEaMBgGA1UEAxMRS2lyayBBbmRy # ZXcgTXVucm8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIANwog4/2 # JUJCJ1PKeXu8S+eBp1F8fHaVFVgMToGhyNz+UptqDVBIsOu21AXNd4s/3WqhOnOt # yBvyn5thWNGCMB/XcX6/SdV8lSyg0swreiiR7ksJc1jK75aDJV2UE/mOiMtcWo01 # SQGddbF4FpK3LxbzjKGMPP7uI1TUFTxmdR8t8HaRlI7KcsZkckGffkboAm5CWDhZ # d4f9YhVzZ8uV0jAN9i+mtmIOHTMMskQ7tZy17GkgyjiGrnMxy6VZ18hya062ZLcV # 20LUqsUkjr0oNvf54KrhZrPQhULagcpKwmxw3hzDfvWov4yVLWdgWT6a+TUG8D39 # HUuVCpXG+OgZAgMBAAGjggGvMIIBqzAfBgNVHSMEGDAWgBR7aM4pqsAXvkl64eU/ # 1qf3RY81MjAdBgNVHQ4EFgQUG+clmaBur2rhO4i38pTJHCFSya0wDgYDVR0PAQH/ # BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMG0GA1UdHwRmMGQwMKAuoCyGKmh0 # dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9hc3N1cmVkLWNzLWcxLmNybDAwoC6gLIYq # aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL2Fzc3VyZWQtY3MtZzEuY3JsMEIGA1Ud # IAQ7MDkwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp # Z2ljZXJ0LmNvbS9DUFMwgYIGCCsGAQUFBwEBBHYwdDAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMEwGCCsGAQUFBzAChkBodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURDb2RlU2lnbmluZ0NBLTEu # Y3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQADggEBACJI6tx95+XcEC6X # EAxbRZjIXJ085IDdqWXImnfQ8To+yAeHM5kP506ddtzlztW9esOxqnhnfIAClB1e # 1f/FAlgpxrEQ2IRCuUHuMfy4AxqRkD9jePVZ7NYKcKxJZ87iu32iuGT+phFip+ZP # O9GkqDYkvzQmB74b7hQ3knn6qFLqUZ8njpSceIeC8PHINZmSx+v+KVkEavN/z0hF # T9xYR2VPPjIIk3MnwtkyHhTWWxNoKGCg+BZV2mApwR9EsWJHVpiGru6DNfNwSQpB # oIvMGOOL919XgE4J1B022xnAcnCCxoGjjSmBPb1TWemijGsGD2Je8/EALw9geBB9 # vbJvwn8wggajMIIFi6ADAgECAhAPqEkGFdcAoL4hdv3F7G29MA0GCSqGSIb3DQEB # BQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNV # BAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQg # SUQgUm9vdCBDQTAeFw0xMTAyMTExMjAwMDBaFw0yNjAyMTAxMjAwMDBaMG8xCzAJ # BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k # aWdpY2VydC5jb20xLjAsBgNVBAMTJURpZ2lDZXJ0IEFzc3VyZWQgSUQgQ29kZSBT # aWduaW5nIENBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcfPmg # jwrKiUtTmjzsGSJ/DMv3SETQPyJumk/6zt/G0ySR/6hSk+dy+PFGhpTFqxf0eH/L # er6QJhx8Uy/lg+e7agUozKAXEUsYIPO3vfLcy7iGQEUfT/k5mNM7629ppFwBLrFm # 6aa43Abero1i/kQngqkDw/7mJguTSXHlOG1O/oBcZ3e11W9mZJRru4hJaNjR9H4h # webFHsnglrgJlflLnq7MMb1qWkKnxAVHfWAr2aFdvftWk+8b/HL53z4y/d0qLDJG # 2l5jvNC4y0wQNfxQX6xDRHz+hERQtIwqPXQM9HqLckvgVrUTtmPpP05JI+cGFvAl # qwH4KEHmx9RkO12rAgMBAAGjggNDMIIDPzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l # BAwwCgYIKwYBBQUHAwMwggHDBgNVHSAEggG6MIIBtjCCAbIGCGCGSAGG/WwDMIIB # pDA6BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20vc3NsLWNwcy1y # ZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMA # ZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8A # bgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAA # dABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAA # dABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0A # ZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQA # eQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgA # ZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjASBgNVHRMBAf8E # CDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4 # MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk # SURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln # aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMB0GA1UdDgQWBBR7aM4pqsAXvkl64eU/ # 1qf3RY81MjAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG # 9w0BAQUFAAOCAQEAe3IdZP+IyDrBt+nnqcSHu9uUkteQWTP6K4feqFuAJT8Tj5uD # G3xDxOaM3zk+wxXssNo7ISV7JMFyXbhHkYETRvqcP2pRON60Jcvwq9/FKAFUeRBG # JNE4DyahYZBNur0o5j/xxKqb9to1U0/J8j3TbNwj7aqgTWcJ8zqAPTz7NkyQ53ak # 3fI6v1Y1L6JMZejg1NrRx8iRai0jTzc7GZQY1NWcEDzVsRwZ/4/Ia5ue+K6cmZZ4 # 0c2cURVbQiZyWo0KSiOSQOiG3iLCkzrUm2im3yl/Brk8Dr2fxIacgkdCcTKGCZly # CXlLnXFp9UH/fzl3ZPGEjb6LHrJ9aKOlkLEM/zGCBDQwggQwAgEBMIGDMG8xCzAJ # BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k # aWdpY2VydC5jb20xLjAsBgNVBAMTJURpZ2lDZXJ0IEFzc3VyZWQgSUQgQ29kZSBT # aWduaW5nIENBLTECEA3/99JYTi+N6amVWfXCcCMwCQYFKw4DAhoFAKB4MBgGCisG # AQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFHeG # X0dkIGVmihpNhJZlk5rMLxamMA0GCSqGSIb3DQEBAQUABIIBAFlEhTO39RhSD0zM # dtEMpw+Z7x7Z9wXoGI6E8AW5KTlWl7qGFUYi9JLLQL35fV9bA+9PJRjrclv17zQU # +vRKCrM4/P2FK0KZ2LTvAu2IRBptAukhjGPK1rCiltzhxiuY4jy7Qm5jmBcE7dD6 # HUWa9+batNsbJFQKiODM9FA5YwX+Ze+eGmuHJYkeoI2+Ot5aHam4Yeh306j6owv+ # 41VR14SOCMJXaf2SJY+PooRaVZI4VeeTCUVwUEUtkz+hFjUeoxN34SBaY1HLvzrT # IbuLyCQCaqNgLr33VbKflWJjAoTOTz2/+dF1YiQGJj0v+yq0Kzqrka+H/NBysSt0 # Z6+pXUGhggILMIICBwYJKoZIhvcNAQkGMYIB+DCCAfQCAQEwcjBeMQswCQYDVQQG # EwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5 # bWFudGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMgIQDs/0OMj+vzVu # BNhqmBsaUDAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc # BgkqhkiG9w0BCQUxDxcNMTQxMTA4MjMzMzMyWjAjBgkqhkiG9w0BCQQxFgQUx+dl # QcaNYSrOD8LXBPSVNyB85ncwDQYJKoZIhvcNAQEBBQAEggEASK2QzkTJ3/40aeSD # MevsGApYmqHw7v92McobCgv87AnXGc5Kotufhb8/0d5OkEIcMvyMT05oswnRsHbY # o9+AMIRXU39XLPL32+faAHeb7mJ6tC/wzWqxdEgjGln0mHEkENFI5uCkXzkz0ufO # 1CvrLPyh+Ivia8qbgX6F/a7wOrFkz8didClkkKvtkm7VUm26D3nzd4a+Du/hpviV # 9AuGVqIPHXOp4f9G/NmtVTghImOv0HtWfthYTFMmCTPLeZtQMwMsl885pd7rEjnX # HisCQcqjpH2gIkBOuHADFLyYGPVqwIOPYst5XxKlOfqp0nkeBvdPDZUKjgESxfUF # tSFhWg== # SIG # End signature block |