ManagedCompany.ps1
function Switch-KeeperMC { <# .Synopsis Switch to managed company .Parameter Name Managed Company ID or Name #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)][string] $Name ) [Enterprise]$enterprise = getMspEnterprise $mc = $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $Name) } if ($mc.Length -eq 0) { $mc = $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseName -like $Name + '*') } } if ($mc.Length -eq 0) { Write-Error -Message "Managed Company`"$Name`" not found" -ErrorAction Stop } elseif ($mc.Length -gt 1) { Write-Error -Message "Managed Company`"$Name`" is not unique. Use Company ID." -ErrorAction Stop } $Script:Context.ManagedCompanyId = $mc.EnterpriseId Sync-KeeperEnterprise Write-Information "Switched to MC `"$($mc.EnterpriseName)`"" } New-Alias -Name switch-to-mc -Value Switch-KeeperMC function Switch-KeeperMSP { <# .Synopsis Switch to MSP #> [CmdletBinding()] [Enterprise]$enterprise = getMspEnterprise $Script:Context.ManagedCompanyId = 0 Sync-KeeperEnterprise Write-Information "Switched to MSP" } New-Alias -Name switch-to-msp -Value Switch-KeeperMSP function Get-KeeperManagedCompany { <# .Synopsis Get a list of managed companies .Parameter Filter Managed Company ID or Name #> [CmdletBinding()] Param ( [Parameter(Mandatory = $false)][string] $Filter ) [Enterprise]$enterprise = getMspEnterprise if ($Name) { $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $Filter) -or ($_.EnterpriseName -like $Filter + '*') } } else { $enterprise.mspData.ManagedCompanies } } New-Alias -Name kmc -Value Get-KeeperManagedCompany $Keeper_MspAddonName = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() $msp_addons = @('enterprise_breach_watch', 'compliance_report', 'enterprise_audit_and_reporting', 'msp_service_and_support', 'secrets_manager', 'connection_manager', 'chat') $toComplete = $wordToComplete += '*' foreach ($addon in $msp_addons) { if ($addon -like $toComplete) { $result += $addon } } if ($result.Count -gt 0) { return $result } else { return $null } } function New-KeeperManagedCompany { <# .Synopsis Adds new Managed Company .Parameter Name Managed Company Name .Parameter PlanId Managed Company Plan .Parameter MaximumSeats Maximum Number of Seats .Parameter Storage Storage Plan .Parameter Addons Addons .Parameter Node Node Name or ID #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory = $true, Position = 0)][string] $Name, [Parameter(Mandatory = $true)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, [Parameter(Mandatory = $true)][int] $MaximumSeats, [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, [Parameter(Mandatory = $false)][string[]] $Addons, [Parameter(Mandatory = $false)][string] $Node ) [Enterprise]$enterprise = getMspEnterprise $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions $options.Name = $Name $options.ProductId = $PlanId $options.NumberOfSeats = $MaximumSeats if ($Node) { $n = findEnterpriseNode $Node if ($n) { $options.NodeId = $n.Id } else { Write-Error -Message "Node ${Node} not found" -ErrorAction Stop } } else { $options.NodeId = $enterprise.enterpriseData.RootNode.Id } switch ($Storage) { '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } } if ($Addons) { $aons = @() foreach ($addon in $Addons) { $parts = $addon -split ':' $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions $addonOption.Addon = $parts[0] if ($parts.Length -gt 1) { $addonOption.NumberOfSeats = $parts[1] -as [int] } $aons += $addonOption } $options.Addons = $aons } if ($PSCmdlet.ShouldProcess($Name, "Creating Managed Company")) { return $enterprise.mspData.CreateManagedCompany($options).GetAwaiter().GetResult() } } New-Alias -Name kamc -Value New-KeeperManagedCompany Register-ArgumentCompleter -CommandName New-KeeperManagedCompany -ParameterName Addons -ScriptBlock $Keeper_MspAddonName function Remove-KeeperManagedCompany { <# .Synopsis Removes Managed Company .Parameter Name Managed Company Id or Name #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $Name ) [Enterprise]$enterprise = getMspEnterprise $mc = findManagedCompany $Name if (-not $mc) { Write-Error -Message "Managed Company ${Name} not found" -ErrorAction Stop } if ($PSCmdlet.ShouldProcess($mc.EnterpriseName, "Removing Managed Company")) { $enterprise.mspData.RemoveManagedCompany($mc.EnterpriseId).GetAwaiter().GetResult() | Out-Null Write-Information "Removed Managed Company `"$($mc.EnterpriseName)`" ID: $($mc.EnterpriseId)" } } New-Alias -Name krmc -Value Remove-KeeperManagedCompany function Edit-KeeperManagedCompany { <# .Synopsis Removes Managed Company .Parameter Name Managed Company New Name .Parameter PlanId Managed Company Plan .Parameter MaximumSeats Maximum Number of Seats .Parameter Storage Storage Plan .Parameter Addons Addons .Parameter Node Node Name or ID .Parameter Id Managed Company Name or Id #> [CmdletBinding()] Param ( [Parameter(Mandatory = $false)][string] $Name, [Parameter(Mandatory = $false)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, [Parameter(Mandatory = $false)][int] $MaximumSeats, [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, [Parameter(Mandatory = $false)][string[]] $Addons, [Parameter(Mandatory = $false)][string] $Node, [Parameter(Position = 0, Mandatory = $true)][string] $Id ) [Enterprise]$enterprise = getMspEnterprise $mc = findManagedCompany $Id if (-not $mc) { Write-Error -Message "Managed Company ${Id} not found" -ErrorAction Stop } $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions if ($Name) { $options.Name = $Name } if ($PlanId) { $options.ProductId = $PlanId } if ($MaximumSeats) { $options.NumberOfSeats = $MaximumSeats } switch ($Storage) { '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } } if ($Addons) { $aons = @() foreach ($addon in $Addons) { $parts = $addon -split ':' $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions $addonOption.Addon = $parts[0] if ($parts.Length -gt 1) { $addonOption.NumberOfSeats = $parts[1] -as [int] } $aons += $addonOption } $options.Addons = $aons } if ($Node) { $n = findEnterpriseNode $Node if ($n) { $options.NodeId = $n.Id } else { Write-Error -Message "Node ${Node} not found" -ErrorAction Stop } } else { $options.NodeId = $enterprise.enterpriseData.RootNode.Id } $enterprise.mspData.UpdateManagedCompany($mc.EnterpriseId, $options).GetAwaiter().GetResult() } New-Alias -Name kemc -Value Edit-KeeperManagedCompany Register-ArgumentCompleter -CommandName Edit-KeeperManagedCompany -ParameterName Addons -ScriptBlock $Keeper_MspAddonName class MspDailySnapshotAddon { [string]$Addon [int]$Units } class MspDailySnapshotRecord { [System.DateTime]$Date [int]$McEnterpriseId [int]$LicenseCount [string]$ProductPlan [string]$FilePlan [MspDailySnapshotAddon[]]$Addons } function Get-MspBillingReport { <# .Synopsis Runs MSP Billing Report .Parameter Month Report Month 1-12 .Parameter Year Report Year 20xx #> [CmdletBinding()] Param ( [Parameter(Mandatory = $false)][int] $Month, [Parameter(Mandatory = $false)][int] $Year ) $dt = Get-Date if (0 -eq $Year) { $Year = $dt.Year } if (0 -eq $Month) { $Month = $dt.Month - 1 if ($Month -le 0) { $Year -= 1 $Month = 12 } } $auth = [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'mapping/addons') $rq = New-Object BI.MappingAddonsRequest $rs = $auth.ExecuteAuthRest($url, $rq, [BI.MappingAddonsResponse]).GetAwaiter().GetResult() $filePlans = @{ 4 = '100GB' 7 = '1TB' 8 = '10TB' } foreach ($fp in $rs.FilePlans) { $filePlans[$fp.Id] = $fp.Name } $addons = @{} foreach ($aon in $rs.Addons) { $addons[$aon.Id] = $aon.Name } $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'reporting/daily_snapshot') $rq = New-Object BI.ReportingDailySnapshotRequest $rq.Month = $Month $rq.Year = $Year $rs = $auth.ExecuteAuthRest($url, $rq, [BI.ReportingDailySnapshotResponse]).GetAwaiter().GetResult() foreach ($rec in $rs.Records) { $r = New-Object MspDailySnapshotRecord $r.Date = [KeeperSecurity.Utils.DateTimeOffsetExtensions]::FromUnixTimeMilliseconds($rec.date).Date $r.McEnterpriseId = $rec.mcEnterpriseId $r.LicenseCount = $rec.maxLicenseCount switch ($rec.MaxBasePlanId) { 1 { $r.ProductPlan = 'business' } 2 { $r.ProductPlan = 'businessPlus' } 10 { $r.ProductPlan = 'enterprise' } 11 { $r.ProductPlan = 'enterprisePlus' } default { $r.ProductPlan = "Plan #$($r.rec)" } } if ($rec.maxFilePlanTypeId) { $r.FilePlan = $filePlans[$rec.maxFilePlanTypeId] if (-not $r.FilePlan) { $r.FilePlan = "Storage Plan #$($rec.maxFilePlanTypeId)" } } foreach ($addon in $rec.addons) { if ($addon.maxAddonId) { $a = New-Object MspDailySnapshotAddon $a.Addon = $addons[$addon.maxAddonId] if (-not $a.Addon) { $a.Addon = "Addon # $($addon.maxAddonId)" } $a.Units = $addon.units $r.Addons += $a } } $r } } function findManagedCompany { Param ( [string]$mc ) $enterprise = getMspEnterprise $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $mc) -or ($_.EnterpriseName -eq $mc) } | Select-Object -First 1 } function findEnterpriseNode { Param ( [string]$node ) $enterprise = getEnterprise if ($node -eq $enterprise.loader.EnterpriseName) { return $enterprise.enterpriseData.RootNode } $enterprise.enterpriseData.Nodes | Where-Object { ($_.Id -eq $node) -or ($_.DisplayName -eq $node) } | Select-Object -First 1 } function getMspEnterprise { [Enterprise] $enterprise = $Script:Context.Enterprise if (-not $enterprise) { $enterprise = getEnterprise } if ($enterprise.enterpriseData.EnterpriseLicense -and $enterprise.enterpriseData.EnterpriseLicense.LicenseStatus -like "msp*") { return $enterprise } Write-Error -Message "Not a MSP (Managed Service Provider)" -ErrorAction Stop } # SIG # Begin signature block # MIIR1wYJKoZIhvcNAQcCoIIRyDCCEcQCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUXfMx4UtfZr7cCx8qaopT8amC # Q4Kggg4jMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B # AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk # IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5 # WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP # DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz # ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq # HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC # fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD # G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO # kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD # K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4 # R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN # Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I # U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB # Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA # FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4 # oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN # AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT # Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT # auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9 # ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37 # 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0 # HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL # 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1 # 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8 # M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF # hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy # 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHazCC # BVOgAwIBAgIQAnNTGQOIer82vZ1cJyDJDjANBgkqhkiG9w0BAQsFADBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMB4XDTIyMDIwMjAwMDAwMFoXDTI1MDIwMTIzNTk1OVowcDELMAkGA1UEBhMC # VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK # ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5 # IEluYy4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDNgTqmksdjUyKF # 5zWkDyghf0PLWJWdzG0TX2j8B4J55xwt+B17zd4Xc3n0dvmSVAyPQANeN+mP1chf # 4LTRn9h4jWb8Jsfn+JzyRhj/gYINYvBnpRpqoM0z7QC9Ebwj5T61Cogm9EKGcrG+ # Ujh+Z7pTqfSUrHD8NMXhDL/UpVn+w0Pb4qg7o7AH2o94n7u/qTlMGZCs+VCAvhNr # wPABxvFY07YGb9t5/IZlPE8vG3p1vw2SbgREgFWSEQFj6X2CIhSrbiFCW/766/Mq # EX6qm+RyF71fD4d3yShg39guaE9o+TBl1MqVCje4bK/wGoNxCho0I6Z1fBBKloyp # vlx3gPpU7tJJ+KpuIiel9R9dGQuscqKzehPtbRc9Abr9ThN/HrLg1sFFVMdn2oMR # 63QCUdz+B1NuS7Ap8Ti7XvAPJHzEuQDcdMcRbkIfllJVqrb9UXEFwOPzvRU2KrcQ # 42Jlnn4T+WenPx5Nr3o/o08WLhLTicEK1OacEowyRLBmih4Gxpdk3fUAVCEkdvmq # TSydQpl1Bk8V88dxCkB1wMZyFYLNcddBL4kUbwjso/z6f2TtfAVYs/iIRWqs7Xqt # 4F2BBqobOGMymwg6VgVjjzDIgJCZSbjpq2IoVTci5vli6vxgSoZ01fccSaKa4Izm # B7DbobIkIjLgPqpnCkqlHuJj5hQ9twIDAQABo4ICBjCCAgIwHwYDVR0jBBgwFoAU # aDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFCZd3/KEdT2t5WTIFb3TUaM4 # sTikMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0f # BIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGg # T4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29k # ZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZn # gQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BT # MIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln # aWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIx # Q0ExLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQAGyDM3Cbxq # Auhr8O2xwOoCSVKmFkXqicwlrugwLW44Y4WX+imvTrGfjj2S99k/4D5H8DgtW/u8 # tOxcCoehTOCIEwP5TLrieHppsqAR4jaJRcdAHOWiJ1bmwQBv/cBU9vaelL0oXxxf # TwD9oDaQNuyq6p+nIJMqbKv33b8AWGe3zq4JwblaFjRDL5lUDNhPx3g/pm7JhnbX # 7QTKydAJvpbuP5cqUH1GEeVMjc5vEELtGNy/fy7Ekm4dndX4IZcFXW5L0Lx8cReB # hIZwA+pzdzTWQYvfxgRMb/j2uY+Tkb6Wz2x9BBS1UXiP2qrs3rhQv8DZRkUSqnko # YD4uJP8gk8BXcIXIThgEF2YCq2hBiwna5Ijbwkmjn1lWwGv15SznTOTnrVApJqB1 # tB2s2ovUNV4CyKDPVr+9/CS6IQJfEZeHYcYLsIga2q5NZCrqZAasBfCwALVkALos # DIWhs33vYLfETMSuk5Hd5JC+hLjVM3ZJwslvnc/wec2r0GNAiZ3a1aweC7NYuzRz # 29Mi/eR/4ylmCltyZqYJ1JcC/g6eY2Q0xkdWc8P0yHfQ/3fe7+AKXXKNjfv858GW # lg1Ck2lvwPdLqJWqj1FwJPiGRCB+WulPe0csTyWnf+ed45TXx69tZ6BZr0Xr2jXu # ybBdJtg0NN0a62xxWrmX42CgsrzHzRm7OzGCAx4wggMaAgEBMH0waTELMAkGA1UE # BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy # dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB # MQIQAnNTGQOIer82vZ1cJyDJDjAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEK # MAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3 # AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQU1AG5E5h5dkFoLoDk # L8wKWk4QoHIwDQYJKoZIhvcNAQEBBQAEggIAEeUEJMTSuHwRkZ9IzOFc/9m3biPT # t7iYrrC2n87Erf2JmRYGPwZV1Yn7ixb4tGG/ckFEJ36HORaMAXiJ4slielq0CFX/ # C2iDOunGmGQLGPpCnrow99TFfJZAmXliyT/Et8KrNmGsYApicVfPjjE2A1it6qeB # z/0MT05d32uL3wzhUvtpfHAkHBFQlKTnrJXYi/oR6uXUdk3jf0lK/hZy941QQr1M # TAskRKDZZEZuOnWTcCm3JQcKGwSdj1TU51CDBb1l7Nz9r5b4Qjs5olbeqppGLz2H # gPYKRyAgIDsWeim2MIqjypyOQaWCTOURtthGfE16SgQ/02ch7EkwjhyDSO6HWwUk # f9tin+qFXsZgBOfBMuv+z2co12S6Frfz8gp2CKFFNA4DU1cbR+R/SOC7DAmywmrz # Cd7yKf+94xPhBQ/6vZeI2+bTq4vMoZqKvgyOeOAWzBqTrr7Ew4lHpPpcs7neG/9T # pXDnWTlL+JNdYQmvatrVzl2NTmvn1NJUShCR4dsNvFsymJf2QYlkSE49av/I949Y # BuHfBOcC8XqWoPAjbvi/DPMlckjujmG/HaL6kubH1r9KDX66y2IjA+BTlpDLKtH/ # BJJ0j7wR70ncnvQt2XbVL5VFfNNbCD4I2enzgYhsNi9hoEGl9s1TpHZFOrWWOLOc # 8/TCzbXus3Zn3/8= # SIG # End signature block |