AzureRM.Compute.Experiments.psm1

<#
.ExternalHelp AzureRM.Compute.Experiments-help.xml
#>

function New-AzVm {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory=$true, Position=0)][string] $Name = "VM",
        [Parameter(Mandatory=$true)][PSCredential] $Credential,

        [Parameter()][string] $ResourceGroupName = $Name,
        [Parameter()][string] $Location,

        [Parameter()][string] $VirtualNetworkName = $Name,
        [Parameter()][string] $AddressPrefix = "192.168.0.0/16",

        [Parameter()][string] $SubnetName = $Name,
        [Parameter()][string] $SubnetAddressPrefix = "192.168.1.0/24",

        [Parameter()][string] $PublicIpAddressName = $Name,
        [Parameter()][string] $DomainNameLabel = $ResourceGroupName + $Name,
        [Parameter()][string] $AllocationMethod = "Static",

        [Parameter()][string] $SecurityGroupName = $Name,
        [Parameter()][int[]] $OpenPorts = @(3389, 5985),

        [Parameter()][string] $ImageName = "Win2016Datacenter",
        [Parameter()][string] $Size = "Standard_DS1_v2",

        [Parameter()][object] $AzureRmContext,
        [Parameter()][switch] $AsJob
    )

    PROCESS {
        # TODO: make sure it's logged in.
        $context = if ($AzureRmContext) {
            Get-AzureRmContext -AzureRmContext $AzureRmContext
        } else {
            Get-AzureRmContext
        }

        $rgi = [ResourceGroup]::new($ResourceGroupName)

        $vni = [VirtualNetwork]::new($VirtualNetworkName, $rgi, $AddressPrefix)
        $subnet = [Subnet]::new($SubnetName, $vni, $SubnetAddressPrefix)
        $piai = [PublicIpAddress]::new($PublicIpAddressName, $rgi, $DomainNameLabel, $AllocationMethod)
        $sgi = [SecurityGroup]::new($SecurityGroupName, $rgi, $OpenPorts)

        # we don't allow to reuse NetworkInterface so $name is $null.
        $nii = [NetworkInterface]::new(
            $Name,
            $rgi,
            $subnet,
            $piai,
            $sgi)

        # the purpouse of the New-AzVm cmdlet is to create (not get) a VM so $name is $null.
        $vmi = [VirtualMachine]::new(
            $Name,
            $rgi,
            $nii,
            $Credential,
            $ImageName,
            $images,
            $Size)

        # infer a location
        $locationi = [Location]::new()
        if (-not $Location) {
            $vmi.UpdateLocation($locationi, $context)
            if (-not $locationi.Value) {
                $locationi.Value = "eastus"
            }
        } else {
            $locationi.Value = $Location
        }

        $createParams = [CreateParams]::new($locationi.Value, $context)

        if ($PSCmdlet.ShouldProcess($Name, "Creating a virtual machine")) {
            if ($AsJob) {
                $boundParams = $PSCmdlet.MyInvocation.BoundParameters
                $arguments = @{ 'AzureRmContext' = $context }
                foreach ($argName in $boundParams.Keys) {
                    if ($argName -ne 'AsJob' -and $argName -ne 'AzureRmContext') {
                        $arguments[$argName] = $boundParams[$argName]
                    }
                }
                $script = {
                    [hashtable] $params = $args[0]
                    New-AzVm @params
                }

                $jobName = "Creating VM $Name"
                return Start-Job -Name $jobName -ScriptBlock $script -ArgumentList $arguments
            } else {
                $vm = $vmi.GetOrCreate($createParams, [ProgressRange]::new(0.0, 1.0))
                Write-Progress "Done." -Completed
                return [PSAzureVm]::new(
                    $vm,
                    $piai.DomainNameLabel + "." + $locationi.Value + ".cloudapp.azure.com")
            }
        }
    }
}

class PSAzureVm {
    [Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine] $Vm;
    [string] $Name;
    [string] $ResourceGroupName;
    [string] $Fqdn;

