From c7a71721918e7736e200f57b60f3de5061a60237 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Tue, 10 Nov 2020 11:02:16 +0100 Subject: [PATCH 1/6] Updates help for certificate installation --- .../Install-IcingaAgentCertificates.psm1 | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 index 8aee956..0ae7f4e 100644 --- a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 +++ b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 @@ -1,3 +1,47 @@ +<# +.SYNOPSIS + Installs the required certificates for the Icinga Agent including the entire + signing process either by using the CA-Proxy, the CA-Server directly or + by manually signing the request on the CA master +.DESCRIPTION + Installs the required certificates for the Icinga Agent including the entire + signing process either by using the CA-Proxy, the CA-Server directly or + by manually signing the request on the CA master +.FUNCTIONALITY + Creates, installs and signs required certificates for the Icinga Agent +.EXAMPLE + # Connect to the CA server with a ticket to fully complete the request + PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com' -Ticket 'my_secret_ticket'; +.EXAMPLE + # Connect to the CA server without a ticket, to create the sign request on the master + PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com'; +.EXAMPLE + # Uses the Icinga ca.crt from a local filesystem and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing + PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'C:\users\public\icinga2\ca.crt'; +.EXAMPLE + # Uses the Icinga ca.crt from a web resource and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing + PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'https://example.com/icinga2/ca.crt'; +.PARAMETER Hostname + The hostname of the local system. Has to match the object name within the Icinga configuration +.PARAMETER Endpoint + The address of either the Icinga CA master or a parent node of the Agent to transmit the request to the CA master +.PARAMETER Port + The port used for Icinga communication. Uses 5665 as default +.PARAMETER CACert + Allows to specify the path to the ca.crt from the Icinga CA master on a local, network or web share to allow certificate generation + in case the Icinga Agent is not able to connect to it's parent hosts +.PARAMETER Ticket + The ticket number for the signing request which is either generated by Icinga 2 or the Icinga Director +.PARAMETER Force + Ignores existing certificates and will force the creation, overriding existing certificates +.INPUTS + System.String +.OUTPUTS + System.Boolean +.LINK + https://github.com/Icinga/icinga-powershell-framework +#> + function Install-IcingaAgentCertificates() { param( From ee4e890d2efd07cb8a362849bf6af22630fe597c Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Thu, 12 Nov 2020 14:30:59 +0100 Subject: [PATCH 2/6] Fixes Icinga API being disabled after cert install --- doc/31-Changelog.md | 1 + lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index 1ce5617..6344dca 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -22,6 +22,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic ### Bugfixes * [#059](https://github.com/Icinga/icinga-powershell-framework/issues/059), [#060](https://github.com/Icinga/icinga-powershell-framework/pull/060) Fixes interface handling for multiple interfaces and returns only the main interface by fallback to routing table and adds support for Windows 2008 R2 +* [#114](https://github.com/Icinga/icinga-powershell-framework/issues/114)[#146](https://github.com/Icinga/icinga-powershell-framework/pull/146) Fixes Icinga Agent API being wrongly disabled after successful certificate configuration and installation * [#127](https://github.com/Icinga/icinga-powershell-framework/issues/127) Fixes wrong error message on failed MSSQL connection due to database not reachable by using `-IntegratedSecurity` * [#128](https://github.com/Icinga/icinga-powershell-framework/issues/128) Fixes unhandled output from loading `System.Reflection.Assembly` which can cause weird side effects for plugin outputs * [#130](https://github.com/Icinga/icinga-powershell-framework/issues/130) Fix crash while running services as background task to collect metrics over time by missing Performance Counter cache initialisation diff --git a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 index 9fdede3..8493ff0 100644 --- a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 +++ b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 @@ -561,7 +561,7 @@ function Start-IcingaAgentInstallWizard() Install-IcingaAgentBaseFeatures; $CertsInstalled = Install-IcingaAgentCertificates -Hostname $Hostname -Endpoint $CAEndpoint -Port $CAPort -CACert $CAFile -Ticket $Ticket; Write-IcingaAgentApiConfig -Port $CAPort; - if ($EmptyCA -eq $TRUE -Or $CertsInstalled -eq $FALSE) { + if ($EmptyCA -eq $TRUE -And $CertsInstalled -eq $FALSE) { Disable-IcingaAgentFeature 'api'; Write-IcingaConsoleWarning ` -Message '{0}{1}{2}{3}{4}' ` From a5e7e2b0dca412eb0f1abd054e395ae5151d9ee6 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Thu, 12 Nov 2020 15:46:05 +0100 Subject: [PATCH 3/6] Fix error on SSL reconfigure for name changes --- doc/31-Changelog.md | 1 + .../Install-IcingaAgentCertificates.psm1 | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index 6344dca..8aaa8e6 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -26,6 +26,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#127](https://github.com/Icinga/icinga-powershell-framework/issues/127) Fixes wrong error message on failed MSSQL connection due to database not reachable by using `-IntegratedSecurity` * [#128](https://github.com/Icinga/icinga-powershell-framework/issues/128) Fixes unhandled output from loading `System.Reflection.Assembly` which can cause weird side effects for plugin outputs * [#130](https://github.com/Icinga/icinga-powershell-framework/issues/130) Fix crash while running services as background task to collect metrics over time by missing Performance Counter cache initialisation +* [#133](https://github.com/Icinga/icinga-powershell-framework/issues/133), [#147](https://github.com/Icinga/icinga-powershell-framework/pull/147) Fixes an issue while changing the hostname between upper/lower case which might cause unwanted exceptions on one hand but also required manual signing of requests on the CA master as the signing process was not completed * [#138](https://github.com/Icinga/icinga-powershell-framework/issues/138) Fixes possible value overflow on `Convert-Bytes` while converting from anything larger than MB to Bytes * [#140](https://github.com/Icinga/icinga-powershell-framework/issues/140) Fixes version fetching for not loaded modules during upgrades/plugin calls with `Get-IcingaPowerShellModuleVersion` * [#143](https://github.com/Icinga/icinga-powershell-framework/issues/143) Fixes the annoying hint from the analyzer to check space before open brace diff --git a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 index 0ae7f4e..c8f9a54 100644 --- a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 +++ b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 @@ -82,6 +82,9 @@ function Install-IcingaAgentCertificates() Write-IcingaConsoleError 'Failed to generate host certificate'; return $FALSE; } + + # Once we generated new host certificates, we always require to sign them if possible + $Force = $TRUE; } if ([string]::IsNullOrEmpty($Endpoint) -And [string]::IsNullOrEmpty($CACert)) { @@ -226,8 +229,9 @@ function Test-IcingaAgentCertificates() return $FALSE; } - [string]$hostCRT = [string]::Format('{0}.crt', $Hostname); - [string]$hostKEY = [string]::Format('{0}.key', $Hostname); + [string]$hostCRT = [string]::Format('{0}.crt', $Hostname); + [string]$hostKEY = [string]::Format('{0}.key', $Hostname); + [bool]$CertNameInvalid = $FALSE; $certificates = Get-ChildItem -Path $CertDirectory; # Now loop each file and match their name with our hostname @@ -236,11 +240,18 @@ function Test-IcingaAgentCertificates() $file = $cert.Name.Replace('.key', '').Replace('.crt', ''); if (-Not ($file -clike $Hostname)) { Write-IcingaConsoleWarning ([string]::Format('Certificate file {0} is not matching the hostname {1}. Certificate generation is required.', $cert.Name, $Hostname)); - return $FALSE; + $CertNameInvalid = $TRUE; + break; } } } + if ($CertNameInvalid) { + Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostCRT) -Force; + Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostKEY) -Force; + return $FALSE; + } + Write-IcingaConsoleNotice 'Icinga host certificates are present and valid. No generation required'; return $TRUE; From f9f095e16bf5d53768d505cc1c782cb23d866f72 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Wed, 18 Nov 2020 10:45:22 +0100 Subject: [PATCH 4/6] Adds support to add/remove/test Wmi permissions You can now use 'Add-IcingaWmiPermissions' to add permissions for a specific user and namespace and remove them with 'Remove-IcingaWmiPermissions' --- doc/31-Changelog.md | 1 + lib/core/tools/Get-IcingaUserSID.psm1 | 14 +-- lib/core/tools/Split-IcingaUserDomain.psm1 | 80 +++++++++++++ lib/wmi/Add-IcingaWmiPermissions.psm1 | 113 ++++++++++++++++++ .../Get-IcingaWindowsInformation.psm1 | 31 +++++ lib/wmi/Get-IcingaWmiSecurityData.psm1 | 60 ++++++++++ lib/wmi/Icinga_WBEM_Security.psm1 | 59 +++++++++ lib/wmi/New-IcingaWmiPermissionMask.psm1 | 54 +++++++++ lib/wmi/Remove-IcingaWmiPermissions.psm1 | 70 +++++++++++ .../Test-IcingaWindowsInformation.psm1 | 8 +- lib/wmi/Test-IcingaWmiPermissions.psm1 | 92 ++++++++++++++ 11 files changed, 566 insertions(+), 16 deletions(-) create mode 100644 lib/core/tools/Split-IcingaUserDomain.psm1 create mode 100644 lib/wmi/Add-IcingaWmiPermissions.psm1 rename lib/{core/framework => wmi}/Get-IcingaWindowsInformation.psm1 (72%) create mode 100644 lib/wmi/Get-IcingaWmiSecurityData.psm1 create mode 100644 lib/wmi/Icinga_WBEM_Security.psm1 create mode 100644 lib/wmi/New-IcingaWmiPermissionMask.psm1 create mode 100644 lib/wmi/Remove-IcingaWmiPermissions.psm1 rename lib/{core/framework => wmi}/Test-IcingaWindowsInformation.psm1 (92%) create mode 100644 lib/wmi/Test-IcingaWmiPermissions.psm1 diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index 8aaa8e6..87eb16e 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -18,6 +18,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#139](https://github.com/Icinga/icinga-powershell-framework/pull/139) Add Cmdlet `Start-IcingaShellAsUser` to open an Icinga Shell as different user for testing * [#141](https://github.com/Icinga/icinga-powershell-framework/pull/141) Adds Cmdlet `Convert-IcingaPluginThresholds` as generic approach to convert Icinga Thresholds with units to the lowest unit of this type. * [#134](https://github.com/Icinga/icinga-powershell-framework/pull/134) Adds Cmdlet `Test-IcingaWindowsInformation` to check if a WMI class exist and if we can fetch data from it. In addition we add support for binary value comparison with the new Cmdlet `Test-IcingaBinaryOperator` +* [#149](https://github.com/Icinga/icinga-powershell-framework/pull/149) Adds support to add Wmi permissions for a specific user and namespace with `Add-IcingaWmiPermissions`. In addition you can remove users from Wmi namespaces by using `Remove-IcingaWmiPermissions` ### Bugfixes diff --git a/lib/core/tools/Get-IcingaUserSID.psm1 b/lib/core/tools/Get-IcingaUserSID.psm1 index 1a55a54..7a9a1c0 100644 --- a/lib/core/tools/Get-IcingaUserSID.psm1 +++ b/lib/core/tools/Get-IcingaUserSID.psm1 @@ -8,20 +8,10 @@ function Get-IcingaUserSID() $User = 'NT Authority\SYSTEM'; } - [string]$Username = ''; - [string]$Domain = ''; - - if ($User.Contains('\')) { - $TmpArray = $User.Split('\'); - $Domain = $TmpArray[0]; - $Username = $TmpArray[1]; - } else { - $Domain = Get-IcingaNetbiosName; - $Username = $User; - } + $UserData = Split-IcingaUserDomain -User $User; try { - $NTUser = New-Object System.Security.Principal.NTAccount($Domain, $Username); + $NTUser = New-Object System.Security.Principal.NTAccount($UserData.Domain, $UserData.User); $SecurityData = $NTUser.Translate([System.Security.Principal.SecurityIdentifier]); } catch { throw $_.Exception; diff --git a/lib/core/tools/Split-IcingaUserDomain.psm1 b/lib/core/tools/Split-IcingaUserDomain.psm1 new file mode 100644 index 0000000..15d3675 --- /dev/null +++ b/lib/core/tools/Split-IcingaUserDomain.psm1 @@ -0,0 +1,80 @@ +<# +.SYNOPSIS + Splits a username containing a domain into a hashtable to easily use both values independently. + If no domain is specified the hostname will used as "local domain" +.DESCRIPTION + Splits a username containing a domain into a hashtable to easily use both values independently. + If no domain is specified the hostname will used as "local domain" +.PARAMETER User + A user object either containing only the user or domain information +.EXAMPLE + PS>Split-IcingaUserDomain -User 'icinga'; + + Name Value + ---- ----- + User icinga + Domain icinga-win +.EXAMPLE + PS>Split-IcingaUserDomain -User 'ICINGADOMAIN\icinga'; + + Name Value + ---- ----- + User icinga + Domain ICINGADOMAIN +.EXAMPLE + PS>Split-IcingaUserDomain -User 'icinga@ICINGADOMAIN'; + + Name Value + ---- ----- + User icinga + Domain ICINGADOMAIN +.EXAMPLE + PS>Split-IcingaUserDomain -User '.\icinga'; + + Name Value + ---- ----- + User icinga + Domain icinga-win +.INPUTS + System.String +.OUTPUTS + System.Hashtable +#> + +function Split-IcingaUserDomain() +{ + param ( + $User + ); + + if ([string]::IsNullOrEmpty($User)) { + Write-IcingaConsoleError 'Please enter a valid username'; + return ''; + } + + [array]$UserData = @(); + + if ($User.Contains('\')) { + $UserData = $User.Split('\'); + } elseif ($User.Contains('@')) { + [array]$Split = $User.Split('@'); + $UserData = @( + $Split[1], + $Split[0] + ); + } else { + $UserData = @( + (Get-IcingaNetbiosName), + $User + ); + } + + if ([string]::IsNullOrEmpty($UserData[0]) -Or $UserData[0] -eq '.' -Or $UserData[0] -eq 'BUILTIN') { + $UserData[0] = (Get-IcingaNetbiosName); + } + + return @{ + 'Domain' = $UserData[0]; + 'User' = $UserData[1]; + }; +} diff --git a/lib/wmi/Add-IcingaWmiPermissions.psm1 b/lib/wmi/Add-IcingaWmiPermissions.psm1 new file mode 100644 index 0000000..80d6000 --- /dev/null +++ b/lib/wmi/Add-IcingaWmiPermissions.psm1 @@ -0,0 +1,113 @@ +<# +.SYNOPSIS + Sets permissions for a specific Wmi namespace for a user. You can grant basic permissions based + on the arguments available and grant additional ones with the `-Flags` argument. +.DESCRIPTION + Sets permissions for a specific Wmi namespace for a user. You can grant basic permissions based + on the arguments available and grant additional ones with the `-Flags` argument. +.PARAMETER User + The user to set permissions for. Can either be a local or domain user +.PARAMETER Namespace + The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation +.PARAMETER Enable + Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control. +.PARAMETER RemoteAccess + Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control. +.PARAMETER Recurse + Applies a container inherit flag and grants permission not only on the specific Wmi tree but also objects within this namespace (recommended) +.PARAMETER DenyAccess + Blocks the user from having access to this Wmi and or subnamespace tree. +.PARAMETER Flags + Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite +.EXAMPLE + PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User icinga -Enable; +.EXAMPLE + PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess; +.EXAMPLE + PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess -Recurse; +.EXAMPLE + PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess -Flags 'ReadSecurity', 'MethodExecute' -Recurse; +.INPUTS + System.String +.OUTPUTS + System.Boolean +#> + +function Add-IcingaWmiPermissions() +{ + param ( + [string]$User, + [string]$Namespace, + [switch]$Enable, + [switch]$RemoteAccess, + [switch]$Recurse, + [switch]$DenyAccess, + [array]$Flags + ); + + if ([string]::IsNullOrEmpty($User)) { + Write-IcingaConsoleError 'Please enter a valid username'; + return $FALSE; + } + + if ([string]::IsNullOrEmpty($Namespace)) { + Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for'; + return $FALSE; + } + + [int]$PermissionMask = New-IcingaWmiPermissionMask -Enable:$Enable -RemoteAccess:$RemoteAccess -Flags $Flags; + + if ($PermissionMask -eq 0) { + Write-IcingaConsoleError 'You have to specify permissions to grant for a specific user'; + return $FALSE; + } + + if (Test-IcingaWmiPermissions -User $User -Namespace $Namespace -Enable:$Enable -RemoteAccess:$RemoteAccess -Recurse:$Recurse -DenyAccess:$DenyAccess -Flags $Flags) { + Write-IcingaConsoleNotice 'Wmi permissions for user "{0}" are already set.' -Objects $User; + return $TRUE; + } else { + Write-IcingaConsoleNotice 'Removing possible existing configuration for this user before continuing'; + Remove-IcingaWmiPermissions -User $User -Namespace $Namespace | Out-Null; + } + + $WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace; + + if ($null -eq $WmiSecurity) { + return $FALSE; + } + + $WmiAce = (New-Object System.Management.ManagementClass("Win32_Ace")).CreateInstance(); + $WmiAce.AccessMask = $PermissionMask; + + if ($Recurse) { + $WmiAce.AceFlags = $IcingaWBEM.AceFlags.Container_Inherit; + } else { + $WmiAce.AceFlags = 0; + } + + $WmiTrustee = (New-Object System.Management.ManagementClass("Win32_Trustee")).CreateInstance(); + $WmiTrustee.SidString = Get-IcingaUserSID -User $User; + $WmiAce.Trustee = $WmiTrustee + + if ($DenyAccess) { + $WmiAce.AceType = $IcingaWBEM.AceFlags.Access_Denied; + } else { + $WmiAce.AceType = $IcingaWBEM.AceFlags.Access_Allowed; + } + + $WmiSecurity.WmiAcl.DACL += $WmiAce.PSObject.immediateBaseObject; + + $WmiSecurity.WmiArguments.Name = 'SetSecurityDescriptor'; + $WmiSecurity.WmiArguments.Add('ArgumentList', $WmiSecurity.WmiAcl.PSObject.immediateBaseObject); + $WmiArguments = $WmiSecurity.WmiArguments; + + $WmiSecurityData = Invoke-WmiMethod @WmiArguments; + if ($WmiSecurityData.ReturnValue -ne 0) { + Write-IcingaConsoleError 'Failed to set Wmi security descriptor information with error {0}' -Objects $WmiSecurityData.ReturnValue; + return $FALSE; + } + + Write-IcingaConsoleNotice 'Wmi permissions for Namespace "{0}" and user "{1}" have been set successfully' -Objects $Namespace, $User; + + return $TRUE; +} diff --git a/lib/core/framework/Get-IcingaWindowsInformation.psm1 b/lib/wmi/Get-IcingaWindowsInformation.psm1 similarity index 72% rename from lib/core/framework/Get-IcingaWindowsInformation.psm1 rename to lib/wmi/Get-IcingaWindowsInformation.psm1 index 9263d30..efc079c 100644 --- a/lib/core/framework/Get-IcingaWindowsInformation.psm1 +++ b/lib/wmi/Get-IcingaWindowsInformation.psm1 @@ -1,3 +1,34 @@ +<# +.SYNOPSIS + Allows to query Wmi information by either using Wmi directly or Cim. This provides a save handling + to call Wmi classes, as we are catching possible errors including missing permissions for better + and improved error output during plugin execution. +.DESCRIPTION + Allows to query Wmi information by either using Wmi directly or Cim. This provides a save handling + to call Wmi classes, as we are catching possible errors including missing permissions for better + and improved error output during plugin execution. +.PARAMETER ClassName + The Wmi class to fetch information from +.PARAMETER Filter + Allows to filter only for specific Wmi information. The syntax is identical to Get-WmiObject and Get-CimInstance +.PARAMETER Namespace + The Wmi namespace to lookup additional information. The syntax is identical to Get-WmiObject and Get-CimInstance +.PARAMETER ForceWMI + Forces the usage of `Get-WmiObject` instead of `Get-CimInstance` +.EXAMPLE + PS>Get-IcingaWindowsInformation -ClassName Win32_Service; +.EXAMPLE + PS>Get-IcingaWindowsInformation -ClassName Win32_Service -ForceWMI; +.EXAMPLE + PS>Get-IcingaWindowsInformation -ClassName MSFT_NetAdapter -NameSpace 'root\StandardCimv2'; +.EXAMPLE + PS>Get-IcingaWindowsInformation Win32_LogicalDisk -Filter 'DriveType = 3'; +.INPUTS + System.String +.OUTPUTS + System.Boolean +#> + function Get-IcingaWindowsInformation() { param ( diff --git a/lib/wmi/Get-IcingaWmiSecurityData.psm1 b/lib/wmi/Get-IcingaWmiSecurityData.psm1 new file mode 100644 index 0000000..b855f6c --- /dev/null +++ b/lib/wmi/Get-IcingaWmiSecurityData.psm1 @@ -0,0 +1,60 @@ +<# +.SYNOPSIS + Returns several information about the Wmi namespace and the provided user data to + work with them while adding/testing/removing Wmi permissions +.DESCRIPTION + Returns several information about the Wmi namespace and the provided user data to + work with them while adding/testing/removing Wmi permissions +.PARAMETER User + The user to set permissions for. Can either be a local or domain user +.PARAMETER Namespace + The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation +.INPUTS + System.String +.OUTPUTS + System.Hashtable +#> + +function Get-IcingaWmiSecurityData() +{ + param ( + [string]$User, + [string]$Namespace + ); + + [hashtable]$WmiArguments = @{ + 'Name' = 'GetSecurityDescriptor'; + 'Namespace' = $Namespace; + 'Path' = "__systemsecurity=@"; + } + + $WmiSecurityData = Invoke-WmiMethod @WmiArguments; + + if ($WmiSecurityData.ReturnValue -ne 0) { + Write-IcingaConsoleError 'Fetching Wmi security descriptor information failed with error {0}' -Objects $WmiSecurityData.ReturnValue; + return $null; + } + + $UserData = Split-IcingaUserDomain -User $User; + $UserSID = Get-IcingaUserSID -User $User; + $WmiAcl = $WmiSecurityData.Descriptor; + + $WmiAccount = Get-IcingaWindowsInformation -ClassName Win32_Account -Filter ([string]::Format("Domain='{0}' and Name='{1}'", $UserData.Domain, $UserData.User)); + + if ($null -eq $WmiAccount) { + Write-IcingaConsoleError 'The specified user could not be found on the system: "{0}\{1}"' -Objects $UserData.Domain, $UserData.User; + return $null; + } + + if ([string]::IsNullOrEmpty($UserSID)) { + Write-IcingaConsoleError 'Unable to load the SID for user "{0}"' -Objects $User; + return $null; + } + + return @{ + 'WmiArguments' = $WmiArguments; + 'UserData' = $UserData; + 'UserSID' = $UserSID; + 'WmiAcl' = $WmiAcl; + } +} diff --git a/lib/wmi/Icinga_WBEM_Security.psm1 b/lib/wmi/Icinga_WBEM_Security.psm1 new file mode 100644 index 0000000..3199cd2 --- /dev/null +++ b/lib/wmi/Icinga_WBEM_Security.psm1 @@ -0,0 +1,59 @@ +<# + # WMI WBEM_SECURITY_FLAGS + # https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/ne-wbemcli-wbem_security_flags + # https://docs.microsoft.com/en-us/windows/win32/secauthz/standard-access-rights + #> + + [hashtable]$SecurityFlags = @{ + 'WBEM_Enable' = 1; + 'WBEM_Method_Execute' = 2; + 'WBEM_Full_Write_Rep' = 4; + 'WBEM_Partial_Write_Rep' = 8; + 'WBEM_Write_Provider' = 0x10; + 'WBEM_Remote_Access' = 0x20; + 'WBEM_Right_Subscribe' = 0x40; + 'WBEM_Right_Publish' = 0x80; + 'Read_Control' = 0x20000; + 'Write_DAC' = 0x40000; +}; + +[hashtable]$SecurityDescription = @{ + 1 = 'Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control.'; + 2 = 'Allows the execution of methods. Providers can perform additional access checks. This is a default access right for all users and corresponds to the Execute Methods permission on the Security tab of the WMI Control.'; + 4 = 'Allows a user account to write to classes in the WMI repository as well as instances. A user cannot write to system classes. Only members of the Administrators group have this permission. WBEM_FULL_WRITE_REP corresponds to the Full Write permission on the Security tab of the WMI Control.'; + 8 = 'Allows you to write data to instances only, not classes. A user cannot write classes to the WMI repository. Only members of the Administrators group have this right. WBEM_PARTIAL_WRITE_REP corresponds to the Partial Write permission on the Security tab of the WMI Control.'; + 0x10 = 'Allows writing classes and instances to providers. Note that providers can do additional access checks when impersonating a user. This is a default access right for all users and corresponds to the Provider Write permission on the Security tab of the WMI Control.'; + 0x20 = 'Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control.'; + 0x40 = 'Specifies that a consumer can subscribe to the events delivered to a sink. Used in IWbemEventSink::SetSinkSecurity.'; + 0x80 = 'Specifies that the account can publish events to the instance of __EventFilter that defines the event filter for a permanent consumer. Available in wbemcli.h.'; + 0x20000 = 'The right to read the information in the objects security descriptor, not including the information in the system access control list (SACL).'; + 0x40000 = 'The right to modify the discretionary access control list (DACL) in the objects security descriptor.'; +}; + +[hashtable]$SecurityNames = @{ + 'Enable' = 'WBEM_Enable'; + 'MethodExecute' = 'WBEM_Method_Execute'; + 'FullWrite' = 'WBEM_Full_Write_Rep'; + 'PartialWrite' = 'WBEM_Partial_Write_Rep'; + 'ProviderWrite' = 'WBEM_Write_Provider'; + 'RemoteAccess' = 'WBEM_Remote_Access'; + 'Subscribe' = 'WBEM_Right_Subscribe'; + 'Publish' = 'WBEM_Right_Publish'; + 'ReadSecurity' = 'Read_Control'; + 'WriteSecurity' = 'Write_DAC'; +}; + +[hashtable]$AceFlags = @{ + 'Access_Allowed' = 0x0; + 'Access_Denied' = 0x1; + 'Container_Inherit' = 0x2; +} + +[hashtable]$IcingaWBEM = @{ + SecurityFlags = $SecurityFlags; + SecurityDescription = $SecurityDescription + SecurityNames = $SecurityNames; + AceFlags = $AceFlags; +} + +Export-ModuleMember -Variable @( 'IcingaWBEM' ); diff --git a/lib/wmi/New-IcingaWmiPermissionMask.psm1 b/lib/wmi/New-IcingaWmiPermissionMask.psm1 new file mode 100644 index 0000000..68a4b00 --- /dev/null +++ b/lib/wmi/New-IcingaWmiPermissionMask.psm1 @@ -0,0 +1,54 @@ +<# +.SYNOPSIS + Generates a permission mask based on the set and provided flags which are used + for adding/testing Wmi permissions +.DESCRIPTION + Generates a permission mask based on the set and provided flags which are used + for adding/testing Wmi permissions +.PARAMETER Enable + Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control. +.PARAMETER RemoteAccess + Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control. +.PARAMETER Flags + Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite +.INPUTS + System.String +.OUTPUTS + System.Int +#> + +function New-IcingaWmiPermissionMask() +{ + param ( + [switch]$Enable, + [switch]$RemoteAccess, + [array]$Flags + ); + + [int]$PermissionMask = 0; + + if ($Enable) { + $PermissionMask += $IcingaWBEM.SecurityFlags.WBEM_Enable; + } + if ($RemoteAccess) { + $PermissionMask += $IcingaWBEM.SecurityFlags.WBEM_Remote_Access; + } + + foreach ($flag in $Flags) { + if ($flag -like 'Enable' -And $Enable) { + continue; + } + if ($flag -like 'RemoteAccess' -And $RemoteAccess) { + continue; + } + + if ($IcingaWBEM.SecurityNames.ContainsKey($flag) -eq $FALSE) { + Write-IcingaConsoleError 'Invalid Security flag "{0}" . Supported flags: {1}' -Objects $flag, $IcingaWBEM.SecurityNames.Keys; + return $FALSE; + } + + $PermissionMask += $IcingaWBEM.SecurityFlags[$IcingaWBEM.SecurityNames[$flag]]; + } + + return $PermissionMask; +} diff --git a/lib/wmi/Remove-IcingaWmiPermissions.psm1 b/lib/wmi/Remove-IcingaWmiPermissions.psm1 new file mode 100644 index 0000000..ae7c91f --- /dev/null +++ b/lib/wmi/Remove-IcingaWmiPermissions.psm1 @@ -0,0 +1,70 @@ +<# +.SYNOPSIS + Removes a user from a specific Wmi namespace +.DESCRIPTION + Removes a user from a specific Wmi namespace +.PARAMETER User + The user to set permissions for. Can either be a local or domain user +.PARAMETER Namespace + The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation +.INPUTS + System.String +.OUTPUTS + System.Boolean +#> + +function Remove-IcingaWmiPermissions() +{ + param ( + [string]$User, + [string]$Namespace + ); + + if ([string]::IsNullOrEmpty($User)) { + Write-IcingaConsoleError 'Please enter a valid username'; + return $FALSE; + } + + if ([string]::IsNullOrEmpty($Namespace)) { + Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for'; + return $FALSE; + } + + $WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace; + + if ($null -eq $WmiSecurity) { + return $FALSE; + } + + [System.Management.ManagementBaseObject[]]$RebasedDACL = @() + [bool]$UserPresent = $FALSE; + + foreach ($entry in $WmiSecurity.WmiAcl.DACL) { + if ($entry.Trustee.SidString -ne $WmiSecurity.UserSID) { + $RebasedDACL += $entry.PSObject.immediateBaseObject; + } else { + $UserPresent = $TRUE; + } + } + + if ($UserPresent -eq $FALSE) { + Write-IcingaConsoleNotice 'User "{0}" is not configured for namespace "{1}"' -Objects $User, $Namespace; + return $TRUE; + } + + $WmiSecurity.WmiAcl.DACL = $RebasedDACL.PSObject.immediateBaseObject; + + $WmiSecurity.WmiArguments.Name = 'SetSecurityDescriptor'; + $WmiSecurity.WmiArguments.Add('ArgumentList', $WmiSecurity.WmiAcl.PSObject.immediateBaseObject); + $WmiArguments = $WmiSecurity.WmiArguments + + $WmiSecurityData = Invoke-WmiMethod @WmiArguments; + if ($WmiSecurityData.ReturnValue -ne 0) { + Write-IcingaConsoleError 'Failed to set Wmi security descriptor information with error {0}' -Objects $WmiSecurityData.ReturnValue; + return $FALSE; + } + + Write-IcingaConsoleNotice 'Removed user "{0}" from Namespace "{1}" successfully' -Objects $User, $Namespace; + + return $TRUE; +} diff --git a/lib/core/framework/Test-IcingaWindowsInformation.psm1 b/lib/wmi/Test-IcingaWindowsInformation.psm1 similarity index 92% rename from lib/core/framework/Test-IcingaWindowsInformation.psm1 rename to lib/wmi/Test-IcingaWindowsInformation.psm1 index a3a5374..edb467e 100644 --- a/lib/core/framework/Test-IcingaWindowsInformation.psm1 +++ b/lib/wmi/Test-IcingaWindowsInformation.psm1 @@ -1,10 +1,10 @@ <# .SYNOPSIS - Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions taht might occure. - Returns binary operator values for easier comparison. In case no errors occured it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok + Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions that might occur. + Returns binary operator values for easier comparison. In case no errors occurred it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok .DESCRIPTION - Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions taht might occure. - Returns binary operator values for easier comparison. In case no errors occured it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok + Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions that might occur. + Returns binary operator values for easier comparison. In case no errors occurred it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok .ROLE ### WMI Permissions diff --git a/lib/wmi/Test-IcingaWmiPermissions.psm1 b/lib/wmi/Test-IcingaWmiPermissions.psm1 new file mode 100644 index 0000000..2cff30a --- /dev/null +++ b/lib/wmi/Test-IcingaWmiPermissions.psm1 @@ -0,0 +1,92 @@ +<# +.SYNOPSIS + Tests the current set permissions for a user on a specific namespace and returns true if the + current configuration is matching the intended configuration and returns false if either no + permissions are set yet or the intended configuration is not matching the current configuration +.DESCRIPTION + Tests the current set permissions for a user on a specific namespace and returns true if the + current configuration is matching the intended configuration and returns false if either no + permissions are set yet or the intended configuration is not matching the current configuration +.PARAMETER User + The user to set permissions for. Can either be a local or domain user +.PARAMETER Namespace + The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation +.PARAMETER Enable + Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control. +.PARAMETER RemoteAccess + Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control. +.PARAMETER Recurse + Applies a container inherit flag and grants permission not only on the specific Wmi tree but also objects within this namespace (recommended) +.PARAMETER DenyAccess + Blocks the user from having access to this Wmi and or subnamespace tree. +.PARAMETER Flags + Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite +.INPUTS + System.String +.OUTPUTS + System.Boolean +#> + +function Test-IcingaWmiPermissions() +{ + param ( + [string]$User, + [string]$Namespace, + [switch]$Enable, + [switch]$RemoteAccess, + [switch]$Recurse, + [switch]$DenyAccess, + [array]$Flags + ); + + if ([string]::IsNullOrEmpty($User)) { + Write-IcingaConsoleError 'Please enter a valid username'; + return $FALSE; + } + + if ([string]::IsNullOrEmpty($Namespace)) { + Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for'; + return $FALSE; + } + + [int]$PermissionMask = [int]$PermissionMask = New-IcingaWmiPermissionMask -Enable:$Enable -RemoteAccess:$RemoteAccess -Flags $Flags; + + if ($PermissionMask -eq 0) { + Write-IcingaConsoleError 'You have to specify permissions to grant for a specific user'; + return $FALSE; + } + + $WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace; + + if ($null -eq $WmiSecurity) { + return $FALSE; + } + + [System.Management.ManagementBaseObject]$UserACL = $null; + + foreach ($entry in $WmiSecurity.WmiAcl.DACL) { + if ($entry.Trustee.SidString -eq $WmiSecurity.UserSID) { + $UserACL = $entry.PSObject.immediateBaseObject; + break; + } + } + + # No permissions granted for this user + if ($null -eq $UserACL) { + return $FALSE; + } + + [bool]$RecurseMatch = $TRUE; + + if ($Recurse -And $UserACL.AceFlags -ne $IcingaWBEM.AceFlags.Container_Inherit) { + $RecurseMatch = $FALSE; + } elseif ($Recurse -eq $FALSE -And $UserACL.AceFlags -ne 0) { + $RecurseMatch = $FALSE; + } + + if ($UserACL.AccessMask -ne $PermissionMask -Or $RecurseMatch -eq $FALSE) { + return $FALSE; + } + + return $TRUE; +} From 78432adaed9085683781c1743bc92d02f08af248 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Fri, 6 Nov 2020 10:51:45 +0100 Subject: [PATCH 5/6] Adds first knowledge base entries --- README.md | 1 + doc/10-Knowledge-Base.md | 12 ++++ .../IWKB000002/01_Plugin_Output_Error.png | Bin 0 -> 24388 bytes .../IWKB000002/02_Director_Config.png | Bin 0 -> 12722 bytes .../IWKB000002/03_Fixed_Output.png | Bin 0 -> 33711 bytes doc/knowledgebase/IWKB000001.md | 57 ++++++++++++++++++ doc/knowledgebase/IWKB000002.md | 27 +++++++++ 7 files changed, 97 insertions(+) create mode 100644 doc/10-Knowledge-Base.md create mode 100644 doc/images/04_knowledgebase/IWKB000002/01_Plugin_Output_Error.png create mode 100644 doc/images/04_knowledgebase/IWKB000002/02_Director_Config.png create mode 100644 doc/images/04_knowledgebase/IWKB000002/03_Fixed_Output.png create mode 100644 doc/knowledgebase/IWKB000001.md create mode 100644 doc/knowledgebase/IWKB000002.md diff --git a/README.md b/README.md index 524d08e..67a74df 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Please take a look at the following content to get to know the possibilities of * [Icinga Integration](doc/05-Icinga-Integration.md) * [Framework Usage Examples](doc/06-Framework-Usage.md) * [Icinga PowerShell Framework as Service](doc/service/01-Install-Service.md) +* [Knowledge Base](doc/10-Knowledge-Base.md) * [Changelog](doc/31-Changelog.md) Developer Guide diff --git a/doc/10-Knowledge-Base.md b/doc/10-Knowledge-Base.md new file mode 100644 index 0000000..a367d27 --- /dev/null +++ b/doc/10-Knowledge-Base.md @@ -0,0 +1,12 @@ +# Icinga for Windows Knowledge Base + +While using Icinga for Windows you might run into issues, permissions problems or different problems during usage. Our main goal is to catch all of those problems and print proper error messages to give ideas on what went went wrong exactly. + +However, some problems might be more complex and require further detailed descriptions as an issue could be caused my multiple different events or possible solutions would be way too long to put into a plugin output for example. + +For this reason you will find a list of Icinga knowledge base entries below. Entries are assigned a unique 6 digit number referenced by issue messages, lead by the abbreviation `IWKB`. Example `IWKB000001`. + +| Knowledge Base Id | Short Message / Description | +| --- | --- | +| [IWKB000001](knowledgebase/IWKB000001.md) | The user you are running this command as does not have permission to access the requested Cim-Object. To fix this, please add the user the Agent is running with to the "Remote Management Users" groups and grant access to the WMI branch for the Class/Namespace mentioned above and add the permission "Remote enable". | +| [IWKB000002](knowledgebase/IWKB000002.md) | Plugin execution fails because arguments could not be validated and properly set. An example error could be `The "*" was not recognized as the name of a program, cmdlet, function, script file, or executable. Check the spelling of the name and that the path is correct (if included), and repeat the process.` | diff --git a/doc/images/04_knowledgebase/IWKB000002/01_Plugin_Output_Error.png b/doc/images/04_knowledgebase/IWKB000002/01_Plugin_Output_Error.png new file mode 100644 index 0000000000000000000000000000000000000000..8f8c8f06adcd52813535450b1426f744958c1392 GIT binary patch literal 24388 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

