Files
ping-mee-self-service-platform/context-resources/AD-ProfilePicture-Sync.ps1
T
Ebbe BaßandClaude Sonnet 5.5 24de5878ed Add BMAD planning artifacts: brief, PRD, architecture, UX, spec, tickets
Includes the BMAD install config, the initiative ticket tree, the portal
context-resources scripts, and the .gitignore change that tracks BMAD files
(generated _bmad/render/ is ignored).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sk72AxLwQnYttF6VFSxQLt
2026-10-15 13:33:02 +02:00

290 lines
15 KiB
PowerShell

# AD-ProfilePicture-Sync.ps1
# Runs on the Domain Controller via Task Scheduler as a service account or SYSTEM
# Syncs profile pictures from the fileshare to AD attributes for all users in the target OU
Import-Module ActiveDirectory
$Config = @{
SourcePath = "\\192.168.190.40\DC_data\ProfilePictures\source"
DefaultImage = "\\192.168.190.40\DC_data\ProfilePictures\default\default.jpg"
ProcessedPath = "\\192.168.190.40\DC_data\ProfilePictures\processed"
LogPath = "\\192.168.190.40\DC_data\ProfilePictures\logs\sync_log.txt"
TargetOU = "OU=Organisation,DC=ping-mee,DC=local"
MaxPhotoBytes = 100KB
}
function Write-Log($msg) {
$line = "[$(Get-Date -f 'yyyy-MM-dd HH:mm:ss')] $msg"
Add-Content -Path $Config.LogPath -Value $line
Write-Host $line
}
function Resize-Image {
param(
[string]$InputPath,
[string]$OutputPath,
[int]$Size,
[int]$Quality = 90
)
Add-Type -AssemblyName System.Drawing
$src = [System.Drawing.Image]::FromFile($InputPath)
$ratioX = $Size / $src.Width
$ratioY = $Size / $src.Height
$ratio = if ($ratioX -le $ratioY) { $ratioX } else { $ratioY }
$newWidth = [int]($src.Width * $ratio)
$newHeight = [int]($src.Height * $ratio)
$bmp = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$g.Clear([System.Drawing.Color]::White)
$g.DrawImage($src, 0, 0, $newWidth, $newHeight)
$encoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($encoder, $Quality)
$codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq 'image/jpeg' }
$bmp.Save($OutputPath, $codec, $encoderParams)
$g.Dispose(); $bmp.Dispose(); $src.Dispose()
}
function Set-ADProfilePhoto {
param($User, [byte[]]$PhotoBytes)
# thumbnailPhoto — primary Microsoft attribute, used by Outlook, most LDAP apps
Set-ADUser -Identity $User -Replace @{ thumbnailPhoto = $PhotoBytes }
# jpegPhoto — RFC 2798 / inetOrgPerson, used by Nextcloud, GitLab, etc.
Set-ADUser -Identity $User -Replace @{ jpegPhoto = $PhotoBytes }
# photo — inetOrgPerson, broad LDAP compatibility
try {
Set-ADUser -Identity $User -Replace @{ photo = $PhotoBytes }
} catch {
Write-Log " [WARN] 'photo' attribute not writable for $($User.SamAccountName): $_"
}
}
# --- Main Loop ---
$users = Get-ADUser -SearchBase $Config.TargetOU -Filter * -Properties thumbnailPhoto, jpegPhoto, SID
foreach ($user in $users) {
$sam = $user.SamAccountName
Write-Log "Processing: $sam"
# Resolve source image
$imgPath = Join-Path $Config.SourcePath "$sam.jpg"
if (-not (Test-Path $imgPath)) {
Write-Log " No specific photo found, using default."
$imgPath = $Config.DefaultImage
}
# GUARD: Abort if resolved image still doesn't exist
if (-not (Test-Path $imgPath)) {
Write-Log " [ERROR] Image not found at '$imgPath'. Skipping $sam."
continue
}
# Generate processed versions — both from the original source
$processed96 = Join-Path $Config.ProcessedPath "${sam}_96.jpg"
$processed448 = Join-Path $Config.ProcessedPath "${sam}_448.jpg"
try {
Resize-Image -InputPath $imgPath -OutputPath $processed96 -Size 96
Resize-Image -InputPath $imgPath -OutputPath $processed448 -Size 448
} catch {
Write-Log " [ERROR] Failed to resize image for $sam : $_"
continue
}
# AD only receives the 96px version to stay within the 100KB attribute limit
$photoBytes = [System.IO.File]::ReadAllBytes($processed96)
if ($photoBytes.Length -gt $Config.MaxPhotoBytes) {
Write-Log " [ERROR] Photo for $sam exceeds 100KB after resize. Skipping AD write."
continue
}
# Write hash file for change detection on next run
$hash = (Get-FileHash $imgPath -Algorithm MD5).Hash
$hashFile = Join-Path $Config.ProcessedPath "${sam}.md5"
$hash | Set-Content $hashFile
Set-ADProfilePhoto -User $user -PhotoBytes $photoBytes
Write-Log " AD attributes updated (thumbnailPhoto, jpegPhoto, photo)."
}
Write-Log "Sync complete."
# SIG # Begin signature block
# MIIe7gYJKoZIhvcNAQcCoIIe3zCCHtsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVspl2f++k4gMH4DhClIJlSS6
# HvGgghkyMIIGFDCCA/ygAwIBAgIQeiOu2lNplg+RyD5c9MfjPzANBgkqhkiG9w0B
# AQwFADBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS4w
# LAYDVQQDEyVTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFJvb3QgUjQ2MB4X
# DTIxMDMyMjAwMDAwMFoXDTM2MDMyMTIzNTk1OVowVTELMAkGA1UEBhMCR0IxGDAW
# BgNVBAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJsaWMg
# VGltZSBTdGFtcGluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGK
# AoIBgQDNmNhDQatugivs9jN+JjTkiYzT7yISgFQ+7yavjA6Bg+OiIjPm/N/t3nC7
# wYUrUlY3mFyI32t2o6Ft3EtxJXCc5MmZQZ8AxCbh5c6WzeJDB9qkQVa46xiYEpc8
# 1KnBkAWgsaXnLURoYZzksHIzzCNxtIXnb9njZholGw9djnjkTdAA83abEOHQ4ujO
# GIaBhPXG2NdV8TNgFWZ9BojlAvflxNMCOwkCnzlH4oCw5+4v1nssWeN1y4+RlaOy
# wwRMUi54fr2vFsU5QPrgb6tSjvEUh1EC4M29YGy/SIYM8ZpHadmVjbi3Pl8hJiTW
# w9jiCKv31pcAaeijS9fc6R7DgyyLIGflmdQMwrNRxCulVq8ZpysiSYNi79tw5RHW
# ZUEhnRfs/hsp/fwkXsynu1jcsUX+HuG8FLa2BNheUPtOcgw+vHJcJ8HnJCrcUWhd
# Fczf8O+pDiyGhVYX+bDDP3GhGS7TmKmGnbZ9N+MpEhWmbiAVPbgkqykSkzyYVr15
# OApZYK8CAwEAAaOCAVwwggFYMB8GA1UdIwQYMBaAFPZ3at0//QET/xahbIICL9AK
# PRQlMB0GA1UdDgQWBBRfWO1MMXqiYUKNUoC6s2GXGaIymzAOBgNVHQ8BAf8EBAMC
# AYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDCDARBgNV
# HSAECjAIMAYGBFUdIAAwTAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5zZWN0
# aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1waW5nUm9vdFI0Ni5jcmwwfAYI
# KwYBBQUHAQEEcDBuMEcGCCsGAQUFBzAChjtodHRwOi8vY3J0LnNlY3RpZ28uY29t
# L1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdSb290UjQ2LnA3YzAjBggrBgEFBQcw
# AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIBABLX
# eyCtDjVYDJ6BHSVY/UwtZ3Svx2ImIfZVVGnGoUaGdltoX4hDskBMZx5NY5L6SCcw
# DMZhHOmbyMhyOVJDwm1yrKYqGDHWzpwVkFJ+996jKKAXyIIaUf5JVKjccev3w16m
# NIUlNTkpJEor7edVJZiRJVCAmWAaHcw9zP0hY3gj+fWp8MbOocI9Zn78xvm9XKGB
# p6rEs9sEiq/pwzvg2/KjXE2yWUQIkms6+yslCRqNXPjEnBnxuUB1fm6bPAV+Tsr/
# Qrd+mOCJemo06ldon4pJFbQd0TQVIMLv5koklInHvyaf6vATJP4DfPtKzSBPkKlO
# tyaFTAjD2Nu+di5hErEVVaMqSVbfPzd6kNXOhYm23EWm6N2s2ZHCHVhlUgHaC4AC
# MRCgXjYfQEDtYEK54dUwPJXV7icz0rgCzs9VI29DwsjVZFpO4ZIVR33LwXyPDbYF
# kLqYmgHjR3tKVkhh9qKV2WCmBuC27pIOx6TYvyqiYbntinmpOqh/QPAnhDgexKG9
# GX/n1PggkGi9HCapZp8fRwg8RftwS21Ln61euBG0yONM6noD2XQPrFwpm3GcuqJM
# f0o8LLrFkSLRQNwxPDDkWXhW+gZswbaiie5fd/W2ygcto78XCSPfFWveUOSZ5SqK
# 95tBO8aTHmEa4lpJVD7HrTEn9jb1EGvxOb1cnn0CMIIGKjCCBRKgAwIBAgITdQAA
# AA+pTsONn8YiVAAAAAAADzANBgkqhkiG9w0BAQsFADBHMRUwEwYKCZImiZPyLGQB
# GRYFbG9jYWwxGDAWBgoJkiaJk/IsZAEZFghwaW5nLW1lZTEUMBIGA1UEAxMLcGlu
# Zy1tZWUtQ0EwHhcNMjYwNDA5MDczOTM2WhcNMjcwNDA5MDczOTM2WjB8MRUwEwYK
# CZImiZPyLGQBGRYFbG9jYWwxGDAWBgoJkiaJk/IsZAEZFghwaW5nLW1lZTEVMBMG
# A1UECxMMT3JnYW5pc2F0aW9uMRcwFQYDVQQLEw5BZG1pbmlzdHJhdGlvbjEZMBcG
# A1UEAxMQSVQgQWRtaW5pc3RyYXRvcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBALCk9syN/9zSWis5l6RKd+Twg6GnkBhwkUn5LDwdALKc5bImd7rLCF9j
# +m6zWNEq4Lrl8382PSFLnCnXRd0MeecmMBRXEryLktcnl2OgFPiu87fodptBYRBp
# LpUyHB0XeJlT+plHgURfFIJ8vZwvNP+i0Ai1xmcKdlmUH3PQRVTg5QaH0kzHYPgf
# BNhsWXRujCjg23sR0sZ2seAUOX3KVfiGFyZswHF09MlxJPq05QR8TBTfK1InuTaT
# 1is38tCKEkANQjVt4yZ8KYV0YuM897oEZvtnwJEMDNP75H/3uZoIJ0v0dfUyjMHN
# DfKdt0aDxZpPTT9iICZl3EMveAN+l70CAwEAAaOCAtgwggLUMD0GCSsGAQQBgjcV
# BwQwMC4GJisGAQQBgjcVCIPqtkCCy4lzgsWRF4Xw1Q+BwbsoQISyshCFqrN4AgFk
# AgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDAbBgkrBgEE
# AYI3FQoEDjAMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBTroFoeAJDNgwWOwbsoP6+h
# n09ftjAfBgNVHSMEGDAWgBTgQNNlwwWCz4c1/FnAOF+J5D5/0DCByAYDVR0fBIHA
# MIG9MIG6oIG3oIG0hoGxbGRhcDovLy9DTj1waW5nLW1lZS1DQSxDTj1EQzEsQ049
# Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNv
# bmZpZ3VyYXRpb24sREM9cGluZy1tZWUsREM9bG9jYWw/Y2VydGlmaWNhdGVSZXZv
# Y2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50
# MIHABggrBgEFBQcBAQSBszCBsDCBrQYIKwYBBQUHMAKGgaBsZGFwOi8vL0NOPXBp
# bmctbWVlLUNBLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1T
# ZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXBpbmctbWVlLERDPWxvY2FsP2NB
# Q2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9y
# aXR5MDIGA1UdEQQrMCmgJwYKKwYBBAGCNxQCA6AZDBdpdC1hZG1pbkBwaW5nLW1l
# ZS5sb2NhbDBPBgkrBgEEAYI3GQIEQjBAoD4GCisGAQQBgjcZAgGgMAQuUy0xLTUt
# MjEtMzIxMTQ3Njk4My0xNjY0MTg4ODMzLTM5MDgzNjg2MDMtMTEwNDANBgkqhkiG
# 9w0BAQsFAAOCAQEAw+wwNb8CIqJaqpTzGgJ8TfS3Wt1y9qlNEWCfdyKjl3LbH7HU
# uJmXFrUiygxyWlDtHbD5bah4JlLprv/wSkAN8c3DqxGxTB06orLZNRXH/plR6R69
# wRD23GrxTGcP66iIRUnpDCiX+tXlRyQnxtb/7OPFSy1B/NYC6re74M7fV3cZ6/lU
# gxy0aLzwCWjgfzJvJMTDSsWJKKIHpdIktR2EhCkCdWJay+8j2SAmT+IG8i/MAXrc
# 6wmc4p/O17eAx0sx22hw6JPiA9TNFLfSGrPSzUjX3SD3OuoxPnJNpM4GY4kte5Hs
# lIQ8+KnsCf2oBsk7AciBlLTEuOshD7rtTom9hzCCBmIwggTKoAMCAQICEQCkKTtu
# Ht3XpzQIh616TrckMA0GCSqGSIb3DQEBDAUAMFUxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gUHVibGljIFRp
# bWUgU3RhbXBpbmcgQ0EgUjM2MB4XDTI1MDMyNzAwMDAwMFoXDTM2MDMyMTIzNTk1
# OVowcjELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDldlc3QgWW9ya3NoaXJlMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxMDAuBgNVBAMTJ1NlY3RpZ28gUHVibGljIFRp
# bWUgU3RhbXBpbmcgU2lnbmVyIFIzNjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBANOElfRupFN48j0QS3gSBzzclIFTZ2Gsn7BjsmBF659/kpA2Ey7NXK3M
# P6JdrMBNU8wdmkf+SSIyjX++UAYWtg3Y/uDRDyg8RxHeHRJ+0U1jHEyH5uPdk1tt
# iPC3x/gOxIc9P7Gn3OgW7DQc4x07exZ4DX4XyaGDq5LoEmk/BdCM1IelVMKB3WA6
# YpZ/XYdJ9JueOXeQObSQ/dohQCGyh0FhmwkDWKZaqQBWrBwZ++zqlt+z/QYTgEnZ
# o6dyIo2IhXXANFkCHutL8765NBxvolXMFWY8/reTnFxk3MajgM5NX6wzWdWsPJxY
# RhLxtJLSUJJ5yWRNw+NBqH1ezvFs4GgJ2ZqFJ+Dwqbx9+rw+F2gBdgo4j7CVomP4
# 9sS7CbqsdybbiOGpB9DJhs5QVMpYV73TVV3IwLiBHBECrTgUfZVOMF0KSEq2zk/L
# sfvehswavE3W4aBXJmGjgWSpcDz+6TqeTM8f1DIcgQPdz0IYgnT3yFTgiDbFGOFN
# t6eCidxdR6j9x+kpcN5RwApy4pRhE10YOV/xafBvKpRuWPjOPWRBlKdm53kS2aMh
# 08spx7xSEqXn4QQldCnUWRz3Lki+TgBlpwYwJUbR77DAayNwAANE7taBrz2v+Mnn
# ogMrvvct0iwvfIA1W8kp155Lo44SIfqGmrbJP6Mn+Udr3MR2oWozAgMBAAGjggGO
# MIIBijAfBgNVHSMEGDAWgBRfWO1MMXqiYUKNUoC6s2GXGaIymzAdBgNVHQ4EFgQU
# iGGMoSo3ZIEoYKGbMdCM/SwCzk8wDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQC
# MAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwSgYDVR0gBEMwQTA1BgwrBgEEAbIx
# AQIBAwgwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYG
# Z4EMAQQCMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly9jcmwuc2VjdGlnby5jb20v
# U2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNybDB6BggrBgEFBQcBAQRu
# MGwwRQYIKwYBBQUHMAKGOWh0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29j
# c3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggGBAAKBPqSGclEh+WWpLj1S
# iuHlm8xLE0SThI2yLuq+75s11y6SceBchpnKpxWaGtXc8dya1Aq3RuW//y3wMThs
# vT4fSba2AoSWlR67rA4fTYGMIhgzocsids0ct/pHaocLVJSwnTYxY2pE0hPoZAvR
# ebctbsTqENmZHyOVjOFlwN2R3DRweFeNs4uyZN5LRJ5EnVYlcTOq3bl1tI5poru9
# WaQRWQ4eynXp7Pj0Fz4DKr86HYECRJMWiDjeV0QqAcQMFsIjJtrYTw7mU81qf4FB
# c4u4swphLeKRNyn9DDrd3HIMJ+CpdhSHEGleeZ5I79YDg3B3A/fmVY2GaMik1Vm+
# FajEMv4/EN2mmHf4zkOuhYZNzVm4NrWJeY4UAriLBOeVYODdA1GxFr1ycbcUEGlU
# ecc4RCPgYySs4d00NNuicR4a9n7idJlevAJbha/arIYMEuUqTeRRbWkhJwMKmb9y
# EvppRudKyu1t6l21sIuIZqcpVH8oLWCxHS0LpDRF9Y4jijCCBoIwggRqoAMCAQIC
# EDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwG
# A1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3Qg
# UlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIxMDMyMjAwMDAwMFoXDTM4
# MDExODIzNTk1OVowVzELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGlt
# aXRlZDEuMCwGA1UEAxMlU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBSb290
# IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIid2LlFZ50d3ei5
# JoGaVFTAfEkFm8xaFQ/ZlBBEtEFAgXcUmanU5HYsyAhTXiDQkiUvpVdYqZ1uYoZE
# MgtHES1l1Cc6HaqZzEbOOp6YiTx63ywTon434aXVydmhx7Dx4IBrAou7hNGsKioI
# BPy5GMN7KmgYmuu4f92sKKjbxqohUSfjk1mJlAjthgF7Hjx4vvyVDQGsd5KarLW5
# d73E3ThobSkob2SL48LpUR/O627pDchxll+bTSv1gASn/hp6IuHJorEu6EopoB1C
# NFp/+HpTXeNARXUmdRMKbnXWflq+/g36NJXB35ZvxQw6zid61qmrlD/IbKJA6COw
# /8lFSPQwBP1ityZdwuCysCKZ9ZjczMqbUcLFyq6KdOpuzVDR3ZUwxDKL1wCAxgL2
# Mpz7eZbrb/JWXiOcNzDpQsmwGQ6Stw8tTCqPumhLRPb7YkzM8/6NnWH3T9ClmcGS
# F22LEyJYNWCHrQqYubNeKolzqUbCqhSqmr/UdUeb49zYHr7ALL8bAJyPDmubNqMt
# uaobKASBqP84uhqcRY/pjnYd+V5/dcu9ieERjiRKKsxCG1t6tG9oj7liwPddXEcY
# GOUiWLm742st50jGwTzxbMpepmOP1mLnJskvZaN5e45NuzAHteORlsSuDt5t4BBR
# CJL+5EZnnw0ezntk9R8QJyAkL6/bAgMBAAGjggEWMIIBEjAfBgNVHSMEGDAWgBRT
# eb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU9ndq3T/9ARP/FqFsggIv0Ao9
# FCUwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEwYDVR0lBAwwCgYI
# KwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0
# dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9u
# QXV0aG9yaXR5LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
# Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAA6+ZUHtaES4
# 5aHF1BGH5Lc7JYzrftrIF5Ht2PFDxKKFOct/awAEWgHQMVHol9ZLSyd/pYMbaC0I
# Z+XBW9xhdkkmUV/KbUOiL7g98M/yzRyqUOZ1/IY7Ay0YbMniIibJrPcgFp73WDnR
# DKtVutShPSZQZAdtFwXnuiWl8eFARK3PmLqEm9UsVX+55DbVIz33Mbhba0HUTEYv
# 3yJ1fwKGxPBsP/MgTECimh7eXomvMm0/GPxX2uhwCcs/YLxDnBdVVlxvDjHjO1cu
# wbOpkiJGHmLXXVNbsdXUC2xBrq9fLrfe8IBsA4hopwsCj8hTuwKXJlSTrZcPRVSc
# cP5i9U28gZ7OMzoJGlxZ5384OKm0r568Mo9TYrqzKeKZgFo0fj2/0iHbj55hc20j
# fxvK3mQi+H7xpbzxZOFGm/yVQkpo+ffv5gdhp+hv1GDsvJOtJinJmgGbBFZIThbq
# I+MHvAmMmkfb3fTxmSkop2mSJL1Y2x/955S29Gu0gSJIkc3z30vU/iXrMpWx2tS7
# UVfVP+5tKuzGtgkP7d/doqDrLF1u6Ci3TpjAZdeLLlRQZm867eVeXED58LXd1Dk6
# UvaAhvmWYXoiLz4JA5gPBcz7J311uahxCweNxE+xxxR3kT0WKzASo5G/PyDez6NH
# dIUKBeE3jDPs2ACc6CkJ1Sji4PKWVT0/MYIFJjCCBSICAQEwXjBHMRUwEwYKCZIm
# iZPyLGQBGRYFbG9jYWwxGDAWBgoJkiaJk/IsZAEZFghwaW5nLW1lZTEUMBIGA1UE
# AxMLcGluZy1tZWUtQ0ECE3UAAAAPqU7DjZ/GIlQAAAAAAA8wCQYFKw4DAhoFAKB4
# MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQB
# gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkE
# MRYEFCSv+GJlt5QapIL4BtjV31KgrTQfMA0GCSqGSIb3DQEBAQUABIIBAF1PE5ri
# iMlYNkjQsr3+Z1SJ/EItpyYlEZrT13t42WraDTIR+FxggkCTOaM6/FSRUXO8kMCu
# CiFx0IVl50P/YBbZ/l9kY0DD9dHcfoeCOaF5KyfwnZONQbSdMq/nydDqKtXHMu6/
# VuMGtoP+SwfR9dWWzoooCKcnx5InVcl2XJR5yvet11DuoDFVmbxlKfqaIX2ieZ4e
# TJ431lLN4A5W5Q+1a2GEw3MPO6IkT68EsqaNuygscKGOLMrkZxpgpvXTM4C3LPeG
# EFlvTa+TD+ScTIl3djz38LsuppSN0XdPbpP9h8FkeWfa8wo/v061toA7RON9t4cA
# T+g9bj+/UPaEA3OhggMjMIIDHwYJKoZIhvcNAQkGMYIDEDCCAwwCAQEwajBVMQsw
# CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDEyNT
# ZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNgIRAKQpO24e3denNAiH
# rXpOtyQwDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB
# MBwGCSqGSIb3DQEJBTEPFw0yNjA0MTkxMTU5MDVaMD8GCSqGSIb3DQEJBDEyBDDb
# /5Xcb4yXXq8UPocqdx39gipy8qf2UiiIqbBSW4YWvxWqqsuezH7ONKwPpwu38Asw
# DQYJKoZIhvcNAQEBBQAEggIACh+I1I6l7UW7P6vre696SpxrUTRFOBAk4HwQOkCE
# F5owI0x2Gwas9mNZEuUEvZEfOuJ/0Y6LDq3T+dJADV/lHvqkVlOZipDJ0cQaNgeE
# AzdnXm/xirXfuzocjDVQXR+ucvUm2SFTtOrWxF9m1ivdpjZUtN+Z94IuLVLfZ7GE
# nivwLBhMAU63lWZl2iSOnIhC8LtHxPtDlPDffCf88ng8p0jHjuWl3RbqcjxH0He2
# GoLZZ8UNxXDrH3QhASurk7ou6HyJbKXdE617CaPGBSBB07aIPtJmh789MXX2tCKZ
# lEV7c/Hd6f9K1j/tYBmt0e2tXWm1NeL/uta0owsLWAcIk1KQ1ZsXjOjjqHQdHphQ
# 21ab0nKZTjZROQMC3Rc1nvwZ/xG/mtLLQXS/kZMahaDj0e8fWhBU9rag27RLLECB
# eyat+DSCUA27BZo7mQt9kqT4EurjqFWVtGiFNDNtW+TzUeBr3Fl7md5ARWMf/5jJ
# KvmDAnwEZKPBRoOuaGpJfuy89vXcRYr4czBNoFGsBAwLWaIZKI2IuXNHM7ZUc/LJ
# 4UNNrBHl8Z4niaSC9i4uv3xi7zMtQpJKJzYiMpAjC3/zPcj8a0T+pGSGY/2DIRJj
# SALVk4wBQJyJxBZAnw4OifhAEgG6edHDQmPEPep2RaFk1TOJBnkG3WyCxF/YurD/
# gB0=
# SIG # End signature block