    PSAzureVm([Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine] $vm, [string] $fqdn) {
        $this.Vm = $vm
        $this.Name = $vm.Name
        $this.ResourceGroupName = $vm.ResourceGroupName
        $this.Fqdn = $fqdn
    }
}

class Location {
    [int] $Priority;
    [string] $Value;

    Location() {
        $this.Priority = 0
        $this.Value = $null
    }
}

class CreateParams {
    [string] $Location;
    [object] $Context;

    CreateParams(
        [string] $location,
        [object] $context)
    {
        $this.Location = $location
        $this.Context = $context
    }
}

class ProgressRange {
    [double] $Start;
    [double] $Size;

    ProgressRange([double] $start, [double] $size) {
        $this.Start = $start;
        $this.Size = $size;
    }
}

class AzureObject {
    [string] $Name;
    [AzureObject[]] $Children;
    [int] $Priority;
    [int] $ObjectSize;

    [bool] $GetInfoCalled = $false;
    [object] $info = $null;

    AzureObject([string] $name, [AzureObject[]] $children) {
        $this.Name = $name
        $this.Children = $children
        $this.Priority = 0
        $this.ObjectSize = 1
        foreach ($child in $this.Children) {
            if ($this.Priority -lt $child.Priority) {
                $this.Priority = $child.Priority
            }
            $this.ObjectSize += $child.ObjectSize
        }
        $this.Priority++
    }

    [string] GetResourceType() {
        return $null
    }

    [object] GetInfoOrThrow([object] $context) {
        return $null
    }

    [object] Create([CreateParams] $p) {
        return $null
    }

    [object] GetInfo([object] $context) {
        if (!$this.GetInfoCalled) {
            $this.GetInfoCalled = $true
            try {
                $this.Info = $this.GetInfoOrThrow($context)
            } catch {
                # ignore all errors
            }
        }
        return $this.Info;
    }

    [void] UpdateLocation([Location] $location, [object] $context) {
        if ($this.Priority -gt $location.Priority) {
            if ($this.Name) {
                $i = $this.GetInfo($context)
                if ($i) {
                    $location.Value = $i.Location
                    $location.Priority = $this.Priority
                    return;
                }
            }
            foreach ($child in $this.Children) {
                $child.UpdateLocation($location, $context)
            }
        }
    }

    [object] GetOrCreate([CreateParams] $p, [ProgressRange] $progressRange) {
        $i = $this.GetInfo($p.Context)
        if ($i) {
            return $i
        }
        $pSize = $progressRange.Size / $this.ObjectSize
        $offset = $progressRange.Start
        foreach ($child in $this.Children) {
            $pChildSize = $pSize * $child.ObjectSize
            $pc = [ProgressRange]::new($offset, $pChildSize)
            $child.GetOrCreate($p, $pc) | Out-Null
            $offset += $pChildSize
        }
        $message = "Creating '" + $this.Name + "' " + $this.GetResourceType() + "."
        $percent = [convert]::ToInt32($offset * 100)
        Write-Progress $message -PercentComplete $percent -Status "$percent% Complete:"
        Write-Verbose $message
        $this.Info = $this.Create($p)
        return $this.Info
    }
}

class ResourceGroup: AzureObject {
    ResourceGroup([string] $name): base($name, @()) {
    }

    [string] GetResourceType() {
        return "Resource Group"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRmResourceGroup `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        return New-AzureRmResourceGroup `
            -Name $this.Name `
            -Location $p.Location `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop
    }
}

class Resource1: AzureObject {
    [ResourceGroup] $ResourceGroup;

    Resource1(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [AzureObject[]] $children
    ): base($name, $children) {
        $this.ResourceGroup = $resourceGroup
    }

    Resource1(
        [string] $name,
        [ResourceGroup] $resourceGroup
    ): base($name, @($resourceGroup)) {
        $this.ResourceGroup = $resourceGroup
    }

    [string] GetResourceGroupName() {
        return $this.ResourceGroup.Info.ResourceGroupName;
    }
}

class VirtualNetwork: Resource1 {
    [string] $AddressPrefix;

    VirtualNetwork(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [string] $addressPrefix
    ): base($name, $resourceGroup) {
        $this.AddressPrefix = $addressPrefix
    }