F3-`xtcYojPOCP!@wD@Xg@)4A zm6Xp-Khdr}6;t;N|7|0tL`r=-o5$UyBVd&m`E+XF#t&J^h*w;?YQ)zB{HVGhJ=#*O zIj9)KOB{xh`^9*VVTnN>Ceuz_*B7ujt;+!JbHEa&pZN5)zS_GT8O40vXzsQ zkGi_lr|!8I>0f*?UFFMV*Prpdht~EEuqul@Pdt1X-c$-Hcl!RTWV7*bIIf%>X2*O$ zuDCSM?&iPdomRG@0L875V(Lt)yv>sY6L;ze%)KzXGHOal7_RfgLMQlpK?Lde&NEaP zeG@nTz00cM7QSU!NPYO?tT9CCQsH%#52MQ+Rmp=$LRUMK9Ki}uutToZup#e7OlzTq7yqYM;R{XzY*w5=zZ*huaOVRoXpWKDZ% zj0%psfxvmto|d>Veq8xw$6V)ih$E-vqps0uv^gayPh5IJ; zPv1`RzmjULAL;Pmd;n_FOySSq%s5> z??fGNndya3jx#d6>!s2omzF>W9tINY?1COAq=Fon^jU4VSB38MN{7to$`mM1lA>=J z{dE0)o#%z~*df+492qXX@BUsakS`dnX|o!nDM1=RW*0}$=<-HpNF>*f&`HS*ttGwdH%w-?A_~js@kG`gon$ zgnp@z3g-qG?FELy@)NeD8U>s5GM-6-S#v^%b;fZ zs+EOvK!~el=U#1zj>g)W+3lFmAp+Kx?p2y>lg8#7$-0;sRY4aJZ(HCtQ~uoS08>vgPl`qN4wr^9@ zR!G;`!J)_GemLB#$#CW!U%-tYxnxG|b^-FW(^DN|+|djsvADNnCQ8%rRDcy0cj9XD ztpkRkg)4UaT8rQv$h%9U^eN3QZQo@IJw$c%Ls> zSCWVPy)4%sE20ZjPp$D4SpE*!+vZ(HB{@p&{kIX1r>};UE?VbPzaZ9JaRSaZ<(WVs z=2Lq=D>6#V5yVZVupNjWWEL0@QB$ zzTdG8QY%%w^(T(6Wjfe?Hj7AH(^KU;6EmJxIP%VBC6n`wyH+>x zopR0M>0qzY!0QM)?GE>y9YLw?9USF}i2Jjt{dL_bzsdJ4)E6Ud?q+?qVOVn@9X_ss zfH*{3&8A&bk_izwYpbFYiSl9SG?{`W_3NFtB<920W&Qevk=L-W2e3Awv|pw%(^=dv zyLXOY0glt=PyUzvsx9jD+FDGo+51%<2JGR_^ zBDQGdGtf=a%18G9XJLW^0zB+gfKU};nhc6iWz%Ttw=Sjg4?VaJI`gipStqVVqEsS_ z^&h(OSfG`K&S!=zvuzKIQsLKVcZZDoBW9}I1xpL$6NtCu10#B_SEG{l3k2QVJ69ls zmJc&Lc4`ct)9Z}V_T+tuO)1EXLFc`jHLhm+og?tg!S4P7JPwQ?Lp&+}2fN8_(_t|LJc%A{T<#nqK_ z04FHAq4u1cURN1}7_gIR^Lc=142d;6lhhWbZLHRODgwLfgb2rky;m0jJ)FR?9QfOk z!$f#e?{v1qV1zE~@o|65sndWDZ$ToHeMTo!bt|xoSGMB%?@tn*;p4ejV!7dnR-=SU zrJ9#Rmv3l28VcK%CbyDVNRl0mqD*8#wLf&^@1J4O)qIE+I1R~sPS;Y?j;y34PSi#( z30?$3TlBKL)^2u;_}EzQM|aEz){$M6#nZ{N++T&iZds2YlC0B3_{b4%;X>N%P;gvs z4#=-i7ks}yJld<&dZ4ej4o?uU9cWSJ;)1+s*^3Vsa=ptH{&bN6wF(%yfWvRwU-J1d zeZM}uQ`GcFoTZHjodojRT|-G&AJ&^cJPfsD;%VO6T5M!7-~TGxF;o&XebEK6W4YPH zAYHi`#xe+T`)yS{cs4DV)@1hdM1^5L8A3VPRK@wfD?Ys+Fc7Eao9N9AuvfS~)M zib4~vuDFF`X52s?+-4=ve(@U|JbAtGrZ-2_E~I0iAWU+u!_?k}j~ty2p$u(A?dPz) zN%?r^XR}btHE8BT1>$!tQHJ!i|N_Urx7vDOXePy@PuW?;N*MIxM}VXPCH?B-@S; z?YxgH>A!!G1>f`&s@dRYRWvM8s&kfyW0bJ3XK>jrA3yBVHNny*mhG|_o1j__yl}d+ zE&HWNnBLN4(!G=u`9&Lqr(1tJGkPg*K03^LZiu{1Rk@o@f|!iGo^o6}&n-Q6n4oux z1M@s!MxtwC6V`n~aWx8};17~{_Hk4BgBjsFA6f%JuHSVwPuo(yMG`)D54&wvjK_wY zW~EhTrmoIAPs5WmHxX1lx8XBduR%HL=wyyiS7hEN^y!f?1>pS8Te1IZ$JCeSpA515 zpGNM#+PVMlvbrbRLftfffGmzrI3S6l z$r8xX9l0tyYrcZi$Xbh(N3rsVp|k&feUK?cfNhGP*d{D4*d8wgli<)weLtd{s^H)& zpu;4#P2I*w_e4ZlV}x)zmc*V`-iiL2*6#QW_mMWQvpT zpp?N{|7waZHEcu}Zs< z4N*s~g;x6oa13^twXJngGsv{4rVzMAaUe6ZJClSuN!776O>i^#n`>}qj~B_Ki)BP1 zIvbF9gU#Ewhg}nd8ZqqIf?Zf}BVnVH|BkYjec6rTNBxhT5`(uzFLzwX>mp()saw~g z&!)nwM|Y3vBJRc7b=!HbVh%)fM-O>f9AlR7xeN)OC8^dHSD)I?abQr+e+PU%?I#L2 zq!_1Hlc{>^YzJH_nzv8bf5kI;ErvWEvVaRys)~>>BNkX>UC0g7LYca@Ty+e4?83^~ z{dx{iplULXxrZb-fy}j4Q!?DVUvyV;ACCx1^$L_3E7l6KH@o|f^s#bM@tYnevnZg~ zfpv?9_ihF{v~N>pJpWP~c89xTu2t9k#ot)_=<@~e(PJwz%50FL-Xgzxd3JnT03At~ zL-v#p_hOi$rAj;p^g3OYkjq~ZQr1i)aQtr8dSKIIQU}f7y_zoOrfJfxi)q8ITc`43 zy_ARB=N$&ev>d=AQlGO_LS&}2d=}(x!N^UM5k!b;Cx?jgM_yo5R7oQ(iJtn(DkLHKuK&bvf zj}0o!5cY#FHaQ(5d1rUW?Umtx4&#cJqvm4uLZuXT$q}zt|H5k-UmwX8|L@lLf1lys zY!!qwBd{)`*+qmPfs4^QelJNuqWO(RA9C3A*5A3S^ZpDKOg1Bhl#Lc}X zhm$~JB<=Cv1|H+4sqT_b{_f=)H+?QH&JMwW&2PPQ|jsp=4f71soq%8cq*{s@D?NK1RM6=)9DF|mk!U*!e)dz;mtQqP<-Y|f{t;utD99$6YGcxQU7 zUt3JaZXRv`v3+cfw&5aQ0c{*L3X#9$@7a@(FBn+Q2PMj0F}+R+&dVzd{wn!`{Y9um zewx$1qWNl!aI1G_YK)l6TGMI!*}(To%*dkL=YH;;Sd< zA0Q3z{uv&bO!kV#94+kYuub;Y$T0)zyDnEuJm8OM3ThQY?fW*Dk|f(gnB`;m==hn) z!^h{JCEB`)G_prq7<7g|Me;6p9UD*#Ka4%BkW2|WAm40KkLDz?iOXaKk|kgF>XDW) zVsD95omYlGAD0Fs%}>oevU%+L|09Fjk{~(?(XjHjk|l}?rx2{d*f0#m$la3XP@((@5hZB zH=-o7DkCdr=FB)#E1IW*HSUU*~M-ULC{=c4}!?vYHARvLF-$jL#-E_}8 zk?pjH-M62vRbvW9ro=i{4am32!I47i7MfaKgvU?wn99-!wvN@Z&LcE6_CiiM8b>o~JWN)WxZPWQ6#&A(THaCTV1=0ClaI zi04@^IGwKN(x(6MPiZKk?+4M2IQX<+z9$0ayMVK`zKxK_FXZg+uPX^|ycF`m&>gT9;oO_^ zZvLf>mx=$w5$o=QIQ%*s>~&Zm&^B{Iu!T|6M##kk>hQyb`oIpYI#WvIB4yS1?U6j(y*eilu7Xca>csulQEvFYJhzUZv$xv&Cw6-<@I%|Fy~(Q+ybGAf z7R5aTe>j93&akpyS+_+2WZVo&_g#bh=zy%TeL9+P1_YXq=L?{(!0*9&BQ)eB1 z^*s_6##S(KGz*IR!W~Wu7L$AjI<4@zA9`Y43+;OIJvxym25~s^W&QZ4G3bzp-N;+1 zi{m91t>Ulr;oW@j-XG7Nb`Q^d@=LGcR}%u3ei^=-&}6r#Ua0T=QhZEcdj8-a`LL%x zx0ps^?Ihd>x1bUn;H++^*;}@LrIW|3r6JEB3<18T+he?-Rpncip(#i2FkLrmzm!6| z+jGxaYkI)X1~huLd^f>;A98R>u4~?5es(!A(q&5tt9@u(aisFOUC};HV0!V~tm*j+ zf#I9?DaL7cBmwm=Mz)M)4W!cId7f+b%>M&u*~$ z4-t4L?{@I_Iv%|!IlhOQ?X{1@j+%CQq#QqFgRiWY8!Dc+#aHDjZ%f@2K)%Putz5_E zZMCsIwIsb*!HpE2(kGeKvVh|hkJ2qg@Mk<59}>_lo7nybdOiOX5%0L=sGD{-%+2TN z(|{kZs)+oo5pv=_4NzO5mu^%6_W$ZC_(=WJ$75C@DFQyIQ}3xT13A1PYnLh|B98Ef zHF4Arv3Wc2KbNkuahH_~e6V)%w#rny<6g@BZQAcY-m=zR9e_2UofI!Q@2VG`R~5h$ zZHNncZdscqU*>Wj)NV*;y?puNKu-*uziu^y6wuI}lCIOYKnQ%dYGkMnE0ix8E9u|`eyH+D~cXvcl~ALKVZGi2AlPJEmu>z_58{{@DOL^=KF`ri_XN~)-sI# zY{CQK7)kyaDo%S09?NPxK46`-#7GniYwY{I_gBVxlDq4M)(`3(Pq9$_%W*wMG+G`% z#>fI(Kfqr@n-?x6Z_W^F9hYoDJ6OTCu(Ru?SAf7~{dYzvgF6B?+l*a#*HnPCy}B9` z(xCg9Df}r`z>x7Xsb+i5GQUGZ}1+GpEKkIj37;AQ(tmr3wJ2$*|PyXtyW&%Y7< z_)bLb169(YH!TJ;R z<{*B+Oug$-uX*`I*1W^s;eVh`WJ>h{+p_&p4YWCW7u!#)Abfx%*HGBci!iUpeX;uc zcw2q~&Nx1gND1Ff(BJPG8{+z8KH$>+)q%%YUbh`(uA&#u<-KVUYmmI~bbXsav&}yu zc*?@wSs%BM&O?rC7<*zv^n!ZB^?KE^1wgKgPNCkQQNw@;z0J({-JU=hi4S8qMc?$0 z4A&0^ucEiLxIYmhqL(g1TuxY#;9g+34}^Z_Dj>IJEl9E(0iJAU547hWxVW3%1YH|B zK}5!!Jr9evA~h!3Vn8qOFKgvHi&`~(z-PVC^+nU%bKt`FM2oOyPNBQGX8qG?Xal47 zrESjne>z&4WGzE%>DIUeZUQ}DT>1ANeInc+r^n||lY2`Xnf{NrlqA>RvORTveKMt+zaexOAB4QXU1M4P9{%aD zXxWBh|31+n8aAp%QAGa)zlPV^o#DU3T7#H=|34d;ME8XJ^YsL-Kcc|jH&Gfp7@p5R zG13x(Ict0}gL9#JuoJjh;lupT$F5+1uK#I(2HF3IeR911-FSmV7^}yB_E?DuCb#{% ztjAyCQ-yEp@(Nqo@B7bBNxLoY{rjM)Hm+V?g}55_w5~!{W4ybh<<`Mpb{Kyhy$z-| zSD;~#rUr<3Cd8?>CzEn+LVAYKyv?)pxVf+!0&XpQG2;FTQo>@~5(KN@I(yviKf+PX zKSR}|g_N%5H(>+exDfK9ExLE~r*?Qn3ZuOBN0JHXq75w^Dnh9%9}+a$oVD@Pq%8ZG zu{;$xBX_F{$sNWJgGD%F_t(vKcS$GExu(k!$*f#Z;3XUQ#q!aCLH^VD#?=s+j798& zo*$==tpMBH6tBn?`+eo*mX}^8WAI&E@xI*|uAZ`KTJjGO74&=+yel<`a(=Sd@A%1I ztkq%ZRR{Q``j?q{y8IKFcz9@<2C$ZvnfzA@rJAI4dl|p?8-go~7sz`Py+G=h!Sw0HDUUKkA-d-w8k3zO4bSScOMGu{sk4>(|)# z{&|QHyaXn(&1pE)m4#5T9ejMgfoy>g4S41GE6evAk*gkYU+@yd%dOAz>bv<0LiiY( zk}4;-(FO!Bq%pfw__oA~8fsIy&VgQj)@Xxjnp!Zab$kcl?xYk+U4Z4y*J71-jX8a2 zEp(ncrguj;BDs-FyL56R!{6ZT%4R{}bautHr$0t*kA9cNG7rE-S~+FO zy(81maA4V&ot6=n>|}H|M^&UEdTZ^f$GGf2GP|Kq1KQEbU0^R3P=^tHy-eZRABgv* z0t_ip)9JF1AjqX^U2sz)m#h;!DW)KwWs*SpwxWFwhdA~m$f{r;$Z$B$IAH?k^YGC# z*iyYo$Nbs;qqys-l;lWHX(yF2&4_xSX~)ddYjaAYeH}|<&0lC@vo>{WusxwjLhZ>WAOT zm=Y)^C^)+zdZ+vN^6qmo^y22j{BisG@)W6--KbY$&A8E${86;G^2ipwKZ`*!P;cvRfX>9`RnU=1Dm$g>Z#l_vyo=>o4D- z(C<3RFzHSfBSdrr8u=M`FS%iFXi04P=W&-mNLzBg=KuL8E14|nG;V8 zB)FGlC2fg)>I*wMNX-~@Jm4=XBO!9na?6Rs3(lCD(|e-RTlt|Lall7Q#3gT!MByqD z(}l&o&+x!Jg>@ih64X#;-7g*A}Fy5txkFv!Yi!+KeDCuBx z8oib^ed@2T3e_1Aifs<>Sk$;6SDZ3g#WP?A3Tc$tFbT zUvH)RQ0oMG;V$|*alTFolwS?w`Nt6o?Qpf!;8tc6oC<@EAT+0ECljttOV)^c@Iazi zUIViQF|{7wKnM!rmhp=%nc>30nHS!ap%IzSvQWZ%@=plN1NSk;8ROdRFj;0H{yf}g z8idKZ3JEy%9KZ9dL2#j_)d6tCl~S5XIKfR>navckxx?l~3Ks7vjN-lvx9^PRd9uRm zKLtxtfRA$APc(fu!~YZ5;xIYGd;2)WLEn+v&AM3S{>2l%Fm~ty1Ezb6S$IMVpyICo(0^G)ct z`ux_tpffWIjL=HEj=0m7H~%_Te53jqDT500L$-LkpFy@0&x9_Qt-D_4Kzv>MPk(pb zV|ty}O!r57=J@%l^)kAWsgw${9yqHEAY1O`nXP?5Iv2yBC6*@5`nl7KHb*1hkipE~ z?&;VW`4AzL*E$XNVJA_i0mPI4q%G=*70!-G3Rj`ZRr+xRyVI#YQX;N|Reecr;2)YU zuw;1%c<7Ssbfk`}ui`G`{|ZaHCLEO9&P2t+e;JAv)@*Jho&$wzpFtan>|6=tj8KLYt)y ze|K+i0K!*0Z2BjMQ=PlJ%%V^mPV8$XG7)A2&dAbwO@|=&NEf{i45?O=2s*95kF|D6 z7T2%4hu&iYKf<+Tj^}M5Z-VdIdVW#%NYTN#Y}hi4eSgv>$4QKtz|h9k=Vo}9Wbl!h zbXg$w4|<{c1~XA(*`%{ZMZ7H2p(IFFFhvhK3pVwVQoaItmN#%Q2(6|86-N5(2}w)W z22xNVl(KAsU;B!=aWtnql>vI`OvCr|@O``~{=sJ!TS6N?wtII_gD5B41L9BNT6dL_q^<;@2IHOwB|JrITG$IiXOrX*xQOm6T|;CljdmT|R!|hWVse zfmi0wP|B~l&N6HKx=cNGku~>BvOli4Hfj&xsblsA7%^}!++YG(uFH%z2Qzk`VE z2z_cAjw*Pl`xfp{!pN@UzSto*rvE#Mb`0cplb?MfIvZ%#(gSbMF)7Qv%^U4SJ-*Cb zahBagk@JND?Ea2fRN@kQlsF=qPot~$)jBfL#$t~wW~91v7v71L!2}?IY`_iG&Twtb z1_g>|FwDPqB}v1bfjG=E8g01uqhRxGnrR|S@(ysc+ty*KJtZT#0+6VvR!^o-tFp z2kQd;evB!K@l%5FJ71!$icT6^AXp#72y_5B=Y>qT>tq^d*TLn@cu+!Gqls`me`Q$)^(t^YW1CdTw+-7uwlo0#rFqB4Z{&{trMWBrn?hZ_`nTkTApDmk z?O)%l9sYkQr2lWC_dmP*|4Bvv-*%{;DsHpcQRYH_(FxSOw>)usW#lD^{ZReM%KHwn zxbrW~&x`Z$A1#jO(|XMyF;$*LQTVrpjj=7O!s~kT<53`;)bq*9pLP^>SYb_4^-Lz? zoBy2biL|gih~F8l0{f^G!cCZ*WRW{mv@?^#Ds;G!wt1bY-(Qd<8(%(+zp{=U!TLTy zU6Hgx&Zb1zr3{#y6Y;##ylkOMwb7NOl11Md|7ljLeJSJ~Kk+l8u7fc}T~+?#E|Zvr zmK-Qad>TvP)x}71qbn43^f;n8P(uq@__GYjoUn~fE{GJmjG+T7N68`~b@I!}7ZNm9 zx%S(3=c)272;*YCuxi~(v-bMhc21;txcdkX=lg`6=G#ERWuTI?pwRHg)n@yGE|ToW zf$KJ}#pO2HR={~T52T*wZRP3*+A=KGc3n;f%>%{Sj_+INR;aTh-_-=~XR`8kYdL>iJP-7@$D&RBCmVrF=^&?jZ!k5(}G$-gKY$wpi z$ANATw};uNrG&X#PO=9J{1X+sn&2#$p2Qeum?z(^QBF8NJ9*UC9toic%juw1)PX#$ ztdg^}kj5ww1qp;ZVXuCk7w=gJ1bvO(em69l=m*GU&)*)Q1g7r^mur5I-PVs0JSLQ@ zJTL?^u?Ex2QYb^#^COXuo7GL^%ff3O=(y7aO$WyCQRDhV%AJQ{0z<~~qX|jze9|da za0Ny+4`F7OSFiN@F$WV-S||}?-Uo3{rHe`~PSr$8ODc;JD@0kWw;92DK9pmrp2qhX zynvuQxj>=m+?$Ie5qpHzZa?>3cp=;SWKU+mZuv=evT(`{uGXgGBB#;SLl1m@2L|IU zOSYr#6P$6gX`9eM>#vTW>CM3D_h({$JjdqW=6=u9R7Ap;Q(8Rb*i$V~`Pw?97jnXr zx1U0$GUg=Ajb0F*Z!4Kw0?OmfWIIj9{k*PSNaD4CxIe!)?#rBXLIBfUw zJ}K8fMF72%%Tq;$Af7s_hE%Rt-3#aJG`}7|OKsv_8cf4_Sp|XdybDOR*4`{7Jq}oMIGz9M4tB+XLW)}#<|IO zv!ri{z8fm{^D^?!Df`wOffi*HpWznWvC(mv;Sbhi8k*q0^wIp(&SLYKBg!S~Lpw=V z%wL-*(i!1n1D%%e134Bfu*@$1#1!cp0VL>PSrVvyZZ;YP%&>I#*`W`}kPBjOW(ciT zrj;87r4|tI`!G9Y_%qO$JX$bg8j1Sn7pUX5AS+}pJhBtl>W`IVF8rhU`_wLidp!1L zQ2qKJ+!UX*XMchl&s;D)XUg*f@}v0CVp(i8z?|dcpUTs)oDEfA45dcxF3yY!%|j4R z?YKC>yHP+T`sV?sPWC_U6Fzm~jrwe%EJOubfWL!4xC4>c3%MUqlX4!rd!!oEPwguW z_7$;JsI55Z)#l{wm2W9of$ckn_A3?G$NA9$C^!p>fHz{79&)F zHiO1k$9^$~c9V#CMyQwzh5At^S{$5U4+FFX_l$FDA+37XoI{P)j#CaYBP`KK-`WWuzP& zllR~W4!O6{@}VGYf8O3VgI4Z^dR2oYP#$>&!@L}iF0k-eqppSXtX?35b_=DmMFSoqe z^j*SLOspZQTX}hTqZJkt7zh=tTwN)=BORm*zj<+>1*T*n87drG%~u&cP0IGJH;Gw2 zXf3x(us>0?D%y&fv}^!u&lmPg_QN(7`&(v$fk=DL5_~8+a*l3SxxB)M3YTqx;Er^~PLw6W2pt;_bM3~Bv zR00O+RJqtyf^|kpvCAyQnnJ3DZ`jFhl|ZcngG-_@w}{CPJ-5?vhrdZyoBHHT2JX9n z7bq;OBVToQ1RT9-nY$>?IQmq09qNN|WO4sc;nyQh}NpSP(}6Q_vR@g%WPc9IQ_7!&ZH^y4TI9x*mRTFYDjmU;I=mB#1>e~QXxka!&e zQazZxuhJ*eCPlchL7Px^|105O?Mrg-@j#dgrf%ZKcd;(~ z^M)u71@2#rf{`wl>k8xgxaqmoOwLH0?Owl`f-z#p)iLG4%Mr!uBWt<%0-mI6{veXd zf0QcUxhVS}=VySA@YRfZXNg=u1s~|*I=@sM1sBv-V>k#T0+T$S8x2XTCR^NGaGpmu zkgd}AF#_im%*nZie=MA<5voU(jDt%MijmQg%8Y>9Vq0QQi=0=xd2r5Tm3Fvx%UP#* z6ST#EIi0z05DTWqTCFg6D2+{mLlx$*;#Khd&WAf~29?%*gv70PoM|bNBv7;B)*qE) zT#~HbU`{AmC@}EI7%jDw5}qXK=Z(prXUt_logLmwvoYB#!)`FN`@@QOHPgmp*3)Kx zBWyf8Cf>wm(W%}G^QOY664k4jGCp3y|78BE=K-n%X5Kdz`|I4G;%-Y%D@oB9}e`vLnwqS|0E%kmP!0y^qPk1*D7Fo z$m}5`E+!Dq(+k4j!Q)>wPn+a}ea@0#5*O;p7z=ooKxgC(T--1uMfg)`R>EyBU>5?G zI`w5^nHp=0z|j1ivlwyaP|W-x+30lW_1JJd%EsHnQrE@E!6J*BhxxOcuu&&cO=#cD z#^MRpF{AACHOvNfzZ?5k+owRjB|9&3#XbGDW{ZTQj!pJE-{eO5Cfy;DbxSaEVMUG| zcl0x=f`<)(>O6qsj=ZMOvTP3ns z#|%PC$gSMyQK%%o`NVIgI9)@)&#Qm~zC9eeeIIvZC1W3?4>@;FcD^w$NQwhwZXG~5 zKa0y^)>&x$lUQj9x-d;jy(y)!cc9+i6*JAXHs_-R_4E8ATiY~LkD$sEZX19 z4$>_60~OaEEJEqwo+g=}R(&7ep1tVX!KQbe5ITJf3#NsxvPwN-$uofeUp2s`lZ>Q$!_oUBU_sOY>b z3kFDk(bd~o!INZql|Ss-D@h4xxRPdo&S?W0Jf@yX+@|^xbvdaay%Pdh?THRs!7_X`7_RCPJ}Xmwk@^qO_vLdlk# z^A@8YBo9ve%w){iK=)mE1Y0u{XI}5*n-*`bTClk7^+ElzqA~_7N!u`Dsc~Vn^LRAT z@C*(Wj=pZWk%-ptvgbKOATOt@=d_RB& z^nPw&Wm4As$GFr_Xz+32-)#CD#{RDa3HZ5V3USbBQHR_uU&Ry0tCK5q4GB>@W?NLe zGDVULCj;qkJ2ucTpl}(J{2x_`(7Mx>Y62W`7^#59#ktiKg+7ks8}W;j%vGG!msQby z4z7tINt4^D_0dqzE&d^Mzl3gBLpOLL5VA}8GpP`0E)57y;MvWXr)9lv<81fl8Yal@ zKt;Z)7BUlnX-r|RyUY0@R&FMm$Ynq#TUJSJsaDf>cq9+J%urQK$df@v3(bc{ZHq-$ z%s(mqp2piL6Kxeh7p_Y+dQ^bA!4qgCf4$>9mD1%V%6aWu`Z+ZSrTcO-3Gia3Ir>A} zO;U#5&Dv>HyOLbCCAFu~W{9Sm8qak!ad?ODG^l))Le*qHr9~gLeA{^_ zj?yQ{+y?s$+9V*m!B7t`+$7n^K!-u-NmFqZX2XO-SZ?)09ToQ`y*$CNOmr|dV!vl; zDP4#6t#)G(42>n1QU4yakz(?GUtEweOz0tvK5I~|+cXwV!qaq(Nibg|)|7;)rm@1Stiws{(|%v4yp3{WFqyF4SBXPJ5N7Lp)uGh|(-uPOwL8VH0FeGlY z=e8T>(mg994K?i-R^mJ*CFd#PUURHIF$s%pMv+zJEaREv-k!>VXeiL~rH={8kI8{j zpFD{qD$mg3pcqyS(mYoj` zrUL$Wk~G!%oPIH=*q6t2Ap$uDo{Lka{&EDQeM@tH9V^Lnf3+bS08#0F@>2yBdlZh* zqd}giz{n1)XPS==gF^F0w86vIPFr{TV$wt&fag774ezb+hch;Z@lNGO?$iFK^oR#8 z!iB7-ni6&|glDGKTqQB=5F=BttBXuUW5Ia2ggY*5JS8z?upkJe`#7JmK5C$` z`+}sh*oe?0{Bjs3+I+#Yn0|4$dZeeYsEl~R_`WmLqbLNI)77CXd!XPBIlis{6G)0- zcJt$U@J*D?PFFMh)o0DmVM~OM1Qf7saNx6sLVAfY;3gZk8FZzNXzr-^+9;cTqL#9w z#-JOrC21#)^RI~>{v@t{+oY`<|1m^s^L0A^@g65`dI|q+iS`kkT<^t-{bO9N|7X^x zwl9Q8hE20i(JXHTY3rS@^)z((FRQPDwP+UN`<})xzTbs0q52#+ZcXb@4HOH{gd$ogIvTfK3Mi?twf_Soa6g@#r(yIn^O>(_)k@4J1*4{yBD4MzpwoOmcQP+hf1Xg zHHzr-!vNeXXdUH!UF^t9JDX3~Gx(3BA1 zQT=XL+(7k_SgUg^@9sS&0*xo3gYSS557KgqjOK}RzZialYnSA%)wz?0cJ3TF+&&o8 zFMr*_LLnTo6^+NKy>?^IEimuS)BRYtS_Kl@d9Cd;j5lquhJ1@9pgj@07Q>g}`)QUv zy@m>mcNabkZ}n$PzMZ_TJppgAYG!QP1adyy7u%NB>m#3Hw=!IahR+RO)#9W?o~o51 zErxe*#-FXM5Za%a+nzU2$gG-;B?5^|jyRPcV)l$6+r-*is{#t0RHRR zq6Vc)p1U$7N@`KBz{3hs34$==ha|Ok*4^BjUof%l*(gt$+4c&&7p0s7?3(;vp5UgZ zSBZ*9oWJi_rX3hzL|rRIM(8!Q2Br9aU3S0RxRSMjLD1W9^>HBd@mYGCx$@)5<$4@J zyW;Hzs65>Va$bg<3q0sncG_#LNrbJtgZKUn|t zqh1TRXr_$UfhI)DOkcO?rf4ZQ_K z-W`C~`DDYX1clJxBRY)X;9v?=SWa)>H^`=9(9;D2P*rtU3E_+qFcFb9jBRyZYHpoy z#y(-F+$Kr2ZPe0dgdS}UzkM?MW3#M4vhxRq`I|Tlk<(Je-v+dFc-X19_e%OW`oBz0 z%#JVU0}7v!(dm6|cRO{x5LTMv8;Ym6oxDclptt;O3_Q&F zMTq=I5Q3pxjEIvyb0`&R!{&JCL+96XzxBtWV|xbnHWnSNHw=_<8hiWZRy%L`B!>zs zLBD8fm%>Y?#>zh!(N(VAG>*0)wL__e{+YwVa7;vim^+2N$tS zK~r}UdlSrr@d$V%yd-)hs0z@q^mKt$Zjc<>U2Ph=6rrGAOMopMN9m+GVi=s<*+VtV z;sk4^Rz%}V3vvT~>qMSXcaI7_qO^IT{yjB=8(~4vWH_8`dH9s))Mu7Nm1sukX{>4M zP@(xm7l$}+yl)ys2YxT*3h$0~^r2;m$ za;)fN@#*r#I}5Pr9=Y8dPr{(U8^MF?d!9JqG{5-w@1+}(!3t`QV>84Qi=Z=?@(J-e z-sKLclyyuzd_qMe*|brZiW5_qt|V-X*ft#C$h6)fIGoaR?rf^GEM{vgJ(~5_eS%E_ zsw(KEQGtxl(VDjb2hvmh)O4xcQqZa(VTB&68R zTwjEmU!LHEGnpS8o1iAvXwQiA=9yux$KL?vASpo-cO@>B~Nq&eL zII$w~S^-+UcIsIaAN`wS%SIAGQM$%Z!1gIK zlSJ>j7dp$431AF0#d1L(r;^A260syy26;09Pi9%-kDgy=r*4QjihQ>mXDJUfo>RZI zT@;|oO!~o8YoJBm#JSF**fIRiD!d(O&`YQGW-BP?NbOvQXW`7!R*@&DfM3q!eGkyq z2iN6-t3`Aur+X>S#u9-gUDJ$8`Kqk31|VTG4T=-C{AD8uYX4EE&(RooF}j$!0k599 zx+ruUqmf;*Yo=QZ7Ex)_eRCL<{G<4X_Mx$M=JU#NwYPUu(rGxLNTIX~*>~y(}@Rf4~nEvDZ>fY=p2!zrxd8dAC{Z(MZUZA{p01cZdR;kK0cE-*M znMS0c9OH=OR>2LD3Nr%*#W){~P^V84GRM!ST<;b!`020i-xZ8fx7U}Tl|A(Nuh_nN z<;E7x^O{$r32nPExW`y;xZG+WcUE>}xV`Bwgt5%fWa^Eed2z)+Y1#E_`xptD@4aIO z@ryMK&K+#ffQmNiBaBRoM)B8<)f+J;c=yhK3S^ukBr7x;gcgu9&uI9@9j$( zE@ytF>JO{)8Bd|s4W8o^@Pj6O=}n6|*d{~n4kBC&<;-}He?LeFNvi5w zNK%maEpi?Qk;81B&nt{$`_)2P9@JQ7Coh5r!xB|*{ZMqf(xzsxQmv%9S{pHnO&+QV zCRTRn^tAU5PiW8*yLOkLxLIgym^hVHmz=L>{-DKfgNuClYJ@=o+ARl1bj)zxt|#Ig z>nDEc?2gV(>c}A!TNmX{zJ_P9!KpOiZeND=j0w;ufJ(kI4UEcL!h_KFd#sX_v)n&3ovW6$}}_GU1MnF{QX0jnNUEn6s;Di;6xFrcD<; zN{i-QkE2%DQ*&7S8QVc#KX1ROEMNqvPLC0&ajOUv?5B`gN|z@Z47E{vsSt zW+zspdvKs7y>%qN*9|rC#C5}(kn{nKG#l|YDfkiNSyy9}U#LSztz&>EW(ToxNn^t_~yZVGwqlJrKD9iCBH`oo6+Sw z*ss9vT@s!i0L3?%hGCeDtV9TU5DVz3ae;Tr;MvdrGyS01>J_OTM|JYkoZ-P)- zc*DlFBT}OXOSf$@M@kxRmWtV9a_rib7LM@06N9BjXr5dCsYVFVko-^D!Fv3^;W-NL zKM4hododJ20vGy!(X$Ere}if`JRfrjOm*@uhZ%s+Rsg3SbN5*6$gW_0 z4r)vyJ@;-S2{T2#x)3rY95V;)Bi!~1*q_64)d!wyLbsy^%Y0Z*Y6q870XGRzHAQO5 z&*Arq#yly-j%G-_tpf%MWf%#b6uD2BWfPAzjV+?;EL4{ZY_VI}`t?R>6#9eh9tV;H z-u@|tuw%dJRu&uDn=iHx(0rvid`^mf#;ZZ^=HJ-3|hTjk!#a!7*EGBOk6}g%y zoFEh|pV*x{yQF{Cy(Yi$d#6*B6N}|~^!SpR9*rUXpl)#<#vkW1pZU%IFYv7hmNz!0 z2a<(#f&{7zd#l;xwKxfO?|H==pMf!W?rSbmPeh;#Ul2+qV+8HSI_O2CnbC6N(z?>I zCtY@?YSTi~nCj9>l-?XQD26WmHt?rB$8d0@qgMTzJ#HTii$*%uwUl7}E#BCvRrSIy zStz4Ro%%1Dz4&i5+u3E5(FlvafspS*j$A8DNFI*v0O3i#NrdgC|8Uh4@lARe^K(w7rNex_X> z^73Zfh@|enMV6R#qX7r2TWZ3Mie1ig0U12EC0qAyoEuAQL244mt&@lRn@dqZcL8)p z{;bPF%dNp~Mm)J%k!eeZ?EaUwpH;4_8WTB~*UIhu+CHt+Tj37B4fnm4cFP!OZN$_E zaYRSQrO0I&y4UG8jRh|sQX2yU?C(X2)N--tDAB8T&6U1){BC6#`7emw0rKOdxK29$ zjj9AOINjj;W(h$Sq7mz4CWfN|yggI`@zgNm!37+T6646P!gl<)s zj|sZ!`>)X5V)^hl%^9kNvg9>&^;OX-^rQ3${%mr<8m3w^w69$DDy5i$~3 zRb}N4zPV;pb&OOaEjOEk6`L&huceJtgU5vx>kkyX08+ESOUnYns#Ij?w|6%vOH#ODlE6o^YF10y~7#ePbW;C4L@iZ;+U7%IDy>%UutA7jb zfO~L!C@HtYIcjuGXzp#BUf~OykQJi&>9@hbNZrW@OYLmyu;|uxuX~g9#Fx6+I_zSj zkewzIvA1t9{+XA$M1Jq}eG{F&dQ|GPOql=i{hO5Rp`#2biZ2h6+O*EEeM$W%O8_U7 zErx_Icsz2o#Z%8$S9&6Otn8~ceSW6u*_$*as7aAjohNp-7{HH2EtJ2B)^J(K25QRW z$IR}|4heF+b56?F|G~54#s3G-P9dK9q0vC|frP#o#YSQ+VG*NMK^>uywrdi*IDat# zfEgY~&79!imK(Cv+OMT1xiW#>$BL0S+6*P29>zC0M%%Tpmm@JXvsUcxA&tFWjfs9s z6457AM?TvDZ@JE1#oFH<5_j!?mMhaS@>b#e6Lfpk$T?k3mJEThr$iiufu)5@>|+A= zyU@u3H&>ScQ$IKvgf1)_4gv8*)z9#}aNmid3kDv?Z{6BzNJNgNz5LJ1W*-PyV#J z_`1pmdPS!1Hvs9A#aRDhrb++!U=9Gc8GmB+D1u?Xn5bx%<5ti2^Q>~*^-RCSmMwzB z4THOksSKUle0WRHhpznW$eWByzT#{tea-ID{m{!heBHW#cov#!8stfDAAGMh4H-&V z-R>+#2jfZbUr?)K{t2~d$kLwrQlU5k@p@DEq2Uh00R>+)ddg};aTIfYU5C&;Tee#|*; zrjJDe3hv)ji~4_1EdzW)nGv3}jmS!SNP>Q=%|BSH^WU)+eDlI415o@?o%-v5`uwIuE^U>`PQIUiM5Y5ssB8#uzybow< z?|mU-GIY zyTRoUJ&>Vt6V|I@)6`p)7)ZJ$uF0$@{7g5dgQ+G24@94s{lY1L$m@!)O}Z!NLD13Rk2(l*SEcmMRKS{ zq(|7Nr`p?}nijM_+^;B>Q(7R3=RNbke%~Na&MS3;sSzeFg}(~J#%DD4+fgumWr|`r z#r=~m*W*`?FiL9@V7^5ggDiXxTRxLHwqEWQHF@$ z*YAl~8vWRin)RIoA>apBwp6y^+A!4r1l_*FRMI%gWa z#@ghejOLOurjtAui2z6GpQNe5+-yRkMb`O45E#n(_4%^Y(#kBZ(HSPXm(6N^)PasN+pHLgJ zG+PvM^E<)u8_J0lo{PTt$a{G|xP;jWwFlUYVEd`DF?vEfwE4XCvr?vUHOhRJ6k7y zlP^%?QG}gnYfA2Pu66loN=~+yqQ^3I;PDpt?C!X@=)5Yu$M{S2xp1XZTno7;FY!08 zAjX9O)1@_)&o5==6-c81Ik5C)BsHPMnd@nQU_#q4l#zTtMl6Y{u3Zx%>2(cMiBn z+cMWL*L{eKi&9yu#ne#`7P2oF1ilKcK)P_}?u2*@;&xmN(D**1eV<~X8~R1=-~rD~ ztTzq)vVR5LZ)q_i6xC2<8D)UV_Rax^wxvAG%-t*?yF_rq-jRZzhgNzfH#A77E9!jG z<}`QDY{pqLjOaYG6I2ndDSAO@)M#V6zB*-%%#oE~!KBbCkning=tlC*R(O(mt%14| zj09KV@il-CUwN~Q#OE;VL0czB5xjowpa^5nNd$Wca+d$MIbL-gUJn(KCCm^$IsTk@ z{PlYPHPL*3tWUE8p|QzAT@3%Zj*L`Oe1%VCIhKp5d1i>36fQN3ugYIua`C?VYi68U zudi-hk>Hey*hVeMW;h(VdmiBzgCPaxW=drZ`K5D~$-QPa`BpfVoJ<;D!dnZLeFD9% zzhIXN{0QJs|5q(&-Et*H~I74 zs@p5|l@KCf`lgc*J43m#;LVd+FeB{n$}7dY`zwdTaY?@rS{cIZPuw-sSPndhMZg#e zXW1w22|E1CFxDR>o)}oMx#A98B}sREP-L38sf9!AzOl#ip%pRvccm<>hKk|83RlyL z0{^R4wvS+CVf>#zi)b;3{jXYDfeUrv$33LK3u;x-{!=bnS-X=OVl)D|CKY&iomk-* zR`q9r^S=YHd6l#suTbJMRMvGiEQn0ZnYQ8oQ{G!e)q%F#n!yR01lK?yxNC5CcXyZI z?z)iR!QI_m7VhpY3GT9Rf>bXmRe$Y$_TPJVk8}E}b4$kH3Rv@<^Laj3R)MQ~Rye&~ zA_kVE-~y%gY+%?qS%@|qBgSK6-eG?HhL`yuE`99l z{~uE{XY#GiIB}MqxGL{vfBoX@Y|jIYyYGI9>%5PFu+J4GT*0R+_v*XHO%>JfJY!eJ zHJ!NXJ6P(g(P&q0>%)_|Hb5q$P50F}oeuG~mQAbXmyyWA<9w99FX;|JQu;wcyU6xg zDsnWst=8Yv)N)$=T23`!jGm74?;0hrwOq1%&`yANHg4qX(15BlE*(xAz%(nYEt3sJi#otDgsrmQWmLn`u!>4x292P)sN0w>r3WIhTHM$Mz(y*~~tI znPZ4YHkq!u56+7;f0n=kh$Ws*j$q@%8&;Kf_6DF_z2`wTGQ|z6T3~{Wu_jLwN<^;Cv@GDU|>8j>?sn{^Y5(vNcs=Xoe7`yUF zB6Qa-e;hgVXsF)*XvT>Z!o9rrJh912RnghHeE8jA&$X&jjq)z+$~J*OtcQ%tY}sjt zmP9&{=IP2)!OJ8&`{_c)?+kLoS81}?TLOAZ&ZvXab(+pGIKnm=Na$ZW={K}bHf>4t zL)%!5J|Zeg&=9eUQ;h}FfEewy6lTT?6Oy8V`ffXdCC0X>u^FW-fNZS4*}7tO_C>XS zkRVov_Dz+v8)n4kZU38ULS8?-^Ac|X6dNxm_VPdCS40-noO@-zpuTcBoQe|il-w{q z>h?7S5L;%2L>b_Le=2OTS_q7K%4edtU-Q?}CABFGUqkhQbFd)H$Jf$VN-=EA1iWy@ z5D`1Z$G2#5{Td&l9A1*AsF1|23%{+H=Yv24RsNAvSS>PIlD-GL{w~eB_q_XAEMHmg zoVO+2A)0_VkcS$LOr}4}dE}tFc#zPS2({)J4JC&T54-QgG|I%L!wi<+Xw%ZTLNlQm56n*TO1l4q8nX2R+(`jZ?q$%EP>;GTVX??HN$y$O1Y zeV7%rQjst16q%2NtY}B@<~jdO{lZscwJgP$EmEq`3qnZxKF8o`K}qtlE~{}wK$^^Q z9#c{{7>6o61R7Ape>3rGFkW5TfQq*bn8=$!>R93|T|`VQ8e=6adlNg9yUSxAfe8Mw zAmv2bjXWfrMSm@N3$gN%<5nVTdlE4GM$HRhp>(a3s|VVRclP_ark1RGw<`gGBK0Fy z5pwvNNF?M7hIm#S%#fR@ZYU zX=NdPr~E<^RXYk~xs1!=u*O+~x%89=UU4xo!a0iay7+sDvc40aJfW1&1jYbtnnCU0 zz>~ZNh(xr6*6wFQJIGKra}qjb04NNZA&gdW78pbrJlWWG*^iHX9WG6o_*`p6-xX#T zTuAe;##i~v!oO{NcVq1on^<8}q-j~uE!|_`1l?oEv`4-pa5Y3s`{8#=xmBKoGr%o3 zW$1Qo%{8J3x{h6PV~AY^Z0@nUrN?Jqwn-9cAI@6MkH z(SJNeA*b^)rTR?iUQp}gm`%OYQiKylxj9Qow)P6UtU?u`1X!Mge`QzB>xe)s3J~@g zn)y)6IJOp5j@ui}RDgZl6dyb=P-gdQ5AK5Bm=F7V4frpbf!jr%6~pI_tp;rGIyl)M z;awB8MgE}f$zyWOfiwCKj@y)v4ax=rv}O^5X7r>=jx_S zC`LeIpU@dM>y!cbC#RVBxfXDFujl4szA{R*ChvwY0iR7`UU`c_Hjlpd55qe3{TfDnv&S@ET6Rij{0NHCD&Lny8KobslP0 z{qD1o9vcT{IK@vJG~-Tm*Ad`GE?X}!o;%|k6pb6Wx6M8N#4`u8OnzG7Z5bJGr0a>qYe3t%b5_R%r6bbdL}{i>%XWU}K^YhQhjy68mLc*t_H8QDapZ-f0K zPe#O`^M@psR_Z1f8mol3Y|N9EevUUnsn$MG$(B)CW;Z4lu%iL9DlggzR%9`*qHUS= zGvG4nz|fMwZ-W+VGe(A2lQV6oIp8ZU{s@WE6#wkJzRwc#`Wx~)+b-8Bev&aUW%I)? zduU3KK1!l}@~~GDjAT-Lw&%FcvJwIYmubHSsDUUK5285Cl}+t3or{UKrw(^Oy;1Ub zy>TZ6P`>0sYR?c}%H%icJmQ{RK9d+V4dQ?uD?8~`qi=8m+s_w-&n-T8zqS+G)KakA zH-#H2tQB!A2buEwA*Zh@U42mZZmyz2D4KrN^H4=2WO)1$6q0G*AqTK+4ydcyslhA%0sK`fd7%gO%nE~y*z(jyPYeA7$<>#go+-Hbw3Msz(Q_dv6mccC>0TJWad4c7+~?xX-g zWH$r|t(9a-_^DhKAHIR;F<7cnv`3q2cZi(Lqg$RZDrh#FP^e^BHrCREMhSz1$-M4# z1drK*w{{}vD@LYhFc(o<`jXI6eNnUC3!4V-=<+f>Q)g8{z7vFn$>AVAJHW8e&5>k_m>$r~9j3vU-BHkD;U|>Ev2pHclCE4W`48oR0Jyxy>+8_G)47#7D z7^ib4Dk8K##aLNTds8+W!nZuq7wsbV|FFfW#Sk5~w@^LH4(}wu%ae4w5L&xGjhl^m)i+XnFP&IC?2u6Qm zbgP~9UxZr4gyke*)8l-(%AA7WAN{znc>|L;h(5%v>NTHST?{;Cj;&XUJ~pU5wunwh z8PexLsN7~--`9MJZOJ3*Js*g~tNi-VocSJBI1PFD_K|LH z@atgac&F3$v)4;+)~=r7#Ef+(;!{c2p z1zC@X^m9$_d6WKe__8m76z=X}eZ#MYo;IX|b%AqQd^J90kB4FJ{%ku8xwM(?`g2RR ztn>Ib@~9^(e)nz)YL|3(&4J;Rq^B4I54BSj$bmhE+hOxW9)kv8zvUR|0!CSnZ>n0zlMLI>~{#&%_{izJB7yHVcx9{)usFn zq1_uQ;9mFJu?Ipc_ZgZl`!lcBBAz?U$^MC)$|lpqHdmz9Ftz^r;t8P(0~bt*Ii$-f zF#o!PG=HvrSnAu+gKDzzU3SBA>+BGT>5+C4z9YrHBd~6?&gY~-kd$9UZf)|T zFQpR**tj2RXE`w$T5gxK5L~Y|bu*`yC+u-r{58_`X14u#&E+19JcolBZ3xS<^y3dk z1Piz#-d_{w5i#`WTRcAayZxYuh$740m}O4|)O^(Tzc;ATh2dsTf4>jpY0XFVc$4W1 zv2_$0bd-!_y>|O~zV5yMFR{EB4t6w#v9Z$u@a~wTd8?8LwLIkJ0%FZg?iA6%Zac5d z;JIjyuC}8T&!xxxekILpK2|ay_=%F=sGnr-uS&NCC%N2$|8urLICk9BUWvT;TL^rs zB1!(L7;yY0Nk|j{yWOA|l8}iW#PK;b_kW7FwIeogGrY*<`FpYeKez_kmniVTBtk5p z66Ch^DPdunfc0*m=w^4Q6GGAgnx->#*tn|LTD1`m28gr;g~jkz(eqCm4qd?L%5Sm} z<`#jI91wOtNi&iFrkxg{^Fkr^KMt~s{i3sU(ajvTNf-ol1i<-|iRkkWSVTFiyNSCl zMw6~6WGK@5W_k7mx{sx#!GHI;!cdl5Y4ngz^2vKYSLiQV)G4E-^`AtzcTAnDjNE=% zoX$YFSLWgFRh24*k6pm?%59Jvub#8`R12=`sdO7=`d-sSzzp-FTbmf z4boN+i2H=Ze4qtRI;PAQ%AcjQdRa2Wj96pJdUY(8YLKcEt5H-H z)pc_T>mvg`gwbebq72>(G4j^+!owAMB01ZrmaK_GW6H?MMtiI_Nws!G!3rQjmD zRVX~*-o?dcVV(2$mLf-ET?h-80S6lUbNaDI(XDEtAH(N_NN@{zwv67j4N3rhXV68P z=oOfcUr!mb)S56Nv)*CI887Pkp$W88#r0Sy!jHfu!Y#6q)l*QoPE#nIJMWHuV3=KT zqbs~g0Oko`1s^@m$wjtSFtRk)ctO*-LQId|JQVF*^^&4k(%_PO2|O?i<#y* z`ZT^rB;Ka7MGN(bnJ?sz?`pF`uq>(?eFZR>)nm=TZJ3(t2wmk7C=-VD?4CK~hGZYr zhot@dm&J*k>9wq{_N*7l4X=5$0KH!a^L)(@&v?mVgGce;-*&dqK-~>pzMOdGhN+*^ zJuG2h58|Eb5)ssUtv}MH{)(ar0w}e%Thi1{2*JcfAL@8`2zW#_00R9jykG|`V~|uc z-X%CTOU?+?;|BPu<^Uqlt+;jd{E&Fr1ubTR0WgJO3KFolbqYy8|7>kb&;+uht7RpZ zXE94R72pRQ?ZFnP7_bZLs3^)JJ4fMa(D;jLVQjHd(;xXXi#=R~&?eUgE7zQSdwj1^kfU>n&E za&;2lCc?1t$6lC_HEB-1xqR>LP6S>cv&MrL$gpJe6i^aQNt&-Im4jE|uLUwP9k{Ed zX4~|>DzOIfGKaVZ^ZXGlksSyWNY^>iJ4#Be$>bzIYwr-0m6y{i}p1}P@Byuc`7M28}9*DpkhZ_xz zUFbk2JK|B_H@|+Lth-0dVktXfnpyQ`tUUDTATMAK0_22ZpaF*Vs)getR`+gQ@3rvrW`_FE1{>67V*7 zAAC87NqSSI^I?1P$MOEShSp*U$fCpGN;-AjvmOis#VMJFO1>~8-!&pbo!~8n9QC}R zMm>6AK5yU_f1ezenbSy`4_FPtI`W(Ts)kF>w#$a%2R^N4MP~Oyr~9Oi|%hv!9P35x4~1Zc8y?Hc`CLGaiiL?CCugAGt)Kmuf^^&}6)oR?6kj zihIj}UkLhYxdb^(5P2`K-z?37`8~zW9}sTIy)r;#?v87sWhHwYxH#kIWtLj6mEg1f z{ZW55h2)akhLkJdS{VuX9reeP@4X+nfrX=ilE+QasRjv~4cB2OGtTUEX1a5&86ppL zt*bKOBkSWmsB62N;_ODhSUGOKtH4?)?S>-NLEtW$;TO@mVbx|KS!YM#o9mE|7J{^8 zCSxY*0VdeR(NvIl1Hst?g`i66l{Q*A>-85bVXR8-s9(?3yEpk8$eiS(z-Mh@bL>e( z)CSs%(^gc*w zb3)a#CS+n``FA;7O2p(pO_LMMFmQc#x7nUl0aJe~jz83v4*X>~V~~RT-;2ZHv?faM zuPfvU;>KFFAKC6t_4_=AG`}zdmW|zylPl3#O3vlGTh3GD^>N_a{hl2J!5!{56-rfv zRHsFC4&o=nKgMcF5_RgT@C|dXH!@%n4E9^+O4qO-7Sz|tSu8(C6Wx%GQ-_{Q(#_Wv zvHY)NN4|(-TPwd0Xc&*e%up!*#B})fkpB-0TT&W9sn} zr^dw=4SyBH(ABW7|3j`HCN56xOrF~Lnk;+5KFn%MSuy`qqS$>S)lPYWzpBbw@LTqUJE$ru|H<>lGXKT%q9wiZyo@(so|imptmi7Kddjn6UQpa( zCU+CJ21~#CsQG+^7Ci~&z%_j_vqUw$Is^HOhLwjo>WD6uwjd1*mN}LFE7gl*B|lcd+VbvW9ESM2Q_pB(O!YzOpT+HU zC%xHsy2KjX^9kU=HK@ZBIQf|420HX2*LkFS@m_WdAV4rf%dBh1IX|{++^{fX^wsQB zI{jt$uv_RwJ|f{u7o4$SLUhaMRp%7@Ue$dhJ}F5&9Xy-X0FL@?5L|EcyiTK&vewj) z5Y#~R8oG&Us!a62vfJc~q07@a;zThsceWUl_14UpF11(ak{o~1_FEx;heR)UAp@EySXojT~yfH`wi8<9HyYT&fD=ehLQa@ z%N{4>CVD5&TR-9w%EO_92Vsyt`$;bkDmi}GaU@%qx$ zJetB6r|Z&8J1^m@*#>p{u}UvFD)az*MeG_<`gmV$QzziQk*Ad^>CH51K&Obx!Tf>gjAe`tfY!Gr%CPhf2 z#F7sMgo3lMpMCP!D?9ZMSsYKVJ7%iC-AGS)PL!BbWC#xNBql6eu*1^$tzQWpVGhkg zdl$x!#`a)CE2OΞKeRsCdspPb?waOg^~*ilP4>gnYrb$P5ADi+^&(DFG}d>Ax%H z;xA}1L2Q!&LBSobTrmclP72K{SA6TE6D$1JY}*L=zk1{g)i5mJ%AD65gGeGc9o zkNqkJe6selq#EAZL$3C;Ll+g>T_70czhq^SWgrB%w0~y(yUPwBe<<~B5bG!t{a#%`zRSyT`;D|DKxC7*fhcl6-b zGIpGitA#t8PXcl5bJ1FnE7_R{ZGP&v1Za9PspcTQZ8JKq&S3$Ak%9yAkC64n+wqx> zVigFC&M5tYhi-eJL!N;Z3dwD^h|ZX^t=238BGWL1ibqm!O$r+jh zU*IJY#Ya7P^4l;o&K*o>reEAMD=f+(SnX~WJwQ3t7TS*}7+>h^AkaOM;;;58R*FMf&en@h~!H+Ukf#pR^8YR8# z$|7HpNpf775!JPfp6agN)WE)}Q!t(1?@2LW29x>aLOf{Fjo^cXE{iH5Pno83*;^J! zzA)c2_jf2GPzhoUKI<^(%zN8t3^ROh8?+?)k3Y-e;3_9`zWGHE%vxI}N6BITfjOcs zK^1qaC10CdT;L$H$k1GuVa+-ru+-SXDp@t9Ee4T}0eqK=`&!rV@>$a0FhNK`-dnpG zDBM^hE)pt?S&>*{^pu00HEj?Sh#psfeIcsOg4n^f02O9!A-qeM&`{QcK`RpvWGapH zEQqB~$dr$Q(fm10Rh8(nb}87Wd17=bY^Cb1txbq=BWoGcypaMZVRjGw<|Qkf?W5I| zI(I88MmHGlPM<)WmrG1y&kI4&(}hR|MK2tj@984qF#!>-${&eCi7BH>#)4_~v4f!d z;>Hp=?%E0A(){`xEWuY67gZHVuxojD;!K8E*sVIiZKz!9$iVZuw0JIn-zeL7SHh#8 ziK5@JL2?anF|c#`a4f02Q^k*daC#9klC|qy8!bj1LE#G^mv`Hn4-0x9`-s{-BS z*hcK~1|as$GBBK;18Eqk8?ZS7fjs z6)0u=G`vuiv{>~wbse8mJWm->^FG-QM>>CqQOG8DQpO)gRL$lGive}(YZS+nBM{kQfLn&Iw-0y8Jo)FZO!$2ufnr{P@ZM>ieDKYbgdT4=#F#dUr=2Jv zO6>CoNdd%i*f8bhTRP)AF6yauQ_uZSk0Ok-R`NRtBq=D8=M~0c*2r3Yri)-+&TP-| z3c-)*Q$KB19TSKP-IGe?cz0tLsQuMm5U8M~**iB-@JgT7L-=Z*8c-L_cWu7|^C@bj zz)n-Z9p zT>qYIHI#_Q(wg|OZdT?GwV5+`^Uja74=0szy1a4nLE3@8?9#yNcdLhTag~a^9R6L> z^MmOtGw|gE+nZy-b{XhX)pMBku?s5pSzmg<;UYF;N2JRn`Td1yRw4+oV&~m3&_@rgm7~B(!vL7{u1Ax~OLJB=S$aPbgWeJrh$)N$Z*e zAAUd;1no6n$br#9gNdc$o?Ki*2@?++96}YLTn=Nn6ogUfI^Hh3&Ag_b`4JJ^?&qLy zPEWVu4^anK829>NoHJ;(EAqm&q=P#LgXU%d zS3a+|ZHv_VxF<1|B#mc9xsM#uljf-9Q#Equ3kjw%8fCnF` z6(QNxth#Ha2DlLA#-gslYR7dODWho9L6`t$YfN$#>#N?z7z0@ z53_(4{fF7`>2RWvq_52(1Sx~~g#10RKZ5=DV#OS>CIt8FE%>2{Bb~zu(TmCv1=d^U zhjvQ22PT>N`b9m2 zSrF!%g$hC}q_c(+a>-#MRjcg36+h}dbz_w62O{x!3P7UO2|9hx`npgPuE8H<(5i?Ar)h>h8!z_12WvrA=|&O>l+Rar9tei zOlE86_y;P7!3I3lsAPc5XwBxm0clXGsPGC_evPAQl?$j?I{L-0h&EPK=C z6AWGxvbn=z&Gm+mTQsr9G^=?cAC;Es!?))yotIPr8GHZDuVJ5aioByWUUr;RSk5>~ zjs4^wJhc<}3PKVIEUn%08#vk%8Oo!(hwg1WGyERf39i}_(2Q~F0+GpChzvsr6(1pn z;*v%X!nCq}W#g9S+eV*E-&D|0=VF1s2hQq=;M~u%=I^%}7(|c3<*D0aG) zD0oa7@hSm4J}26Oy>f2{205bjQif~}3sMHpT@2>IuzgNZcK0qDN>tP49kkck;f|k_g|b?y=EhRWZF8&$Cbapkif9B zwHh+Zd0NdJ;qKrbX?{DxhjH={gCd7L!GumOuwvx)CU*QfZ}+VQwY!0DDircLYHk(c zaQlZTFXsWx;?eNWftR|GlN|Nr$uu~oZ`J=kGLfev{m(}xB9KybrtakkLB251tUL*A z(sJ~!_^pCfW)s;SI@;QbDqF0Sewak^{LKIpLr_iphYF!3HZKu^`3+(!c+G_o-?tx_&R#pE?MUmlDxGhKs3=y;5zr(_aTqO~Q5iEbg0R0-~MT7tJ`AfBVH zR+xvev-@lN?IorpWOgmdT7L>kzfkXVyzvy0;gto6wN%Z`CShOnbnB@Lt=@}sTioMhqc_1o*{{n!h^k)NpJUZg%0-Q~rPEnDk=cv)B9o2C{Fp`}dUn#^Ty<%zokD zQucLjrOZEq_N{FP{yk}*C1p_LiWBOM^n*snI7lUvX?OSY2Xe4b4)dHT+ZC?8$?jDe zw@ZG95!kbv!IpUl1l#A?X8OdB1N>tj%CF|yEcN^+?f0mmQua4kCvhH#T_^Q;@iMN$P z3gnf-D)Af}KgcauU^r`vHDiY18Te1ixT5UQZQf0lsdFpY02Sq-GJQTX-%^Amd)?zb z65BxVDarHQU#BEzdP;Ye3-6v;&S@x5?(=?EMfOCH^^L5D-lE$`yn7VTCZSwwMLSIGC zPo`Ocxzq$c&iKFX!a?v6In07ZMTU%N{s)a7^IGryTgO##MN2Iqm=LRrZ=D^spBWy^ zL*}6vxnLzCe4C2)*&tO|{hSlng1SgD$BqnDyw(I#KI*0vhdRKIK^+_Lc)elYP2PoYnm>R3TsI99>f} zHZWfnWF=+Qw!T&S-8i2#SAex)s zZdGf)DpBL!2&=)@^{XHUVehUV!n*C+;WKHJ9StKzzY$ekqc&cxLLy_4-kE}Puk7Y! zc+*|a+o{s=edg!bdsp3+wVw*ziZ4*{MPd(*0uNm=@Ad*Aa4>Ne%07Jz-M`66|XX>odNxUHGk&j2}@cOV3mH+pMC( zm@uJif~N~1c6#&@f5G~4FtSSjvdv}x8{1r?q`PB}@&NLz z6JdhnzXSFGufV>Qv^2!uz&^#msuT8RS2z(s1z_+_P#~DE?)B0XnPIz0>s-vUwO{`IZF@#~)_3d%F zj<=qS6=-@fd?Yv31jsDg86vO1e#oW&Zg<1${bLC3_5KkGzJG)|6rJ@~00D8r*!N3Q z?;^!l%z>4&Xgk(#-U&{C9duks^_N`^7T9B2ML#LMe3qhxcie_F57a_ya%=zd>At{HGzoot&y=ZO$&anDB4momDCE(XP% zc%H%@=Fp`ISS?%O?zWa?l314b`Wvj*z8>PZ9l18yz@3?fF-xO)>HQDO4Onlqh&RLC zaDa|bHZcZ8?swujRh?3I;Fr$%(vJPle>}0Atl7UqDa}g|@gNvF-lw7dP4xFH2$J}g zG|+?ZB&dJt>2O#7($lfJ$|Tu=Cn8XDs=;`nTC1G!e;-N!X<47jR;##qj0%!Vu(7O@ zJ^K4Mbnq}Q<3)3RHG%eNs8~zomAQk|h~MQ~M~8NU6k)Lmod;0=gQ2b(FH#U~*PldA z?v?1rUw6{%H?sC_V}pN)`A<;4%tZzixz0IF7*lHm#YbqU(a@~Lb=cj&$k(Sp`@E)j zwexlZWiI1#W5nWl-(kzwc6+@m{5h@fc_X{hg98m?$DPDI$d&aO9op}04q_f z8cQU;u|kLPAGPk!|AU`yfiED#L=I{@@P|4HSWxE+O2Cs_#vqRT=&#wFm1?2>PKgai zF*so`{KC-zIDT=w*WLoc+FVM&W`Qo|cc`;K-PNN5FGZ-dEr7wdEX1!&zaV7CkqPO3 zZE@k0Tb|^quyYu?b;ii6vCe-9;9NT@#4Ku#6q&|h$CU=&i{OGSn&c#{9>NSkpBnxv z+OOSggI^jlK!H1*OT7ZIVFnv}iOq^%ZTJ}MLd?nur1lC{6EO#(A-n3uVs>4oX0O$} zH}CTlO1LZ*hX`}L-7nG~DK5{24@ zDniHarDgbE40b#N0T%A!*U;JiF7uUS*UDkN zVL?b!epF6X2WP^_bD2(2^sMq0=a$J}iQbr~`Pvqye2dZ3Ocg<0BsB}SFj6T#Rv zMb^D4s!=jhd&Ghc{lFh=JxRrOqNUY)IhREfj7>1d2Z+)0bq;W<13DT@>slMw{sk!$ z!I>avulLthF>ytX_I?!=Ld)x0%=g#wSjJf={gMN%N%39kDplsYqm@YBmT;HFlqOY-oiKRl8>JavgRKFGjFS!#Kpr{M$%6Zca zxODO|%O!g|{5H-PY^#&|(^fZs&C+P`(b~TISj!5;dGre(U1zEB%#;@Y1C#p6dhhfC z#KF45dz9s!yn?#02x>Rkz-@8%)j5>=2_f?!tGBY}Cw^G{>Z2Pv=4MV|{`~Jcquec9 z1%{G#*dUFA@{OCXuj~7ThJR`|NVBI-z6+da!sQ0bt(d{`cbFi>VYiuPS$f-Svj@_26D`Cl zH!^2rUdh^7$k4l!ZqIV%g>y!DB3C%Nmeost!T7g>P8@_Lnb|-yVB7z_*bYamZwg1C zD3__nBEhvn*Dg`RKhYFBDL_eK`7-oH8~plgKuD4XrE1D1IU*#^m$th2!;F6Q&EoQm zAVx6duL#JJueQ|Xb2cuC4Ud5}4{;->3f&3z5I;zG<7k#kr3A+KrTiJ5O7RCoMC20; zrXO|=IM3Z#aV%J97P)=O&@ASb_dwKW2BB(hU<%=F&+9$}A}s*6Gg0i#f3LOse(6Vp zm)pQr Date: Wed, 18 Nov 2020 18:14:44 +0100 Subject: [PATCH 6/6] Fixes array handling for ValidateSet Empty arrays will now properly be rendered as empty array with @() instead of $null. In addition the config renderer now also supports ValidateSet for array entries --- doc/31-Changelog.md | 1 + lib/core/tools/Get-IcingaCheckCommandConfig.psm1 | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index 87eb16e..aba71fb 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -31,6 +31,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#138](https://github.com/Icinga/icinga-powershell-framework/issues/138) Fixes possible value overflow on `Convert-Bytes` while converting from anything larger than MB to Bytes * [#140](https://github.com/Icinga/icinga-powershell-framework/issues/140) Fixes version fetching for not loaded modules during upgrades/plugin calls with `Get-IcingaPowerShellModuleVersion` * [#143](https://github.com/Icinga/icinga-powershell-framework/issues/143) Fixes the annoying hint from the analyzer to check space before open brace +* [#152](https://github.com/Icinga/icinga-powershell-framework/issues/152) Fixes incorrect rendering for empty arrays which used `$null` incorrectly instead of `@()` and fixed ValidateSet which now also supports arrays as data type ## 1.2.0 (2020-08-28) diff --git a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 index 8b75a4b..a18c80d 100644 --- a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 +++ b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 @@ -165,7 +165,7 @@ function Get-IcingaCheckCommandConfig() 'value' = @{ 'type' = 'Function'; 'body' = [string]::Format( - 'var arr = macro("{0}");{1}if (len(arr) == 0) {2}{1}return "$null";{1}{3}{1}return arr.join(",");', + 'var arr = macro("{0}");{1}if (len(arr) == 0) {2}{1}return "@()";{1}{3}{1}return arr.join(",");', $IcingaCustomVariable, "`r`n", '{', @@ -259,10 +259,16 @@ function Get-IcingaCheckCommandConfig() ); if ($IsDataList) { + [string]$DataListDataType = 'string'; + + if ($parameter.type.name -eq 'Array') { + $DataListDataType = 'array'; + } + $Basket.Datafield[[string]$FieldID].Add( 'settings', @{ 'datalist' = $DataListName; - 'data_type' = 'string'; + 'data_type' = $DataListDataType; 'behavior' = 'strict'; } );