Framework/Helpers/ControlHelper.ps1
# This class should contains method that would be required to filter/targer controls class ControlHelper: EventBase{ static [psobject] $ControlFixBackup = @() static $GroupMembersResolutionObj = @{} #Caching group resolution static $ResolvedBroaderGroups = @{} # Caching expanded broader groups static $GroupsWithNumerousMembers = @() # Groups which contains very large groups static $VeryLargeGroups = @() # Very large groups (fetched from controlsettings) static $IsGroupDetailsFetchedFromPolicy = $false static $AllowedMemberCountPerBroadGroup = @() # Allowed member count (fetched from controlsettings) static $GroupsToExpand = @() # Groups for which meber counts need to check (fetched from controlsettings) static $GroupsWithDescriptor = @{} # All broder groups with descriptors static [string] $parentGroup = $null #used to store current broader group static $CurrentGroupResolutionLevel = -1 # used to define the current level of group which is expanding. Negative value indicates all level. static $GroupResolutionLevel = 1 # used to define the level of group expansion. Negative value indicates all level. static $UseSIPFeedForAADGroupExpansion = $false static $AADGroupsObjFromPolicy = $null static [CloudmineDataHelper] $CloudmineDataHelperObj; static $InactiveResources = @() #Checks if the severities passed by user are valid and filter out invalid ones hidden static [string []] CheckValidSeverities([string []] $ParamSeverities) { $ValidSeverities = @(); $ValidSeverityValues = @(); $InvalidSeverities = @(); $ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); if([Helpers]::CheckMember($ControlSettings, 'ControlSeverity')) { $severityMapping = $ControlSettings.ControlSeverity #Discard the severity values passed in parameter that do not have mapping in Org settings. foreach($sev in $severityMapping.psobject.properties) { $ValidSeverities += $sev.value } $ValidSeverityValues += $ParamSeverities | Where-Object { $_ -in $ValidSeverities} $InvalidSeverities += $ParamSeverities | Where-Object { $_ -notin $ValidSeverities } } else { $ValidEnumSeverities = [Enum]::GetNames('ControlSeverity') $ValidSeverityValues += $ParamSeverities | Where-Object { $_ -in $ValidEnumSeverities} $InvalidSeverities += $ParamSeverities | Where-Object { $_ -notin $ValidEnumSeverities } } if($InvalidSeverities) { [EventBase]:: PublishGenericCustomMessage("WARNING: No control severity corresponds to `"$($InvalidSeverities -join ', ')`" for your org.",[MessageType]::Warning) } return $ValidSeverityValues } static [object] GetIdentitiesFromAADGroup([string] $OrgName, [String] $EntityId, [String] $groupName) { $members = @() $AllUsers = @() $rmContext = [ContextHelper]::GetCurrentContext(); $user = ""; $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $rmContext.AccessToken))) try { $apiUrl = 'https://dev.azure.com/{0}/_apis/IdentityPicker/Identities/{1}/connections?identityTypes=user&identityTypes=group&operationScopes=ims&operationScopes=source&connectionTypes=successors&depth=1&properties=DisplayName&properties=SubjectDescriptor&properties=SignInAddress' -f $($OrgName), $($EntityId) $responseObj = @(Invoke-RestMethod -Method Get -Uri $apiURL -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -UseBasicParsing) # successors property will not be available if there are no users added to group. if ([Helpers]::CheckMember($responseObj[0], "successors")) { $members = @($responseObj.successors | Select-Object originId, displayName, @{Name = "subjectKind"; Expression = { $_.entityType } }, @{Name = "mailAddress"; Expression = { $_.signInAddress } }, @{Name = "descriptor"; Expression = { $_.subjectDescriptor } }, @{Name = "groupName"; Expression = { $groupName } }) } $members | ForEach-Object { if ($_.subjectKind -eq 'User') { $AllUsers += $_ } } return $AllUsers } catch { Write-Host $_ return $AllUsers } } static [void] ResolveNestedGroupMembers([string]$descriptor,[string] $orgName,[string] $projName){ [ControlHelper]::groupMembersResolutionObj[$descriptor] = @() $url="https://dev.azure.com/{0}/_apis/Contribution/HierarchyQuery?api-version=5.1-preview" -f $($orgName); if ([string]::IsNullOrEmpty($projName)){ $postbody=@' {"contributionIds":["ms.vss-admin-web.org-admin-members-data-provider"],"dataProviderContext":{"properties":{"subjectDescriptor":"{0}","sourcePage":{"url":"https://dev.azure.com/{2}/_settings/groups?subjectDescriptor={1}","routeId":"ms.vss-admin-web.collection-admin-hub-route","routeValues":{"adminPivot":"groups","controller":"ContributedPage","action":"Execute"}}}}} '@ $postbody=$postbody.Replace("{0}",$descriptor) $postbody=$postbody.Replace("{1}",$orgName) } else { $postbody=@' {"contributionIds":["ms.vss-admin-web.org-admin-members-data-provider"],"dataProviderContext":{"properties":{"subjectDescriptor":"{0}","sourcePage":{"url":"https://dev.azure.com/{1}/{2}/_settings/permissions?subjectDescriptor={0}","routeId":"ms.vss-admin-web.collection-admin-hub-route","routeValues":{"adminPivot":"groups","controller":"ContributedPage","action":"Execute"}}}}} '@ $postbody=$postbody.Replace("{0}",$descriptor) $postbody=$postbody.Replace("{1}",$orgName) $postbody=$postbody.Replace("{2}",$projName) } $rmContext = [ContextHelper]::GetCurrentContext(); $user = ""; $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken))) try { $response = Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $postbody if([Helpers]::CheckMember($response.dataProviders.'ms.vss-admin-web.org-admin-members-data-provider', "identities")) { $data=$response.dataProviders.'ms.vss-admin-web.org-admin-members-data-provider'.identities $data | ForEach-Object{ if($_.subjectKind -eq "group") { if ([ControlHelper]::UseSIPFeedForAADGroupExpansion -and [Helpers]::CheckMember($_,"isAadGroup") -and $_.isAadGroup -eq $true) { $members = [ControlHelper]::ResolveGroupUsingSIPData($orgName, $_) [ControlHelper]::groupMembersResolutionObj[$descriptor] += $members } else { if ([string]::IsNullOrWhiteSpace($_.descriptor) -and (-not [string]::IsNullOrWhiteSpace($_.entityId))) { $identities = @([ControlHelper]::GetIdentitiesFromAADGroup($orgName, $_.entityId, $_.displayName)) if ($identities.Count -gt 0) { #add the descriptor of group to denote the user is a direct member of this group and is not a part of the group due to nesting, to be used in auto fix $identities | Add-Member -NotePropertyName "DirectMemberOfGroup" -NotePropertyValue $descriptor [ControlHelper]::groupMembersResolutionObj[$descriptor] += $identities } } else { [ControlHelper]::ResolveNestedGroupMembers($_.descriptor,$orgName,$projName) [ControlHelper]::groupMembersResolutionObj[$descriptor] += [ControlHelper]::groupMembersResolutionObj[$_.descriptor] } } } else { #add the descriptor of group to denote the user is a direct member of this group and is not a part of the group due to nesting, to be used in auto fix $_ | Add-Member -NotePropertyName "DirectMemberOfGroup" -NotePropertyValue $descriptor [ControlHelper]::groupMembersResolutionObj[$descriptor] += $_ } } } } catch { Write-Host $_ } } static [void] FindGroupMembers([string]$descriptor,[string] $orgName,[string] $projName){ if (-not [ControlHelper]::GroupMembersResolutionObj.ContainsKey("OrgName")) { [ControlHelper]::GroupMembersResolutionObj["OrgName"] = $orgName } if ([ControlHelper]::IsGroupDetailsFetchedFromPolicy -eq $false) { [ControlHelper]::FetchControlSettingDetails() } if ([ControlHelper]::UseSIPFeedForAADGroupExpansion) { if (-not [IdentityHelpers]::hasSIPAccess) { [ControlHelper]::UseSIPFeedForAADGroupExpansion = $false } } [ControlHelper]::ResolveNestedGroupMembers($descriptor, $orgName, $projName) } static [PSObject] ResolveGroupUsingSIPData([string] $OrgName, $group) { $users = @() try { #check if group object id is present in the policy file if ($null -eq [ControlHelper]::AADGroupsObjFromPolicy) { [ControlHelper]::AADGroupsObjFromPolicy = [ConfigurationHelper]::LoadServerFileRaw("AAD_Groups.csv", [ConfigurationManager]::GetAzSKSettings().UseOnlinePolicyStore, [ConfigurationManager]::GetAzSKSettings().OnlinePolicyStoreUrl, [ConfigurationManager]::GetAzSKSettings().EnableAADAuthForOnlinePolicyStore) | ConvertFrom-Csv } if ([ControlHelper]::AADGroupsObjFromPolicy.displayName -contains $group.displayName) { $groupObj = [ControlHelper]::AADGroupsObjFromPolicy | where-object {$_.displayName -eq $group.displayName} } else { #Get the object id of the group which will then be used to create mapping with SIP database $groupObj = @() $rmContext = [ContextHelper]::GetCurrentContext(); $user = ""; $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken))) $url=" https://vssps.dev.azure.com/{0}/_apis/Graph/SubjectQuery?api-version=5.2-preview.1" -f $($orgName); $postbody='{"query":"' + $($group.displayName) + '","subjectKind":["Group"]}' $responseObj = Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $postbody if ([Helpers]::CheckMember($responseObj,"value") -and $group.descriptor -eq $responseObj.value[0].descriptor) { $groupObj = $responseObj.value[0] } } #Get the members of the group from the SIP database $accessToken = [IdentityHelpers]::dataExplorerAccessToken $apiURL = "https://dsresip.kusto.windows.net/v2/rest/query" $inputbody = "{`"db`": `"AADUsersData`",`"csl`": `"let GroupObjectIds = dynamic(['$($groupObj.originId)']); let LatestGroupEtlDate = toscalar ( cluster('dsresip.kusto.windows.net').database('AADGroupsData').GroupMembers | summarize arg_max(etldate,*) | project etldate); let LatestUserEtlDate = toscalar ( UsersInfo | summarize arg_max(etldate,*) | project etldate); cluster('dsresip.kusto.windows.net').database('AADGroupsData').GroupMembers | where etldate == LatestGroupEtlDate and GroupId in~ (GroupObjectIds) | project GroupId,GroupDisplayName, GroupPrincipalName, objectId= UserId | join kind=inner (UsersInfo | where etldate == LatestUserEtlDate | project objectId = UserId, providerDisplayName = UserDisplayName, mail = UserPrincipalName,extensionAttribute2) on objectId | project GroupId,GroupDisplayName,GroupPrincipalName, objectId , providerDisplayName , mail ,extensionAttribute2`"}" $header = @{ "Authorization" = "Bearer " + $accessToken } $kustoResponse = Invoke-RestMethod -Uri $apiURL -Method Post -ContentType "application/json; charset=utf-8" -Headers $header -Body $inputbody; $kustoResponse = $kustoResponse | Where-Object {$_.FrameType -eq "DataTable" -and $_.TableKind -eq 'PrimaryResult'} $kustoResponse.rows | Where-Object {$_[0] -eq $groupObj.originId} | ForEach-Object {$user = "" | select-object identityId, originId, subjectKind, displayName, mailAddress, descriptor, DirectMemberOfGroup; $user.identityId = $_[3]; $user.originId = $_[3]; $user.subjectKind = 'user'; $user.displayName = $_[4]; $user.mailAddress = $_[5]; $user.DirectMemberOfGroup = $_[1]; $users += $user} } catch { #eat exception } return $users } static [PSObject] ResolveNestedBroaderGroupMembers([PSObject]$groupObj,[string] $orgName,[string] $projName) { $groupPrincipalName = $groupObj.principalName $members = @() #increasing the level of group which is currently expanding and comparing it with defined expansion limit on each recursion. [ControlHelper]::CurrentGroupResolutionLevel += 1 if ([ControlHelper]::CurrentGroupResolutionLevel -le [ControlHelper]::GroupResolutionLevel) { if ([ControlHelper]::ResolvedBroaderGroups.ContainsKey($groupPrincipalName)) { $members += [ControlHelper]::ResolvedBroaderGroups[$_.principalName]; } else { [ControlHelper]::ResolvedBroaderGroups[$groupPrincipalName] = @() $rmContext = [ContextHelper]::GetCurrentContext(); $user = ""; $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken))) $memberslist = @() if ([string]::IsNullOrWhiteSpace($groupObj.descriptor) -and (-not [string]::IsNullOrWhiteSpace($groupObj.entityId))) { $apiUrl = 'https://dev.azure.com/{0}/_apis/IdentityPicker/Identities/{1}/connections?identityTypes=user&identityTypes=group&operationScopes=ims&operationScopes=source&connectionTypes=successors&depth=1&properties=DisplayName&properties=SubjectDescriptor&properties=SignInAddress' -f $($OrgName), $($groupObj.entityId) $responseObj = @(Invoke-RestMethod -Method Get -Uri $apiURL -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -UseBasicParsing) # successors property will not be available if there are no users added to group. if ([Helpers]::CheckMember($responseObj[0], "successors")) { $memberslist = @($responseObj.successors | Select-Object entityId, originId, descriptor, @{Name = "principalName"; Expression = { $_.displayName } }, @{Name = "mailAddress"; Expression = { $_.signInAddress } }, @{Name = "subjectKind"; Expression = { $_.entityType } }) } $members += [ControlHelper]::NestedGroupResolverHelper($memberslist) } else { $descriptor = $groupObj.descriptor $url="https://dev.azure.com/{0}/_apis/Contribution/HierarchyQuery?api-version=5.1-preview" -f $($orgName); $postbody=@' {"contributionIds":["ms.vss-admin-web.org-admin-members-data-provider"],"dataProviderContext":{"properties":{"subjectDescriptor":"{0}","sourcePage":{"url":"https://dev.azure.com/{1}/{2}/_settings/permissions?subjectDescriptor={0}","routeId":"ms.vss-admin-web.collection-admin-hub-route","routeValues":{"adminPivot":"groups","controller":"ContributedPage","action":"Execute"}}}}} '@ $postbody=$postbody.Replace("{0}",$descriptor) $postbody=$postbody.Replace("{1}",$orgName) $postbody=$postbody.Replace("{2}",$projName) $response = Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $postbody if([Helpers]::CheckMember($response.dataProviders.'ms.vss-admin-web.org-admin-members-data-provider', "identities")) { $memberslist = @($response.dataProviders.'ms.vss-admin-web.org-admin-members-data-provider'.identities) } $members += [ControlHelper]::NestedGroupResolverHelper($memberslist) } [ControlHelper]::ResolvedBroaderGroups[$groupPrincipalName] = $members } } return $members } static [PSObject] NestedGroupResolverHelper($memberslist) { $members = @() if ($memberslist.Count -gt 0) { $memberslist | ForEach-Object { if($_.subjectKind -eq "Group") { if ([ControlHelper]::VeryLargeGroups -contains $_.principalName) { [ControlHelper]::GroupsWithNumerousMembers += [ControlHelper]::parentGroup } else { $members += [ControlHelper]::ResolveNestedBroaderGroupMembers($_, $orgName, $projName) #decreasing the current level of resolution, so that other groups present at the same level can also be expanded. [ControlHelper]::CurrentGroupResolutionLevel -= 1 # Uncomment the below code if member count needs to be displayed on console. # Write-Host "Group: [$($_.principalName)]; MemberCount: $(@([ControlHelper]::ResolvedBroaderGroups[$_.principalName]).Count)" -ForegroundColor Cyan } } else { $members += $_ } } } return $members } static [PSObject] GetBroaderGroupDescriptorObj([string] $OrgName,[string] $groupName) { $groupObj = @() $projName = $groupName.Split("\")[0] -replace '[\[\]]' $rmContext = [ContextHelper]::GetCurrentContext(); $user = ""; $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken))) $url= "https://dev.azure.com/{0}/_apis/Contribution/HierarchyQuery?api-version=5.1-preview.1" -f $($OrgName); if ($projName -eq $OrgName) { $body=@' {"contributionIds":["ms.vss-admin-web.org-admin-groups-data-provider"],"dataProviderContext":{"properties":{"sourcePage":{"url":"https://dev.azure.com/{0}/_settings/groups","routeId":"ms.vss-admin-web.collection-admin-hub-route","routeValues":{"adminPivot":"groups","controller":"ContributedPage","action":"Execute"}}}}} '@ $body=$body.Replace("{0}",$OrgName) } else { $body=@' {"contributionIds":["ms.vss-admin-web.org-admin-groups-data-provider"],"dataProviderContext":{"properties":{"sourcePage":{"url":"https://dev.azure.com/{0}/{1}/_settings/permissions","routeId":"ms.vss-admin-web.project-admin-hub-route","routeValues":{"project":"{1}","adminPivot":"permissions","controller":"ContributedPage","action":"Execute"}}}}} '@ $body=$body.Replace("{0}",$OrgName) $body=$body.Replace("{1}",$projName) } try{ $responseObj = Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body $groupObj = $responseObj.dataProviders.'ms.vss-admin-web.org-admin-groups-data-provider'.identities | Where-Object {$_.principalName -eq $groupName} } catch { Write-Host $_ } return $groupObj } hidden static FetchControlSettingDetails() { $ControlSettingsObj = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); [ControlHelper]::VeryLargeGroups = @($ControlSettingsObj.VeryLargeGroups) [ControlHelper]::AllowedMemberCountPerBroadGroup = @($ControlSettingsObj.AllowedMemberCountPerBroadGroup) [ControlHelper]::GroupsToExpand = @($ControlSettingsObj.BroaderGroupsToExpand) [ControlHelper]::IsGroupDetailsFetchedFromPolicy = $true [ControlHelper]::GroupResolutionLevel = $ControlSettingsObj.GroupResolution.GroupResolutionLevel [ControlHelper]::UseSIPFeedForAADGroupExpansion = $ControlSettingsObj.GroupResolution.UseSIPFeedForAADGroupExpansion } static [PSObject] FilterBroadGroupMembers([PSObject] $groupList, [bool] $fetchDescriptor) { $broaderGroupsWithExcessiveMembers = @() if ([ControlHelper]::IsGroupDetailsFetchedFromPolicy -eq $false) { [ControlHelper]::FetchControlSettingDetails() } # if the value is set to -1, it means all level of the groups needs be expaned. if ([ControlHelper]::GroupResolutionLevel -eq -1) { [ControlHelper]::GroupResolutionLevel = 1000 } # if environment variable is provided, it will override the policy configuration. if ($null -ne $env:GroupResolutionLevel) { [ControlHelper]::GroupResolutionLevel = $env:GroupResolutionLevel } [ControlHelper]::CurrentGroupResolutionLevel = 0 $groupList | Foreach-Object { # In some cases, group object doesn't contains descriptor key which requires to expand the groups. if ($fetchDescriptor) { $groupName = $_.Name.split('\')[-1] } else { $groupName = $_.principalName.split('\')[-1] } if ([ControlHelper]::GroupsToExpand -contains $groupName) { if ($fetchDescriptor) { if (-not ([ControlHelper]::GroupsWithDescriptor.keys -contains $_.Name)) { [ControlHelper]::GroupsWithDescriptor[$_.Name] += [ControlHelper]::GetBroaderGroupDescriptorObj($this.OrganizationContext.OrganizationName, $_.Name) } $groupObj = [ControlHelper]::GroupsWithDescriptor[$_.Name] } else { $groupObj = $_ } [ControlHelper]::parentGroup = $groupObj.principalName #Checking if group is prenet in the dictionary, if not then expand it, else fetch from dictionary if ([ControlHelper]::GroupMembersResolutionObj.ContainsKey($groupObj.descriptor)) { $groupMembers = @([ControlHelper]::GroupMembersResolutionObj[$groupObj.descriptor]) } elseif (-not [ControlHelper]::ResolvedBroaderGroups.ContainsKey($groupObj.principalName)) { $groupMembers = @([ControlHelper]::ResolveNestedBroaderGroupMembers($groupObj, $this.OrganizationContext.OrganizationName, $this.ResourceContext.ResourceGroupName)) } else { $groupMembers = @([ControlHelper]::ResolvedBroaderGroups[$groupObj.principalName]) } $groupMembersCount = @($groupMembers | Select-Object -property mailAddress -Unique).Count # Checking the allowed member count for broader group # Fail only if member count is greater then allowed limit. if ([Helpers]::CheckMember([ControlHelper]::AllowedMemberCountPerBroadGroup, $groupName)) { $allowedMemberCount = [ControlHelper]::AllowedMemberCountPerBroadGroup.$groupName if (($groupMembersCount -gt $allowedMemberCount) -or ([ControlHelper]::GroupsWithNumerousMembers -contains $groupObj.principalName)) { $broaderGroupsWithExcessiveMembers += $groupObj.principalName } } else { $broaderGroupsWithExcessiveMembers += $groupObj.principalName } } else { if ($fetchDescriptor) { $broaderGroupsWithExcessiveMembers += $_.Name } else { $broaderGroupsWithExcessiveMembers += $_.principalName } } } return $broaderGroupsWithExcessiveMembers } static [PSObject] GetInactiveControlDataFromCloudMine($organizationName,$projectId,$resourceId,$resourceType){ $resourceDetails = @() [ControlHelper]::CloudmineDataHelperObj = [CloudmineDataHelper]::CloudmineDataHelperInstance if (![ControlHelper]::CloudmineDataHelperObj) { [ControlHelper]::CloudmineDataHelperObj = [CloudmineDataHelper]::GetInstance($organizationName); [ControlHelper]::InactiveResources = [ControlHelper]::CloudmineDataHelperObj.GetCloudMineData($projectId) } if(-not [Helpers]::CheckMember([ControlHelper]::InactiveResources[0],"ResourceID")){ return @([Constants]::CMErrorMessage); } $resourceDetails = @([ControlHelper]::InactiveResources | where {$_.ResourceType -eq $resourceType -and $_.ResourceID -eq $resourceId -and $_.ProjectID -eq $projectId}) return $resourceDetails } } # SIG # Begin signature block # MIIntwYJKoZIhvcNAQcCoIInqDCCJ6QCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAOJ1wEJ6segYY1 # lFbvwFScXByQvnzvmu8iP8eu+zOTO6CCDYEwggX/MIID56ADAgECAhMzAAACUosz # qviV8znbAAAAAAJSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjEwOTAyMTgzMjU5WhcNMjIwOTAxMTgzMjU5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDQ5M+Ps/X7BNuv5B/0I6uoDwj0NJOo1KrVQqO7ggRXccklyTrWL4xMShjIou2I # sbYnF67wXzVAq5Om4oe+LfzSDOzjcb6ms00gBo0OQaqwQ1BijyJ7NvDf80I1fW9O # L76Kt0Wpc2zrGhzcHdb7upPrvxvSNNUvxK3sgw7YTt31410vpEp8yfBEl/hd8ZzA # v47DCgJ5j1zm295s1RVZHNp6MoiQFVOECm4AwK2l28i+YER1JO4IplTH44uvzX9o # RnJHaMvWzZEpozPy4jNO2DDqbcNs4zh7AWMhE1PWFVA+CHI/En5nASvCvLmuR/t8 # q4bc8XR8QIZJQSp+2U6m2ldNAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUNZJaEUGL2Guwt7ZOAu4efEYXedEw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDY3NTk3MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFkk3 # uSxkTEBh1NtAl7BivIEsAWdgX1qZ+EdZMYbQKasY6IhSLXRMxF1B3OKdR9K/kccp # kvNcGl8D7YyYS4mhCUMBR+VLrg3f8PUj38A9V5aiY2/Jok7WZFOAmjPRNNGnyeg7 # l0lTiThFqE+2aOs6+heegqAdelGgNJKRHLWRuhGKuLIw5lkgx9Ky+QvZrn/Ddi8u # TIgWKp+MGG8xY6PBvvjgt9jQShlnPrZ3UY8Bvwy6rynhXBaV0V0TTL0gEx7eh/K1 # o8Miaru6s/7FyqOLeUS4vTHh9TgBL5DtxCYurXbSBVtL1Fj44+Od/6cmC9mmvrti # yG709Y3Rd3YdJj2f3GJq7Y7KdWq0QYhatKhBeg4fxjhg0yut2g6aM1mxjNPrE48z # 6HWCNGu9gMK5ZudldRw4a45Z06Aoktof0CqOyTErvq0YjoE4Xpa0+87T/PVUXNqf # 7Y+qSU7+9LtLQuMYR4w3cSPjuNusvLf9gBnch5RqM7kaDtYWDgLyB42EfsxeMqwK # WwA+TVi0HrWRqfSx2olbE56hJcEkMjOSKz3sRuupFCX3UroyYf52L+2iVTrda8XW # esPG62Mnn3T8AuLfzeJFuAbfOSERx7IFZO92UPoXE1uEjL5skl1yTZB3MubgOA4F # 8KoRNhviFAEST+nG8c8uIsbZeb08SeYQMqjVEmkwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIZjDCCGYgCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAlKLM6r4lfM52wAAAAACUjAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgXe4f23Nv # m0an+i16LvKnQvYzttMybwMAOI2O+ybAMoYwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQBViaKH0thmvs40gn3osQ0rXrwjSfTSKw701ls1+PZB # 3R7jAVkTj7ZDZT/UtipFeysWc8kg/Pq5X2AIwOquUQ+/FLChqbZH4wa7TgEUI+Yd # IOh/jrf0vGxvhJ3mra7puYzOXVi6PAdHNnBRijjYh1QWUR9zwMXDfWO7PsnKy3cu # JArBcv5L+WzW8MDqmT0iSe/pJPbQBuMMUcw0DHnONsrUwINVfrraybsoROew9YO6 # HAAjRbjdSDJi2UcphzgORSsSJpQE6HEMiwpUPqIHAI+U9Q2yfEGn9iVSdaX8BkCo # OhgCxFZNU+8HFxZuNZoJWVpIhwBGL89cKCf8WeRH59mBoYIXFjCCFxIGCisGAQQB # gjcDAwExghcCMIIW/gYJKoZIhvcNAQcCoIIW7zCCFusCAQMxDzANBglghkgBZQME # AgEFADCCAVkGCyqGSIb3DQEJEAEEoIIBSASCAUQwggFAAgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIA5+LZVgp4mKqXnqMU5gk4gSAaDq7yqBxsP7mrAb # C/KOAgZiF7V1n5IYEzIwMjIwMzE1MDgzNTE0LjY4NVowBIACAfSggdikgdUwgdIx # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1p # Y3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhh # bGVzIFRTUyBFU046MkFENC00QjkyLUZBMDExJTAjBgNVBAMTHE1pY3Jvc29mdCBU # aW1lLVN0YW1wIFNlcnZpY2WgghFlMIIHFDCCBPygAwIBAgITMwAAAYZ45RmJ+CRL # zAABAAABhjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMDAeFw0yMTEwMjgxOTI3MzlaFw0yMzAxMjYxOTI3MzlaMIHSMQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQg # SXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1Mg # RVNOOjJBRDQtNEI5Mi1GQTAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt # cCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwI3G2Wpv # 6B4IjAfrgfJpndPOPYO1Yd8+vlfoIxMW3gdCDT+zIbafg14pOu0t0ekUQx60p7Pa # dH4OjnqNIE1q6ldH9ntj1gIdl4Hq4rdEHTZ6JFdE24DSbVoqqR+R4Iw4w3GPbfc2 # Q3kfyyFyj+DOhmCWw/FZiTVTlT4bdejyAW6r/Jn4fr3xLjbvhITatr36VyyzgQ0Y # 4Wr73H3gUcLjYu0qiHutDDb6+p+yDBGmKFznOW8wVt7D+u2VEJoE6JlK0EpVLZus # dSzhecuUwJXxb2uygAZXlsa/fHlwW9YnlBqMHJ+im9HuK5X4x8/5B5dkuIoX5lWG # jFMbD2A6Lu/PmUB4hK0CF5G1YaUtBrME73DAKkypk7SEm3BlJXwY/GrVoXWYUGEH # yfrkLkws0RoEMpoIEgebZNKqjRynRJgR4fPCKrEhwEiTTAc4DXGci4HHOm64EQ1g # /SDHMFqIKVSxoUbkGbdKNKHhmahuIrAy4we9s7rZJskveZYZiDmtAtBt/gQojxbZ # 1vO9C11SthkrmkkTMLQf9cDzlVEBeu6KmHX2Sze6ggne3I4cy/5IULnHZ3rM4ZpJ # c0s2KpGLHaVrEQy4x/mAn4yaYfgeH3MEAWkVjy/qTDh6cDCF/gyz3TaQDtvFnAK7 # 0LqtbEvBPdBpeCG/hk9l0laYzwiyyGY/HqMCAwEAAaOCATYwggEyMB0GA1UdDgQW # BBQZtqNFA+9mdEu/h33UhHMN6whcLjAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJl # pxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAx # MCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3Rh # bXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4ICAQDD7mehJY3fTHKC4hj+wBWB8544 # uaJiMMIHnhK9ONTM7VraTYzx0U/TcLJ6gxw1tRzM5uu8kswJNlHNp7RedsAiwviV # QZV9AL8IbZRLJTwNehCwk+BVcY2gh3ZGZmx8uatPZrRueyhhTTD2PvFVLrfwh2li # DG/dEPNIHTKj79DlEcPIWoOCUp7p0ORMwQ95kVaibpX89pvjhPl2Fm0CBO3pXXJg # 0bydpQ5dDDTv/qb0+WYF/vNVEU/MoMEQqlUWWuXECTqx6TayJuLJ6uU7K5QyTkQ/ # l24IhGjDzf5AEZOrINYzkWVyNfUOpIxnKsWTBN2ijpZ/Tun5qrmo9vNIDT0lobgn # ulae17NaEO9oiEJJH1tQ353dhuRi+A00PR781iYlzF5JU1DrEfEyNx8CWgERi90L # KsYghZBCDjQ3DiJjfUZLqONeHrJfcmhz5/bfm8+aAaUPpZFeP0g0Iond6XNk4YiY # bWPFoofc0LwcqSALtuIAyz6f3d+UaZZsp41U4hCIoGj6hoDIuU839bo/mZ/AgESw # GxIXs0gZU6A+2qIUe60QdA969wWSzucKOisng9HCSZLF1dqc3QUawr0C0U41784K # o9vckAG3akwYuVGcs6hM/SqEhoe9jHwe4Xp81CrTB1l9+EIdukCbP0kyzx0WZzte # eiDN5rdiiQR9mBJuljCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUw # DQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhv # cml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z # b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw # ggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg # 4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aO # RmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41 # JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5 # LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL # 64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9 # QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj # 0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqE # UUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0 # kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435 # UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB # 3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTE # mr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwG # A1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNV # HSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNV # HQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo # 0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29m # dC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5j # cmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jv # c29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDAN # BgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4 # sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th54 # 2DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRX # ud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBew # VIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0 # DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+Cljd # QDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFr # DZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFh # bHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7n # tdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+ # oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6Fw # ZvKhggLUMIICPQIBATCCAQChgdikgdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MkFENC00Qjky # LUZBMDExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB # ATAHBgUrDgMCGgMVAAGu2DRzWkKljmXySX1korHL4fMnoIGDMIGApH4wfDELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z # b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDl2pdVMCIY # DzIwMjIwMzE1MTI0MDUzWhgPMjAyMjAzMTYxMjQwNTNaMHQwOgYKKwYBBAGEWQoE # ATEsMCowCgIFAOXal1UCAQAwBwIBAAICEEowBwIBAAICETQwCgIFAOXb6NUCAQAw # NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC # AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQCXIVBsyO0/vKPAn8VXAFK+y2eatCJK # zneQSrXv1JfTa/1dmZrkKrsnsiM2/xhLn2KFuDyhu34T8Ev7wHwKduZTE3PpB40J # L/iRIshCmuAutZqp0TDZFRrT8XV+R/1W3P9YrHRkafTPqBacyzZrD8nHpe5VJBJC # S43GSom7TSF8IjGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD # QSAyMDEwAhMzAAABhnjlGYn4JEvMAAEAAAGGMA0GCWCGSAFlAwQCAQUAoIIBSjAa # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIFfrAYxc # G4J0gnuyaMPfyVfHT6PWXIaIXFh7YMjFrtjkMIH6BgsqhkiG9w0BCRACLzGB6jCB # 5zCB5DCBvQQgGpmI4LIsCFTGiYyfRAR7m7Fa2guxVNIw17mcAiq8Qn4wgZgwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAYZ45RmJ+CRLzAAB # AAABhjAiBCAJ8Uqz2fNh7qmNYvFvks/Yz3yhRjhW867NWHSBtlp2SjANBgkqhkiG # 9w0BAQsFAASCAgAB6pDiIZo2SLzzLPab3EQrK68FdNbhxAaPJQmNKpLuAXy50qYL # MHH2nceqy9dRjcaTGh8kMSqqojv2LI4maaBUTTIajyAW6bOEtys7WLrvprxkncYI # J8KulI4r4R2uJjPFFIWmbuW8+LCDAkNvnIOfCmcIoIVunkP1iSZZ4ElzbFVbU3Dl # F3aAwVgtyepYyLcQVkyNecdMhPUlHrZsoQhZIZwL0BCGRElq40Nf1GPlYgenhdz4 # iKPIFxGfKpWRKkVO8OQfZgLSck2ZdHoXLUDfzo+v4OEqDqOWzsHNS4Q2CVLc/4LM # IzutLmv0IgApf2F9NPhVmX/pAwp6HZFElikgNXV40ae6t8Gay0TJQehgXSOkAiyg # h64XCx9MPsPaY1jEXBHU2hfbA6ziEqt3nsN/ganj2rUQEDEgVrmWp/XqY0LkjINY # /or8M06S6INcot7EcZKr+QNhwbihRVcQz8NxnbRVXMmKXxZAD2xy71FCmm9qtV5g # HkWorUjmaZsRn1lGpwgLtAjy5TwlHbY5/8t4SzYRW3cre+LtGmI4ip+cZGZ5XYK6 # 78LdHLk+1lkFIebGlS5srZpJ0srClGRbklmsMz7JNAwqnbe6pcQoEmZfuMCPwwU6 # njftSuEZ4sq1/oSq71vOz/cD6o6y2FAnZc6OwIqU1TyQ6DIebNnvEayJ9g== # SIG # End signature block |