helpers/DscOperations.psm1

Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'

Import-Module $PSScriptRoot/GuestConfigPath.psm1 -Force

$script:ExecuteDscOperationsScript = @"
using System;
using System.Runtime.InteropServices;
using System.Management.Automation;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace GuestConfig
{{
    public class DscOperations
    {{
        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr new_dsc_library_context(string assignment_name, string dsc_binary_path, IntPtr writeMessageCallback, IntPtr writeErrorCallback, IntPtr writeResultCallback);

        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern Int32 test_dsc_configuration(IntPtr context, string job_id, string assignment_name, string file_path);

        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern Int32 get_dsc_configuration(IntPtr context, string job_id, string assignment_name, string file_path);

        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern Int32 publish_dsc_assignment(IntPtr context, string job_id, string assignment_name, string assignments_path);

        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern Int32 set_dsc_meta_configuration(IntPtr context, string job_id, string assignment_name, string assignments_path);

        [DllImport("{0}", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern void delete_dsc_library_context(IntPtr context);

        internal enum MessageChannel
        {{
            Warning,
            Verbose,
            Debug,
            Error
        }}

        public DscOperations()
        {{
            m_messages = new List<Tuple<MessageChannel, string>>();
            m_result = "";

            WriteMessageDelegate delegate_write_message = new WriteMessageDelegate(WriteMessage);
            GCHandle m_write_message_gc_handle = GCHandle.Alloc(delegate_write_message);
            m_write_message_callback = Marshal.GetFunctionPointerForDelegate(delegate_write_message);

            WriteErrorDelegate delegate_write_error = new WriteErrorDelegate(WriteError);
            m_write_error_gc_handle = GCHandle.Alloc(delegate_write_error);
            m_write_error_callback = Marshal.GetFunctionPointerForDelegate(delegate_write_error);

            WriteResultDelegate delegate_write_result = new WriteResultDelegate(WriteResult);
            m_write_result_gc_handle = GCHandle.Alloc(delegate_write_result);
            m_write_result_callback = Marshal.GetFunctionPointerForDelegate(delegate_write_result);
        }}

        ~DscOperations()
        {{
            if (m_write_message_gc_handle.IsAllocated)
            {{
                m_write_message_gc_handle.Free();
            }}

            if (m_write_error_gc_handle.IsAllocated)
            {{
                m_write_error_gc_handle.Free();
            }}

            if (m_write_result_gc_handle.IsAllocated)
            {{
                m_write_result_gc_handle.Free();
            }}
        }}

        public string TestDscConfiguration(PSCmdlet ps_cmdlet, string job_id, string configuration_name, string gc_bin_path)
        {{
            IntPtr context = IntPtr.Zero;
            try
            {{
                ClearMessages();

                context = new_dsc_library_context(configuration_name, gc_bin_path, m_write_message_callback, m_write_error_callback, m_write_result_callback);
                if(context == IntPtr.Zero)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to initialize Guest Configuration library.", true));
                }}

                Int32 result = test_dsc_configuration(context, job_id, configuration_name, "");
                for (int i = 0; i < m_messages.Count; i++)
                {{
                    var message = m_messages[i];
                    if(message.Item1 == MessageChannel.Error)
                    {{
                        ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", message.Item2, false));
                    }}
                    else if(message.Item1 == MessageChannel.Warning)
                    {{
                        ps_cmdlet.WriteWarning(message.Item2);
                    }}
                    else if(message.Item1 == MessageChannel.Debug)
                    {{
                        ps_cmdlet.WriteDebug(message.Item2);
                    }}
                    else
                    {{
                        ps_cmdlet.WriteVerbose(message.Item2);
                    }}
                }}
            }}
            finally
            {{
                delete_dsc_library_context(context);
            }}

            return m_result;
        }}

        public string GettDscConfiguration(PSCmdlet ps_cmdlet, string job_id, string configuration_name, string gc_bin_path)
        {{
            IntPtr context = IntPtr.Zero;
            try
            {{
                ClearMessages();

                context = new_dsc_library_context(configuration_name, gc_bin_path, m_write_message_callback, m_write_error_callback, m_write_result_callback);
                if(context == IntPtr.Zero)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to initialize Guest Configuration library.", true));
                }}

                Int32 result = get_dsc_configuration(context, job_id, configuration_name, "");
                for (int i = 0; i < m_messages.Count; i++)
                {{
                    var message = m_messages[i];
                    if(message.Item1 == MessageChannel.Error)
                    {{
                        ps_cmdlet.WriteError(new ErrorRecord(
                                    new InvalidOperationException(message.Item2),
                                    "TestGuestConfiguration",
                                    ErrorCategory.InvalidResult,
                                    null));
                    }}
                    else if(message.Item1 == MessageChannel.Warning)
                    {{
                        ps_cmdlet.WriteWarning(message.Item2);
                    }}
                    else
                    {{
                        ps_cmdlet.WriteVerbose(message.Item2);
                    }}
                }}
            }}
            finally
            {{
                delete_dsc_library_context(context);
            }}

            return m_result;
        }}

        public void PublishDscConfiguration(PSCmdlet ps_cmdlet, string job_id, string configuration_name, string gc_bin_path, string policy_path)
        {{
            IntPtr context = IntPtr.Zero;
            try
            {{
                ClearMessages();

                context = new_dsc_library_context(configuration_name, gc_bin_path, m_write_message_callback, m_write_error_callback, m_write_result_callback);
                if(context == IntPtr.Zero)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to initialize Guest Configuration library.", true));
                }}

                Int32 result = publish_dsc_assignment(context, job_id, configuration_name, policy_path);
                if(result != 0)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to publish Guest Configuration policy package.", true));
                }}
            }}
            finally
            {{
                delete_dsc_library_context(context);
            }}
        }}

        public void SetDscLocalConfigurationManager(PSCmdlet ps_cmdlet, string job_id, string configuration_name, string gc_bin_path, string policy_path)
        {{
            IntPtr context = IntPtr.Zero;
            try
            {{
                ClearMessages();

                context = new_dsc_library_context(configuration_name, gc_bin_path, m_write_message_callback, m_write_error_callback, m_write_result_callback);
                if(context == IntPtr.Zero)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to initialize Guest Configuration library.", true));
                }}

                Int32 result = set_dsc_meta_configuration(context, job_id, configuration_name, policy_path);
                if(result != 0)
                {{
                    ps_cmdlet.WriteError(CreateErrorRecord("TestGuestConfiguration", "Failed to set Meta config settings.", true));
                }}
            }}
            finally
            {{
                delete_dsc_library_context(context);
            }}
        }}

        private delegate Int32 WriteMessageDelegate(Int32 channel, IntPtr message);
        private delegate Int32 WriteErrorDelegate(IntPtr error);
        private delegate Int32 WriteResultDelegate(IntPtr result);

        private string m_result;
        private List<Tuple<MessageChannel, string>> m_messages;

        private GCHandle m_write_message_gc_handle;
        private GCHandle m_write_error_gc_handle;
        private GCHandle m_write_result_gc_handle;
        private IntPtr m_write_message_callback;
        private IntPtr m_write_error_callback;
        private IntPtr m_write_result_callback;

        internal Int32 WriteMessage(Int32 channel, IntPtr message_ptr)
        {{
            string message;
            message = Marshal.PtrToStringAnsi(message_ptr);
            m_messages.Add(Tuple.Create((MessageChannel)channel, message));
            return 0;
        }}

        internal Int32 WriteError(IntPtr error_ptr)
        {{
            string error;
            error = Marshal.PtrToStringAnsi(error_ptr);
            m_messages.Add(Tuple.Create(MessageChannel.Error, error));
            return 0;
        }}

        internal Int32 WriteResult(IntPtr result_ptr)
        {{
            m_result = Marshal.PtrToStringAnsi(result_ptr);
            return 0;
        }}

        private void ClearMessages()
        {{
            m_messages.Clear();
        }}

        private ErrorRecord CreateErrorRecord(string error_id, string error_message, bool include_error_from_message_list)
        {{
            string error = error_message + "\r\n";
            for (int i = 0; include_error_from_message_list && i < m_messages.Count; i++)
            {{
                var message = m_messages[i];
                if(message.Item1 == MessageChannel.Error)
                {{
                    error = message.Item2 + "\r\n";
                }}
            }}

            return new ErrorRecord(
                    new InvalidOperationException(error),
                    error_id,
                    ErrorCategory.InvalidResult,
                    null);
        }}
    }}
}}
"@