    [string] GetResourceType() {
        return "Virtual Network"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRmVirtualNetwork `
            -ResourceGroupName $this.ResourceGroup.Name `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        return New-AzureRmVirtualNetwork `
            -ResourceGroupName $this.GetResourceGroupName() `
            -Location $p.Location `
            -Name $this.Name `
            -AddressPrefix $this.AddressPrefix `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop
    }
}

class PublicIpAddress: Resource1 {
    [string] $DomainNameLabel;
    [string] $AllocationMethod;

    PublicIpAddress(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [string] $domainNameLabel,
        [string] $allocationMethod
    ): base($name, $resourceGroup) {
        $this.DomainNameLabel = $domainNameLabel.ToLower()
        $this.AllocationMethod = $allocationMethod
    }

    [string] GetResourceType() {
        return "Public IP Address"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRMPublicIpAddress `
            -ResourceGroupName $this.ResourceGroup.Name `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        return New-AzureRmPublicIpAddress `
            -ResourceGroupName $this.GetResourceGroupName() `
            -Location $p.Location `
            -Name $this.Name `
            -DomainNameLabel  $this.DomainNameLabel `
            -AllocationMethod $this.AllocationMethod `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop
    }
}

class SecurityGroup: Resource1 {
    [int[]] $OpenPorts;

    SecurityGroup(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [int[]] $OpenPorts
    ): base($name, $resourceGroup) {
        $this.OpenPorts = $OpenPorts
    }

    [string] GetResourceType() {
        return "Security Group"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRmNetworkSecurityGroup `
            -ResourceGroupName $this.ResourceGroup.Name `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        $rules = New-Object `
            "System.Collections.Generic.List[Microsoft.Azure.Commands.Network.Models.PSSecurityRule]"
        $priority = 1000
        foreach ($port in $this.OpenPorts) {
            $name = $this.Name + $port
            $securityRuleConfig = New-AzureRmNetworkSecurityRuleConfig `
                -Name $name `
                -Protocol "Tcp" `
                -Priority $priority `
                -Access "Allow" `
                -Direction "Inbound" `
                -SourcePortRange "*" `
                -SourceAddressPrefix "*" `
                -DestinationPortRange $port `
                -DestinationAddressPrefix "*" `
                -ErrorAction Stop
            $rules.Add($securityRuleConfig)
            ++$priority
        }
        return New-AzureRmNetworkSecurityGroup `
            -ResourceGroupName $this.GetResourceGroupName() `
            -Location $p.Location `
            -Name $this.Name `
            -SecurityRules $rules `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop
    }
}

class Subnet: AzureObject {
    [VirtualNetwork] $VirtualNetwork;
    [string] $SubnetAddressPrefix;

    Subnet([string] $name, [VirtualNetwork] $virtualNetwork, [string] $subnetAddressPrefix):
        base($name, @($virtualNetwork)) {
        $this.VirtualNetwork = $virtualNetwork
        $this.SubnetAddressPrefix = $subnetAddressPrefix
    }

    [string] GetResourceType() {
        return "Subnet"
    }

    [object] GetInfoFromVirtualNetworkInfo([object] $virtualNetworkInfo) {
        return $virtualNetworkInfo `
            | Get-AzureRmVirtualNetworkSubnetConfig -Name $this.Name -ErrorAction Stop
    }

    [object] GetInfoOrThrow([object] $context) {
        $virtualNetworkInfo = $this.VirtualNetwork.GetInfo($context)
        if ($virtualNetworkInfo) {
            return $this.GetInfoFromVirtualNetworkInfo($virtualNetworkInfo)
        }
        return $null
    }

    [object] Create([CreateParams] $p) {
        $virtualNetworkInfo = $this.VirtualNetwork.Info
        try {
            return $this.GetInfoFromVirtualNetworkInfo($virtualNetworkInfo)
        } catch {
        }
        $virtualNetworkInfo = Add-AzureRmVirtualNetworkSubnetConfig `
            -VirtualNetwork $virtualNetworkInfo `
            -Name $this.Name `
            -AddressPrefix $this.SubnetAddressPrefix
        $virtualNetworkInfo = Set-AzureRmVirtualNetwork `
            -VirtualNetwork $virtualNetworkInfo `
            -AzureRmContext $p.Context `
            -ErrorAction Stop
        return $this.GetInfoFromVirtualNetworkInfo($virtualNetworkInfo)
    }
}

class NetworkInterface: Resource1 {
    [Subnet] $Subnet;
    [PublicIpAddress] $PublicIpAddress;
    [SecurityGroup] $SecurityGroup;

    NetworkInterface(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [Subnet] $subnet,
        [PublicIpAddress] $publicIpAddress,
        [SecurityGroup] $securityGroup
    ): base($name, $resourceGroup, @($subnet, $publicIpAddress, $securityGroup)) {
        $this.Subnet = $subnet
        $this.PublicIpAddress = $publicIpAddress
        $this.SecurityGroup = $securityGroup
    }

    [string] GetResourceType() {
        return "Network Interface"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRMNetworkInterface `
            -ResourceGroupName $this.ResourceGroup.Name `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        $publicIpAddressInfo = $this.PublicIpAddress.Info
        $subnetInfo = $this.Subnet.Info
        $securityGroupInfo = $this.SecurityGroup.Info
        return New-AzureRmNetworkInterface `
            -ResourceGroupName $this.GetResourceGroupName() `
            -Location $p.Location `
            -Name $this.Name `
            -PublicIpAddressId $publicIpAddressInfo.Id `
            -SubnetId $subnetInfo.Id `
            -NetworkSecurityGroupId $securityGroupInfo.Id `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop
    }
}

class VirtualMachine: Resource1 {
    [NetworkInterface] $NetworkInterface;
    [pscredential] $Credential;
    [string] $ImageName;
    [object] $Images;
    [string] $Size;

    VirtualMachine(
        [string] $name,
        [ResourceGroup] $resourceGroup,
        [NetworkInterface] $networkInterface,
        [PSCredential] $credential,
        [string] $imageName,
        [object] $images,
        [string] $size):
        base($name, $resourceGroup, @($networkInterface)) {

        $this.Credential = $credential
        $this.ImageName = $imageName
        $this.NetworkInterface = $networkInterface
        $this.Images = $images
        $this.Size = $size
    }

    [string] GetResourceType() {
        return "Virtual Machine"
    }

    [object] GetInfoOrThrow([object] $context) {
        return Get-AzureRmVM `
            -ResourceGroupName $this.ResourceGroup.Name `
            -Name $this.Name `
            -AzureRmContext $context `
            -ErrorAction Stop
    }

    [object] Create([CreateParams] $p) {
        $networkInterfaceInstance = $this.NetworkInterface.Info

        $vmImage = $this.Images | Where-Object { $_.Name -eq $this.ImageName } | Select-Object -First 1
        if (-not $vmImage) {
            throw "Unknown image: " + $this.ImageName
        }

        $vmConfig = New-AzureRmVMConfig -VMName $this.Name -VMSize $this.Size -ErrorAction Stop
        $vmComputerName = $this.Name
        switch ($vmImage.Type) {
            "Windows" {
                $vmConfig = $vmConfig | Set-AzureRmVMOperatingSystem `
                    -Windows `
                    -ComputerName $vmComputerName `
                    -Credential $this.Credential `
                    -ErrorAction Stop
            }
            "Linux" {
                $vmConfig = $vmConfig | Set-AzureRmVMOperatingSystem `
                    -Linux `
                    -ComputerName $vmComputerName `
                    -Credential $this.Credential `
                    -ErrorAction Stop
            }
        }

        $vmImageImage = $vmImage.Image
        $vmConfig = $vmConfig `
            | Set-AzureRmVMSourceImage `
                -PublisherName $vmImageImage.publisher `
                -Offer $vmImageImage.offer `
                -Skus $vmImageImage.sku `
                -Version $vmImageImage.version `
                -ErrorAction Stop `
            | Add-AzureRmVMNetworkInterface `
                -Id $networkInterfaceInstance.Id `
                -ErrorAction Stop

        $rgName = $this.GetResourceGroupName()
        New-AzureRmVm `
            -ResourceGroupName $rgName `
            -Location $p.Location `
            -VM $vmConfig `
            -AzureRmContext $p.Context `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop

        return Get-AzureRmVM -ResourceGroupName $rgName -Name $this.Name -AzureRmContext $p.Context
    }
}

function New-PsObject {
    param([hashtable] $property)

    New-Object psobject -Property $property
}

$staticImages = New-PsObject @{
    Linux = New-PsObject @{
        CentOS = New-PsObject @{
            publisher = "OpenLogic";
            offer = "CentOS";
            sku = "7.3";
            version = "latest";
        };
        CoreOS = New-PsObject @{
            publisher = "CoreOS";
            offer = "CoreOS";
            sku = "Stable";
            version = "latest";
        };
        Debian = New-PsObject @{
            publisher = "credativ";
            offer = "Debian";
            sku = "8";
            version = "latest";
        };
        "openSUSE-Leap" = New-PsObject @{
            publisher = "SUSE";
            offer = "openSUSE-Leap";
            sku = "42.2";
            version = "latest";
        };
        RHEL = New-PsObject @{
            publisher = "RedHat";
            offer = "RHEL";
            sku = "7.3";
            version = "latest";
        };
        SLES = New-PsObject @{
            publisher = "SUSE";
            offer = "SLES";
            sku = "12-SP2";
            version = "latest";
        };
        UbuntuLTS = New-PsObject @{
            publisher = "Canonical";
            offer = "UbuntuServer";
            sku = "16.04-LTS";
            version = "latest";
        };
    };
    Windows = New-PsObject @{
        Win2016Datacenter = New-PsObject @{
            publisher = "MicrosoftWindowsServer";
            offer = "WindowsServer";
            sku = "2016-Datacenter";
            version = "latest";
        };
        Win2012R2Datacenter = New-PsObject @{
            publisher = "MicrosoftWindowsServer";
            offer = "WindowsServer";
            sku = "2012-R2-Datacenter";
            version = "latest";
        };
        Win2012Datacenter = New-PsObject @{
            publisher = "MicrosoftWindowsServer";
            offer = "WindowsServer";
            sku = "2012-Datacenter";
            version = "latest";
        };
        Win2008R2SP1 = New-PsObject @{
            publisher = "MicrosoftWindowsServer";
            offer = "WindowsServer";
            sku = "2008-R2-SP1";
            version = "latest";
        };
    };
}

# Images
# an array of @{ Type = ...; Name = ...; Image = ... }
# $images = $jsonImages.outputs.aliases.value.psobject.Properties | ForEach-Object {
$images = $staticImages.psobject.Properties | ForEach-Object {
    # e.g. "Linux"
    $type = $_.Name
    $_.Value.psobject.Properties | ForEach-Object {
        New-Object -TypeName psobject -Property @{
            # e.g. "Linux"
            Type = $type;
            # e.g. "CentOs"
            Name = $_.Name;
            # e.g. @{ publisher = "OpenLogic"; offer = "CentOS"; sku = "7.3"; version = "latest" }
            Image = $_.Value
        }
    }
}

Export-ModuleMember -Function New-AzVm

# SIG # Begin signature block
# MIIkBgYJKoZIhvcNAQcCoIIj9zCCI/MCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDZ94lM46wbzEcp
# bHgnkeucij5IDhMCVKZEiFv17ZaUcKCCDYIwggYAMIID6KADAgECAhMzAAAAww6b
# p9iy3PcsAAAAAADDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTcwODExMjAyMDI0WhcNMTgwODExMjAyMDI0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC7V9c40bEGf0ktqW2zY596urY6IVu0mK6N1KSBoMV1xSzvgkAqt4FTd/NjAQq8
# zjeEA0BDV4JLzu0ftv2AbcnCkV0Fx9xWWQDhDOtX3v3xuJAnv3VK/HWycli2xUib
# M2IF0ZWUpb85Iq2NEk1GYtoyGc6qIlxWSLFvRclndmJdMIijLyjFH1Aq2YbbGhEl
# gcL09Wcu53kd9eIcdfROzMf8578LgEcp/8/NabEMC2DrZ+aEG5tN/W1HOsfZwWFh
# 8pUSoQ0HrmMh2PSZHP94VYHupXnoIIJfCtq1UxlUAVcNh5GNwnzxVIaA4WLbgnM+
# Jl7wQBLSOdUmAw2FiDFfCguLAgMBAAGjggF/MIIBezAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUpxNdHyGJVegD7p4XNuryVIg1Ga8w
# UQYDVR0RBEowSKRGMEQxDDAKBgNVBAsTA0FPQzE0MDIGA1UEBRMrMjMwMDEyK2M4
# MDRiNWVhLTQ5YjQtNDIzOC04MzYyLWQ4NTFmYTIyNTRmYzAfBgNVHSMEGDAWgBRI
# bmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEt
# MDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAE2X
# TzR+8XCTnOPVGkucEX5rJsSlJPTfRNQkurNqCImZmssx53Cb/xQdsAc5f+QwOxMi
# 3g7IlWe7bn74fJWkkII3k6aD00kCwaytWe+Rt6dmAA6iTCXU3OddBwLKKDRlOzmD
# rZUqjsqg6Ag6HP4+e0BJlE2OVCUK5bHHCu5xN8abXjb1p0JE+7yHsA3ANdkmh1//
# Z+8odPeKMAQRimfMSzVgaiHnw40Hg16bq51xHykmCRHU9YLT0jYHKa7okm2QfwDJ
# qFvu0ARl+6EOV1PM8piJ858Vk8gGxGNSYQJPV0gc9ft1Esq1+fTCaV+7oZ0NaYMn
# 64M+HWsxw+4O8cSEQ4fuMZwGADJ8tyCKuQgj6lawGNSyvRXsN+1k02sVAiPGijOH
# OtGbtsCWWSygAVOEAV/ye8F6sOzU2FL2X3WBRFkWOCdTu1DzXnHf99dR3DHVGmM1
# Kpd+n2Y3X89VM++yyrwsI6pEHu77Z0i06ELDD4pRWKJGAmEmWhm/XJTpqEBw51sw
# THyA1FBnoqXuDus9tfHleR7h9VgZb7uJbXjiIFgl/+RIs+av8bJABBdGUNQMbJEU
# fe7K4vYm3hs7BGdRLg+kF/dC/z+RiTH4p7yz5TpS3Cozf0pkkWXYZRG222q3tGxS
# /L+LcRbELM5zmqDpXQjBRUWlKYbsATFtXnTGVjELMIIHejCCBWKgAwIBAgIKYQ6Q
# 0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh
# dGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5
# WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQD
# Ex9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4
# BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe
# 0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato
# 88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v
# ++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDst
# rjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN
# 91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4ji
# JV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmh
# D+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbi
# wZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8Hh
# hUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaI
# jAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTl
# UAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNV
# HQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQF
# TuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29m
# dC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf
# MjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5t
# aWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf
# MjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcC
# ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnlj
# cHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5
# AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oal
# mOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0ep
# o/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1
# HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtY
# SWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInW
# H8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZ
# iWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMd
# YzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7f
# QccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKf
# enoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOpp
# O6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZO
# SEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFdowghXWAgEBMIGVMH4xCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
# c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAADDDpun2LLc9ywAAAAAAMMw
# DQYJYIZIAWUDBAIBBQCggcwwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
# KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIONEB3Db
# +d9Jnn0J0J+QcSy9HoUWlzx84rVtNnv8ansqMGAGCisGAQQBgjcCAQwxUjBQoDaA
# NABNAGkAYwByAG8AcwBvAGYAdAAgAEEAegB1AHIAZQAgAFAAbwB3AGUAcgBTAGgA
# ZQBsAGyhFoAUaHR0cDovL0NvZGVTaWduSW5mbyAwDQYJKoZIhvcNAQEBBQAEggEA
# NHkygghQY1jKG0PVl+6H03hr25lV7T86KsWMcUPukCh+0EGBsUs/MVrP/PJr9+VP
# /E6Cf4v8qsdOUmcaSt4K7TaYIUSYpvGNlDoJyV3SQ5R+7vY5Q77HZw/+SKhEJxPE
# /xz7jNmXBU+1xcNierRmuFbEkuB7hy24Ur797KYhDDgvumCEHwJReyK0s/2dyzCo
# kmwAXphIwqF3YTcMmK7RaXastUEJFBw73JwPORukqqpiDDDiCcA4DxxyKEzmQPZs
# 5pK3CeXVxZ0r18xVkPPsNr5e4Tnx+vpMH3+2vspWduBOccGQDX7pmyhiLjgqUfx/
# nz7p0CVEFrWCOfdrVPmeiaGCE0YwghNCBgorBgEEAYI3AwMBMYITMjCCEy4GCSqG
# SIb3DQEHAqCCEx8wghMbAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggE8BgsqhkiG9w0B
# CRABBKCCASsEggEnMIIBIwIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUA
# BCAKxsOdmgQC9xBtFhq66AtO481uQ8oSL0tRFWZd8pHm5QIGWckEQW32GBMyMDE3
# MDkyNTE5MzgyOS43NjNaMAcCAQGAAgH0oIG4pIG1MIGyMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMQwwCgYDVQQLEwNBT0MxJzAlBgNVBAsTHm5D
# aXBoZXIgRFNFIEVTTjo3QUI1LTJERjItREEzRjElMCMGA1UEAxMcTWljcm9zb2Z0
# IFRpbWUtU3RhbXAgU2VydmljZaCCDsowggZxMIIEWaADAgECAgphCYEqAAAAAAAC
# MA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
# MIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vh
# wna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs
# 1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WET
# bijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wG
# Pmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf0
# 3GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGC
# NxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/
# MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJ
# oEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01p
# Y1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYB
# BQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9v
# Q2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQB
# gjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BL
# SS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBh
# AGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG
# 9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkw
# s8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/
# XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO
# 9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHO
# mWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU
# 9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6
# YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdl
# R3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rI
# DVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkq
# mqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN
# +w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb01+P3nSISRIwggTZ
# MIIDwaADAgECAhMzAAAAq15Ane5G3yxsAAAAAACrMA0GCSqGSIb3DQEBCwUAMHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTE2MDkwNzE3NTY1NFoXDTE4
# MDkwNzE3NTY1NFowgbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xDDAKBgNVBAsTA0FPQzEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjdBQjUt
# MkRGMi1EQTNGMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs+Z+UJigRgmwZgEmijTT
# Kcl9mDWaDCzdM8oDzw4C1wvvu+HILkmk09DZ3HPTu0WFnF3lAfX8K6Zim+GAAqfz
# NyhFSzXeuLpu+4aQ7eGrEPI48HfCW89AE+45ShvSKnoe/IsB+Km8mo95A8PjcNGs
# APOmwMsh3XTU1IeEKIGtGllSYt7s/czFA4lMTQezoNQennsBwjrNY2kJkIgTk8Mt
# lKEsBCm4N9VKtTGK5L5ukTPbfO7MMnxcwS3huLDWIokhKiR54uSjzy4Z1lXJSBEk
# pKjJ9UjIUsIxkpD6ZjYA+aEwGmgPrWlkS1rx62mfc4Z6tmAflJFejiC91N8OKpDI
# SwIDAQABo4IBGzCCARcwHQYDVR0OBBYEFA3HR9AcYMvpwGuUzF8GDmK42GqnMB8G
# A1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeG
# RWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Rp
# bVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUH
# MAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3Rh
# UENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYB
# BQUHAwgwDQYJKoZIhvcNAQELBQADggEBAD+f/rouYfFyKq2qFWaVoARLfbPCRt3Q
# 61tAPPSMdQWtoYFvJHsNLtKjibrwNiv5yMV3Dnq4fN5U4v0PJl88DHYt+hjRohCo
# iF5LKlmVyF93f/5EJLgCmYSRlK8Cx6YqhoSxi/iRJMfQbqM2v/v4uAeabz5p7bbx
# m2FnVK026Nvy2uVipjvIbcxDmiYi80SM6y1HJnXTwuab1oqdFU+T6IAgzg4tlQNT
# 80DgGtxpXEwh10oTKC9F1YL9pMHfITvJ6z84pT8y+s0GS7gfvJsas5Gxk13i/3mh
# FtG4Nfbhkcr3cez9/orD4GU1WMukXg+W5qcir2jzPs/epI2q2O4SpOKhggN0MIIC
# XAIBATCB4qGBuKSBtTCBsjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046N0FC
# NS0yREYyLURBM0YxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZp
# Y2WiJQoBATAJBgUrDgMCGgUAAxUAyey7SC012ZS+to73JqkxboqHjjKggcEwgb6k
# gbswgbgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDDAKBgNV
# BAsTA0FPQzEnMCUGA1UECxMebkNpcGhlciBOVFMgRVNOOjI2NjUtNEMzRi1DNURF
# MSswKQYDVQQDEyJNaWNyb3NvZnQgVGltZSBTb3VyY2UgTWFzdGVyIENsb2NrMA0G
# CSqGSIb3DQEBBQUAAgUA3XPS0zAiGA8yMDE3MDkyNTE5MDkwN1oYDzIwMTcwOTI2
# MTkwOTA3WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDdc9LTAgEAMAcCAQACAgJW
# MAcCAQACAho/MAoCBQDddSRTAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQB
# hFkKAwGgCjAIAgEAAgMW42ChCjAIAgEAAgMHoSAwDQYJKoZIhvcNAQEFBQADggEB
# AEnnuy6WUPgGDoX3J2Rr8NEbT1h58uPKBtZt8vhMRfc9nl0rAb6sgBLod6cxc9Iw
# x0+HmRoivWNKZg+wB6AF5f1PeqcXM8I6r4YxixXKdhx784O1CaC664AWGv4fqtL1
# 9t/gr84VTvi+AGoIN3WWuQSGnxzVaiugH+LGC9ExHcftExtBKeOiNdT/zD0e41xa
# 3ieyi4njVtHUGLmogr+JK4HZQe58koAG7aBSHprOlLx5kkmb/8JLH+c8lXxeZipy
# j6wnTWOIKM1Cjnen0VAAO2xQPGa7wXHHK/JnWa77+5xuGrRR8TxrEYXY17P3RhFb
# ILh/oB1Ugme13g9CbgdhXj0xggL1MIIC8QIBATCBkzB8MQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T
# dGFtcCBQQ0EgMjAxMAITMwAAAKteQJ3uRt8sbAAAAAAAqzANBglghkgBZQMEAgEF
# AKCCATIwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEi
# BCAe10SqZpZkT5sQlbc/vHLLqDnoj+jqH8knxxFSRydNxzCB4gYLKoZIhvcNAQkQ
# AgwxgdIwgc8wgcwwgbEEFMnsu0gtNdmUvraO9yapMW6Kh44yMIGYMIGApH4wfDEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWlj
# cm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAACrXkCd7kbfLGwAAAAAAKsw
# FgQU9ntu9Jt3EBM5GEtNkG0/+KigSAkwDQYJKoZIhvcNAQELBQAEggEAfncOFB0B
# Sqs6ygWT8uqXVsgzfKcMIFG5vENzNc70kZ0uV1aonwRhIH7G++P0zpEDgnJi3kio
# IXi4EACXh5P8g4nXO1oIZSqnQ2UqdGW67dvPve++gpyn8sDKyQZwytrCW6DA+rWX
# 2SEIOriHpZ2LOSKBMXdTAQg+7xdLy49VZg89/i7hqvzf3TpXIIXaRmUlzk1swMcV
# ymXSTP2YTM+ZeKaRC+abbPbHsTnnlhLoFArLs51EZq4tsG04JMXD2oSLWH2mNdGU
# 2FMkYzHJSX7yzxKZ14IPL1xeePR43qouP1dTquBzm1FXQFQF2TV1sXazA8zY8TbW
# 7U+7PGF3KptuUw==
# SIG # End signature block