<#
    .SYNOPSIS
        Test DSC configuration.

    .Parameter ConfigurationName
        Configuration name.

    .Example
        Test-DscConfiguration -ConfigurationName WindowsTLS
#>


function Test-DscConfiguration
{
    [CmdletBinding()]
    param (
        [parameter(Position=0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $ConfigurationName
    )

    $job_id = [guid]::NewGuid().Guid
    $gcBinPath = Get-GuestConfigBinaryPath
    $dsclibPath = $(Get-DscLibPath) -replace  '[""\\]','\$&'

    if(-not ([System.Management.Automation.PSTypeName]'GuestConfig.DscOperations').Type) {
        $addTypeScript = $ExecuteDscOperationsScript -f $dsclibPath
        Add-Type -TypeDefinition $addTypeScript -ReferencedAssemblies 'System.Management.Automation','System.Console','System.Collections'
    }

    $dscOperation = [GuestConfig.DscOperations]::New()
    $result = $dscOperation.TestDscConfiguration($PSCmdlet, $job_id, $ConfigurationName, $gcBinPath)

    return ConvertFrom-Json $result
}

<#
    .SYNOPSIS
        Get DSC configuration.

    .Parameter ConfigurationName
        Configuration name.

    .Example
        Get-DscConfiguration -ConfigurationName WindowsTLS
#>


function Get-DscConfiguration
{
    [CmdletBinding()]
    param (
        [parameter(Position=0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $ConfigurationName
    )

    $job_id = [guid]::NewGuid().Guid
    $gcBinPath = Get-GuestConfigBinaryPath
    $dsclibPath = $(Get-DscLibPath) -replace  '[""\\]','\$&'

    if(-not ([System.Management.Automation.PSTypeName]'GuestConfig.DscOperations').Type) {
        $addTypeScript = $ExecuteDscOperationsScript -f $dsclibPath
        Add-Type -TypeDefinition $addTypeScript -ReferencedAssemblies 'System.Management.Automation','System.Console','System.Collections'
    }

    $dscOperation = [GuestConfig.DscOperations]::New()
    $result = $dscOperation.GettDscConfiguration($PSCmdlet, $job_id, $ConfigurationName, $gcBinPath)

    return ConvertFrom-Json $result
}

<#
    .SYNOPSIS
        Publish DSC configuration.

    .Parameter ConfigurationName
        Configuration name.

    .Example
        Publish-DscConfiguration -Path C:\metaconfig
#>


function Publish-DscConfiguration
{
    [CmdletBinding()]
    param (
        [parameter(Position=0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $ConfigurationName,

        [parameter(Position=1, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $Path
    )

    $job_id = [guid]::NewGuid().Guid
    $gcBinPath = Get-GuestConfigBinaryPath
    $dsclibPath = $(Get-DscLibPath) -replace  '[""\\]','\$&'

    $testGCbinPath = Test-Path $gcBinPath
    if ($false -eq $testGCbinPath) {throw "Guest Config binaries not found at path $gcBinPath"}

    $testDSClibPath = Test-Path $dsclibPath
    if ($false -eq $testDSClibPath) {throw "Guest Config binaries not found at path $dsclibPath"}
    
    $testPath = Test-Path $Path
    if ($false -eq $testPath) {throw "Guest Config binaries not found at path $testPath"}

    if(-not ([System.Management.Automation.PSTypeName]'GuestConfig.DscOperations').Type) {
        $addTypeScript = $ExecuteDscOperationsScript -f $dsclibPath
        Add-Type -TypeDefinition $addTypeScript -ReferencedAssemblies 'System.Management.Automation','System.Console','System.Collections'
    }

    $dscOperation = [GuestConfig.DscOperations]::New()
    $result = $dscOperation.PublishDscConfiguration($PSCmdlet, $job_id, $ConfigurationName, $gcBinPath, $Path)
}

<#
    .SYNOPSIS
        Set DSC LCM settings.

    .Parameter ConfigurationName
        Configuration name.

    .Example
        Set-DscLocalConfigurationManager -Path C:\metaconfig
#>


function Set-DscLocalConfigurationManager
{
    [CmdletBinding()]
    param (
        [parameter(Position=0, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $ConfigurationName,

        [parameter(Position=1, Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string] $Path
    )

    $job_id = [guid]::NewGuid().Guid
    $gcBinPath = Get-GuestConfigBinaryPath
    $dsclibPath = $(Get-DscLibPath) -replace  '[""\\]','\$&'

    if(-not ([System.Management.Automation.PSTypeName]'GuestConfig.DscOperations').Type) {
        $addTypeScript = $ExecuteDscOperationsScript -f $dsclibPath
        Add-Type -TypeDefinition $addTypeScript -ReferencedAssemblies 'System.Management.Automation','System.Console','System.Collections'
    }

    $dscOperation = [GuestConfig.DscOperations]::New()
    $result = $dscOperation.SetDscLocalConfigurationManager($PSCmdlet, $job_id, $ConfigurationName, $gcBinPath, $Path)
}
# SIG # Begin signature block
# MIIjlAYJKoZIhvcNAQcCoIIjhTCCI4ECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBlAUUwTuSOCsM0
# MeaHIZ/uj77hDf5oyzkCvPWCkvXL3qCCDYUwggYDMIID66ADAgECAhMzAAABiK9S
# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQCSCNryE+Cewy2m4t/a74wZ7C9YTwv1PyC4BvM/kSWPNs8n0RTe+FvYfU+E9uf0
# t7nYlAzHjK+plif2BhD+NgdhIUQ8sVwWO39tjvQRHjP2//vSvIfmmkRoML1Ihnjs
# 9kQiZQzYRDYYRp9xSQYmRwQjk5hl8/U7RgOiQDitVHaU7BT1MI92lfZRuIIDDYBd
# vXtbclYJMVOwqZtv0O9zQCret6R+fRSGaDNfEEpcILL+D7RV3M4uaJE4Ta6KAOdv
# V+MVaJp1YXFTZPKtpjHO6d9pHQPZiG7NdC6QbnRGmsa48uNQrb6AfmLKDI1Lp31W
# MogTaX5tZf+CZT9PSuvjOCLNAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUj9RJL9zNrPcL10RZdMQIXZN7MG8w
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1ODM4NjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# ACnXo8hjp7FeT+H6iQlV3CcGnkSbFvIpKYafgzYCFo3UHY1VHYJVb5jHEO8oG26Q
# qBELmak6MTI+ra3WKMTGhE1sEIlowTcp4IAs8a5wpCh6Vf4Z/bAtIppP3p3gXk2X
# 8UXTc+WxjQYsDkFiSzo/OBa5hkdW1g4EpO43l9mjToBdqEPtIXsZ7Hi1/6y4gK0P
# mMiwG8LMpSn0n/oSHGjrUNBgHJPxgs63Slf58QGBznuXiRaXmfTUDdrvhRocdxIM
# i8nXQwWACMiQzJSRzBP5S2wUq7nMAqjaTbeXhJqD2SFVHdUYlKruvtPSwbnqSRWT
# GI8s4FEXt+TL3w5JnwVZmZkUFoioQDMMjFyaKurdJ6pnzbr1h6QW0R97fWc8xEIz
# LIOiU2rjwWAtlQqFO8KNiykjYGyEf5LyAJKAO+rJd9fsYR+VBauIEQoYmjnUbTXM
# SY2Lf5KMluWlDOGVh8q6XjmBccpaT+8tCfxpaVYPi1ncnwTwaPQvVq8RjWDRB7Pa
# 8ruHgj2HJFi69+hcq7mWx5nTUtzzFa7RSZfE5a1a5AuBmGNRr7f8cNfa01+tiWjV
# Kk1a+gJUBSP0sIxecFbVSXTZ7bqeal45XSDIisZBkWb+83TbXdTGMDSUFKTAdtC+
# r35GfsN8QVy59Hb5ZYzAXczhgRmk7NyE6jD0Ym5TKiW5MIIHejCCBWKgAwIBAgIK
# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD
# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la
# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc
# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D
# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+
# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk
# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6
# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd
# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd
# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3
# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS
# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI
# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD
# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h
# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA
# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn
# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7
# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b
# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/
# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy
# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp
# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi
# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFWUwghVhAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA
# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPd9
# hFCsWSMQr9TAzWa0Li0zeAt8v6YjrIy9QyKUUnS7MEIGCisGAQQBgjcCAQwxNDAy
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEAa9KWoKhhjzlNX5L0zJXAxY5eMEVVYMwVDBHt
# GUunPK6/xHisP4LqbLwiB7vohBWrYEqGAD7jM0DQb2T2BMGm7F4uC7KBRwFBr8YN
# wD8Jzu0k1+O0GXq87/QwWr5gsQRbZJ54pgzePGFoBoMK1Vdn8B4xy4xMfr7sPFdr
# 78zahsuHgrivjR564rrXHim7z9l2m6CWHf7PR1+97zZeMPuFxTWtHgDxivQJejZ8
# 6X0sQS0/BNHVlgdMXnlubFhoRNxH0jgY37sZbV0jAU7fsUgEaXMEfruiXKd9ZhbY
# Pi8AHs2wzcu8+63MQhkKhOCJ7zvfQvlnPj4HbVaRe24CEkyBBaGCEu8wghLrBgor
# BgEEAYI3AwMBMYIS2zCCEtcGCSqGSIb3DQEHAqCCEsgwghLEAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFTBgsqhkiG9w0BCRABBKCCAUIEggE+MIIBOgIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCDXtD8CMaqInQZbQPrYu88e7w2/pBm6gHPQ
# lOzmXVdgsAIGX7vNowfDGBEyMDIwMTIwOTAyMTczNi43WjAEgAIB9KCB1KSB0TCB
# zjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMg
# TWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxl
# cyBUU1MgRVNOOjBBNTYtRTMyOS00RDREMSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBTZXJ2aWNloIIORDCCBPUwggPdoAMCAQICEzMAAAEnL26j75GoGagA
# AAAAAScwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTAwHhcNMTkxMjE5MDExNDU5WhcNMjEwMzE3MDExNDU5WjCBzjELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9w
# ZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjBB
# NTYtRTMyOS00RDREMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2
# aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+AHecRGeTp9LjS+9
# Z4PccKAz0SnjFMhCI+clcT0T4eRlW1Ow96ag7KF80DIX3kT+tS9c5VNRwkUvtdvX
# qNMo9c42wJZjwMKLFIMiKJ3rFrfROIRZVwhlHCIOVzHb0Pjrs5Nq/msDUbpPAARj
# mtCOFQcus6gmB8l9qRmrogeN36yUjT+qXKztAgZqQWTY4HqaH+Wf+dLwbiQ1EroO
# jiDEO2cFIUs1+GxJmVFIwMnAW+tnYUKRqh7F3usqVQ04ABJxjjXUgSpB4jU/B9Gb
# dpZtLwi8B8k8LYCHYuu0/ywqfl9ppTx6l7GN7u9l9xmJ/9xvGBQpK0nOpt29ME1z
# 3ef9nwIDAQABo4IBGzCCARcwHQYDVR0OBBYEFOX0llWAXzkxJFtiU4lduFjTbZXy
# MB8GA1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJ
# oEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01p
# Y1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYB
# BQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGlt
# U3RhUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI
# KwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAArKjXzRVccGpWeNnBDLs2XNdujb
# 5bmp8fFHsA1XlEGRGR0ZqaTBRwM0v4Okc5sU8kdrShN5goTRluXUy+99LxG0YZ2E
# ZgYIl/4E93+AEKzj52Rl2O87M3K5W4M8aWpDl/sdLuK5D9wLIYdwdgnSddV7AXYu
# T4mWtbKQelOUvA9eYKk1H6CJ4i0+L9QwXZFhMbCiNb7IhXA3IxieMUZTERfn8O0m
# NFmaDs8EcysQ03YOA7rAF6Wnim3IfYorYSxZP7yMUK6gq/54lvLRAPnks3l/xKtQ
# 9Gcrzp+HtpU58KCVCh+jkAFkgaIMiuDgmxXiTqnSgFIgU4BypECGIf7WykIwggZx
# MIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg
# Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVa
# Fw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
# YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mU
# a3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZ
# sTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4Yy
# hB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQ
# YrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDa
# TgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQID
# AQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDz
# Q3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQE
# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQ
# W9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNv
# bS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBa
# BggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNV
# HSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggr
# BgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQA
# ZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2d
# o6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GC
# RBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZ
# eUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8y
# Sif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOc
# o6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz3
# 9L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSY
# Ighh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvY
# grRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98is
# TtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8
# l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzV
# s341Hgi62jbb01+P3nSISRKhggLSMIICOwIBATCB/KGB1KSB0TCBzjELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0
# IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO
# OjBBNTYtRTMyOS00RDREMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
# ZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCzlbhObIMcxEzuLPqaAaiOq9cfM6CBgzCB
# gKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUA
# AgUA43oSAjAiGA8yMDIwMTIwODE4NTM1NFoYDzIwMjAxMjA5MTg1MzU0WjB3MD0G
# CisGAQQBhFkKBAExLzAtMAoCBQDjehICAgEAMAoCAQACAiCSAgH/MAcCAQACAhIs
# MAoCBQDje2OCAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAI
# AgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAdd2raGfc485E
# dX4bq0Xuwkf+gn6opNqY6R39vW4RZqWJCmZi6gfMg8/WM0vnjAmplQPM0+JslS0t
# ATCAehAqMECgX4R8O9nJah/N1SjauiASVRzVxQ4bPUVGmti4Rr8BAOLcQlqZa8kL
# 2wVO3ZuhMaPmRE844x1KJejYfUreimAxggMNMIIDCQIBATCBkzB8MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
# VGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAScvbqPvkagZqAAAAAABJzANBglghkgB
# ZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3
# DQEJBDEiBCAuMnjd/POO3xyeuYT+RdjqaGbaUjfsZ1GNtEscxRJLSDCB+gYLKoZI
# hvcNAQkQAi8xgeowgecwgeQwgb0EIBuS6EsShh1qFv8FTJWzM7ZUOLqQHcxJqh//
# 7y7tIz4iMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMA
# AAEnL26j75GoGagAAAAAAScwIgQgtjCWw5jOKaG5gY3ar/xoQb7kRKopqdmMQGBj
# KfFz84QwDQYJKoZIhvcNAQELBQAEggEAwlluEI69hlG4Ypxl9m4RykZ8AmsOZwjF
# MUH8+n4B2+yQxN9b3h2oOO1g25nANg/M2Fb8Z5OmFsbbUQpB5c6M+A4ogn5Xhb5h
# 86U0cO4HSzZ4NL1JSUIkdoHQE3rxlv6EdNMg+piy785cHQx1FOHGRnyHcaJzRs0h
# QLw7JxoJO8hW0aUKFww58xiflF9dOvVepbUe1z9NGVfTSWNzJ0Imy6lTUQytYbBy
# 1TgRn9JIiEDN1L80Ae7jTDkd+BWv8bEg2EsF6GJyIV9qyFHKFTEekh52IiMv9tAp
# TKXxe79RLIkBbAV0CODTMhU1gTCsgfWpP2OyaWEP2hYEZDC4KejO8A==
# SIG # End signature block