AppHandling/Copy-AlSourceFiles.ps1

<#
 .Synopsis
  Copy AL Source Files
 .Description
  This function will copy all .al and .xlf files from Path to Destination.
  Information about each file will be sent to the alFileStructure function to determine the relative location of the file.
 .Parameter Path
  Source Path from where you want to copy all AL source files
 .Parameter Destination
  Destination Path
 .Parameter Recurse
  Copy source in subfolders
 .Parameter alFileStructure
  Specify a function, which will determine the location of the individual al source files
 .Example
  Copy-AlSourceFiles -Path "$sourceFolder\*" -Destination $destinationFolder -Recurse -alFileStructure $TypeFolders
 
#>

function Copy-AlSourceFiles {
    Param (
        [string] $Path,
        [string] $Destination,
        [switch] $Recurse,
        [ScriptBlock] $alFileStructure
    )

$telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @()
try {

    Write-Host "Copying Al Source Files from $Path to $Destination"

    if ($alFileStructure) {
        $types = @('enum', 'page', 'table', 'codeunit', 'report', 'query', 'xmlport', 'profile', 'dotnet', 'enumextension', 'pageextension', 'tableextension', 'interface', 'entitlement', 'permissionset', 'permissionsetextension', 'pagecustomization', 'reportextension', 'profileextension')
        $noidtypes = @('profile','profileextension','interface','entitlement','pagecustomization')

        $extensions = @(".al",".xlf",".lcl")

        $files = Get-ChildItem -Path $Path -Recurse:$Recurse
        $files | Where-Object { ($extensions.Contains($_.Extension.ToLowerInvariant())) -and !($_.Attributes.HasFlag([System.IO.FileAttributes]::Directory)) } | ForEach-Object {
    
            $filename = $_.Name
            $directoryname = $_.DirectoryName
            $content = [System.IO.File]::ReadAllLines($_.FullName)

            try {
                if ($_.Extension -ne ".al") {
                    $type = $_.Extension
                    $id = ''
                    $name = $_.BaseName
                    $found = $true
                } 
                else {
                    $found = $false
                    foreach($Line in $content) {
                        if (-not $found) {
                            $line = $Line.Trim()
                            if ($line -notlike '//*') {
                                $idx = $line.IndexOf(' ')
                                if ($idx -lt 0) {
                                    $type = $line
                                }
                                else {
                                    $type = $line.SubString(0,$idx).ToLowerInvariant()
                                }
                                if ($types.Contains($type)) {
                                    $found = $true
                                    break
                                }
                            }
                        } 
                    }
    
                    if ($type -eq "dotnet") {
                        $id = ''
                        $name = $_.BaseName
                    }
                    else {
                        $line = $line.SubString($type.Length).TrimStart()
                        if ($noidTypes.Contains($type)) {
                            $id = ''
                        }
                        else {
                            $id = $line.SubString(0,$line.IndexOf(' '))
                            $line = $line.SubString($id.Length).Trim()
                        }
                        if ($line.StartsWith('"')) {
                            $nameendidx = $line.IndexOf('"',1)
                            $name = $line.SubString(1,$nameendidx-1)
                        }
                        else {
                            $name = $line
                        }
                    }
                }

                $newFilename = ""
                if ($found) {
                    if ($alFileStructure.Ast.ParamBlock.Parameters.Count -eq 3) {
                        $newFilename = "$($alFileStructure.Invoke($type, $id, $name))"
                    }
                    else {
                        $newFilename = "$($alFileStructure.Invoke($type, $id, $name, [ref] $content))"
                    }
                }
                if ($newFilename) {
                    $newFilename = $newFilename -replace '[~#%&*{}|:<>?/"]', ''
 
                    $destFilename = Join-Path $Destination $newFilename
                    $destPath = [System.IO.Path]::GetDirectoryName($destFilename)
                    $destName = [System.IO.Path]::GetFileName($destFilename)
                    
                    if (-not (Test-Path $destPath)) {
                        New-Item $destPath -ItemType Directory | Out-Null
                    }

                    if (Test-Path -Path $destFilename) {
                        Write-Warning "$destFilename already exists, adding sequence number"
                        $seq = 1
                        $dotIdx = $destName.IndexOf('.')
                        if ($dotIdx -lt 0) {
                            throw "Cannot add sequence number to $destName"
                        }
                        while (Test-Path -Path $destFilename) {
                            $seq++
                            $destFilename = Join-Path $destPath $destName.Insert($dotIdx,"$seq")
                        }
                    }

                    if ($type -eq "report") {
                        0..($content.Count-1) | % {
                            $line = $content[$_]
                            if ($line.Trim() -like "RDLCLayout = '*';" -or $line.Trim() -like "WordLayout = '*';" -or $line.Trim() -like "LayoutFile = '*';") {
                                $startIdx = $line.IndexOf("'")+1
                                $endIdx = $line.LastIndexOf("'")
                                $layoutFilename = $line.SubString($startIdx, $endIdx-$startIdx)
                                $layoutFilename = $layoutFilename.SubString($layoutFilename.LastIndexOfAny(@('\','/'))+1)
                                $layoutFile = $Files | Where-Object { ($_.name -eq $layoutFilename) -and ($_.DirectoryName -eq $DirectoryName)} 
                                if (!($layoutFile)){
                                    $layoutFile = $Files | Where-Object { $_.name -eq $layoutFilename }
                                }
                                if ($layoutFile) {
                                    $layoutcontent = [System.IO.File]::ReadAllBytes($layoutFile.FullName)
        
                                    if ($alFileStructure.Ast.ParamBlock.Parameters.Count -eq 3) {
                                        $layoutNewFilename = "$($alFileStructure.Invoke($layoutFile.Extension, $id, $name))"
                                    }
                                    else {
                                        $layoutNewFilename = "$($alFileStructure.Invoke($layoutFile.Extension, $id, $name, [ref] $content))"
                                    }

                                    if ($layoutNewFilename) {
                                        if ($layoutNewFilename.StartsWith('*\')) {
                                            $layoutDestFilename = Join-Path $DestPath $layoutNewFilename.Substring(2)
                                            $layoutDestPath = [System.IO.Path]::GetDirectoryName($layoutDestFilename)
                                            $layoutDestName = [System.IO.Path]::GetFileName($layoutDestFilename)
                                            if ($layoutDestName.StartsWith('*.')) {
                                                $layoutDestName = [System.IO.Path]::GetFileNameWithoutExtension($destFileName) + $layoutDestName.Substring(1)
                                                $layoutDestFileName = Join-Path $layoutDestPath $layoutDestName
                                            }
                                        }
                                        elseif ($layoutNewFilename.StartsWith('*.')) {
                                            $layoutDestPath = $destPath
                                            $layoutDestName = [System.IO.Path]::GetFileNameWithoutExtension($destFileName) + $layoutNewFilename.Substring(1)
                                            $layoutDestFilename = Join-Path $layoutDestPath $layoutDestName
                                        }
                                        else {
                                            $layoutNewFilename = $layoutNewFilename -replace '[~#%&*{}|:<>?/"]', ''
    
                                            $layoutDestFilename = Join-Path $Destination $layoutNewFilename
                                            $layoutDestPath = [System.IO.Path]::GetDirectoryName($layoutDestFilename)
                                            $layoutDestName = [System.IO.Path]::GetFileName($layoutDestFilename)
                                        }
    
                                        if (-not (Test-Path $layoutDestPath)) {
                                            New-Item $layoutDestPath -ItemType Directory | Out-Null
                                        }
    
                                        if (Test-Path -Path $layoutDestFilename) {
                                            Write-Warning "$layoutDestFilename already exists, adding sequence number"
                                            $seq = 1
                                            $dotIdx = $layoutDestName.IndexOf('.')
                                            if ($dotIdx -lt 0) {
                                                throw "Cannot add sequence number to $layoutDestName"
                                            }
                                            while (Test-Path -Path $layoutDestFilename) {
                                                $seq++
                                                $layoutDestFilename = Join-Path $layoutDestPath $layoutDestName.Insert($dotIdx,"$seq")
                                            }
                                        }

                                        [System.IO.File]::WriteAllBytes($layoutDestFilename, $layoutcontent)

                                        $filename = (get-item $layoutDestFilename).FullName
                                        if ($filename.StartsWith($Destination,"InvariantCultureIgnoreCase")) {
                                            $layoutDestFilename = $filename
                                        }
            
                                        $content[$_] = $line.SubString(0,$startIdx) + $layoutDestFilename.Substring($destination.Length+1).Replace('\','/') + $line.SubString($endIdx)
                                    }
                                }
                                else {
                                    Write-Warning "Unable to find $layoutFilename"
                                }
                            }
                        }
                    }
        
                    [System.IO.File]::WriteAllLines($destFileName, $content)
                }
            }
            catch {
                Write-Warning "Unexpected error while handling $filename"
                throw
            }
        }
    }
    else {
        Copy-Item -Path $Path -Destination $Destination -Recurse:$Recurse -Force | Out-Null
    }
}
catch {
    TrackException -telemetryScope $telemetryScope -errorRecord $_
    throw
}
finally {
    TrackTrace -telemetryScope $telemetryScope
}
}
Export-ModuleMember -Function Copy-AlSourceFiles

# SIG # Begin signature block
# MIIoDAYJKoZIhvcNAQcCoIIn/TCCJ/kCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD6onw4XaH+e8gG
# hzozyTPfWgTDNZ42RqIKascC5R/jWKCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z
# 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy
# 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi
# 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ
# hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ
# 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe
# UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk
# tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj
# Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS
# DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns
# WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO
# lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71
# 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9
# nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk
# C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm
# M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn
# lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo
# STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGewwghnoAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB
# BQCggZAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwLwYJKoZIhvcNAQkEMSIE
# IP1shGTVUeWf/AElFE48DTOBxOBPlpYzSqwHspU0L2OQMEIGCisGAQQBgjcCAQwx
# NDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20wDQYJKoZIhvcNAQEBBQAEggEABksVpPMurK/0vD4RhtsRaaW/b2LJedd9
# R10+PEjUnnKq0m4Lnp+8hlr1++PdMC6ZDHRjRCcBtivBamiehshxfaxMavBW8x76
# GCXEPoSfzRusc4kLjHM5+Yhqk9+LveHDKS1OxzDqdJ8I0EQhgCBgrDWO4lmsE8d7
# e4KSLX3LdZCSii5LWtPELKsqCdupaS94EIaFKHsnif01DQAzkJpsMMoBsiPr/P7R
# AwfpYpGTthtTU1euTV2+zcRM0OwNyEJ4mXhPIbVaaJdztsTyhCWtbpsKmFZl1phZ
# Hr1iR4Hxsrv7kClr/9XLtQeuVOe1wU3a2fo8XC4C3k1XAuEh2F6Rf6GCF5QwgheQ
# BgorBgEEAYI3AwMBMYIXgDCCF3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJ
# YIZIAWUDBAIBBQAwggFSBgsqhkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYB
# BAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCB62vHhGc15ConSRATg2OJ6ofoPM/Hd
# 8nxS39izOQXKjwIGaSc7IhbUGBMyMDI1MTIwODEyNDcyMy4wMjJaMASAAgH0oIHR
# pIHOMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYD
# VQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hp
# ZWxkIFRTUyBFU046MzcwMy0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFNlcnZpY2WgghHqMIIHIDCCBQigAwIBAgITMwAAAgpHshTZ7rKz
# DwABAAACCjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg
# MjAxMDAeFw0yNTAxMzAxOTQyNTdaFw0yNjA0MjIxOTQyNTdaMIHLMQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQg
# QW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046Mzcw
# My0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZp
# Y2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCy7NzwEpb7BpwAk9LJ
# 00Xq30TcTjcwNZ80TxAtAbhSaJ2kwnJA1Au/Do9/fEBjAHv6Mmtt3fmPDeIJnQ7V
# BeIq8RcfjcjrbPIg3wA5v5MQflPNSBNOvcXRP+fZnAy0ELDzfnJHnCkZNsQUZ7GF
# 7LxULTKOYY2YJw4TrmcHohkY6DjCZyxhqmGQwwdbjoPWRbYu/ozFem/yfJPyjVBq
# l1068bcVh58A8c5CD6TWN/L3u+Ny+7O8+Dver6qBT44Ey7pfPZMZ1Hi7yvCLv5LG
# zSB6o2OD5GIZy7z4kh8UYHdzjn9Wx+QZ2233SJQKtZhpI7uHf3oMTg0zanQfz7mg
# udefmGBrQEg1ox3n+3Tizh0D9zVmNQP9sFjsPQtNGZ9ID9H8A+kFInx4mrSxA2Sy
# GMOQcxlGM30ktIKM3iqCuFEU9CHVMpN94/1fl4T6PonJ+/oWJqFlatYuMKv2Z8ui
# prnFcAxCpOsDIVBO9K1vHeAMiQQUlcE9CD536I1YLnmO2qHagPPmXhdOGrHUnCUt
# op21elukHh75q/5zH+OnNekp5udpjQNZCviYAZdHsLnkU0NfUAr6r1UqDcSq1yf5
# RiwimB8SjsdmHll4gPjmqVi0/rmnM1oAEQm3PyWcTQQibYLiuKN7Y4io5bJTVwm+
# vRRbpJ5UL/D33C//7qnHbeoWBQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFAKvF0EE
# j4AyPfY8W/qrsAvftZwkMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1Gely
# MF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNy
# bDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBD
# QSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYB
# BQUHAwgwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCwk3PW0Cyj
# OaqXCMOusTde7ep2CwP/xV1J3o9KAiKSdq8a2UR5RCHYhnJseemweMUH2kNefpnA
# h2Bn8H2opDztDJkj8OYRd/KQysE12NwaY3KOwAW8Rg8OdXv5fUZIsOWgprkCQM0V
# oFHdXYExkJN3EzBbUCUw3yb4gAFPK56T+6cPpI8MJLJCQXHNMgti2QZhX9KkfRAf
# fFYMFcpsbI+oziC5Brrk3361cJFHhgEJR0J42nqZTGSgUpDGHSZARGqNcAV5h+OQ
# DLeF2p3URx/P6McUg1nJ2gMPYBsD+bwd9B0c/XIZ9Mt3ujlELPpkijjCdSZxhzu2
# M3SZWJr57uY+FC+LspvIOH1Opofanh3JGDosNcAEu9yUMWKsEBMngD6VWQSQYZ6X
# 9F80zCoeZwTq0i9AujnYzzx5W2fEgZejRu6K1GCASmztNlYJlACjqafWRofTqkJh
# V/J2v97X3ruDvfpuOuQoUtVAwXrDsG2NOBuvVso5KdW54hBSsz/4+ORB4qLnq4/G
# NtajUHorKRKHGOgFo8DKaXG+UNANwhGNxHbILSa59PxExMgCjBRP3828yGKsquSE
# zzLNWnz5af9ZmeH4809fwIttI41JkuiY9X6hmMmLYv8OY34vvOK+zyxkS+9BULVA
# P6gt+yaHaBlrln8Gi4/dBr2y6Srr/56g0DCCB3EwggVZoAMCAQICEzMAAAAVxedr
# ngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRp
# ZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4
# MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qls
# TnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLA
# EBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrE
# qv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyF
# Vk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1o
# O5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg
# 3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2
# TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07B
# MzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJ
# NmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6
# r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+
# auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3
# FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl
# 0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUH
# AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0
# b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMA
# dQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW
# gBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v
# Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRf
# MjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEw
# LTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL
# /Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu
# 6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5t
# ggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfg
# QJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8s
# CXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCr
# dTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZ
# c9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2
# tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8C
# wYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9
# JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDB
# cQZqELQdVTNYs6FwZvKhggNNMIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt
# ZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM3MDMt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# oiMKAQEwBwYFKw4DAhoDFQDRAMVJlA6bKq93Vnu3UkJgm5HlYaCBgzCBgKR+MHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7ODh
# hDAiGA8yMDI1MTIwODA1MzI1MloYDzIwMjUxMjA5MDUzMjUyWjB0MDoGCisGAQQB
# hFkKBAExLDAqMAoCBQDs4OGEAgEAMAcCAQACAgeKMAcCAQACAhNAMAoCBQDs4jME
# AgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSCh
# CjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBALddzHPaV6pwadY5MNhSi2mJ
# Lhj629gK87IMT1p8MFXRtFzmUBtvprc/h46xxL/FY0968pmwmtrKuIgVSCE8Ru8N
# Zq2EBO1nTs7KbHi4rbYH3sRqL3on63G/QIjNdmxRhC5oADGwoQ3eNT8CPwIfPqKw
# HAuovEGV0jEEK/JxPLVOijQ02m/tN2NNBmyV6dc8aabZNhkK2lQrMDaxMSiu7hZ8
# Bow7eOfW1wVf+qbiccqEycfMOTybO73F76pltqvgMv0iWoN9BHX9+wKhdNZ5+ApT
# F4bRdXAXjcPdzezfvFULrEf43TXocG+oEirjM0If5VneNqzK/biDQFgqNGRNAF8x
# ggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA
# AgpHshTZ7rKzDwABAAACCjANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkD
# MQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCA1oZMOV5w0aeUnJ2ZIpzEp
# y/HNZwUR04DXjO8EZ9ZHKjCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIE2a
# y/y0epK/X3Z03KTcloqE8u9IXRtdO7Mex0hw9+SaMIGYMIGApH4wfDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
# IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIKR7IU2e6ysw8AAQAAAgowIgQgXT29
# juHhi5h4UWex9n5gWbLP3ljpCA2rlvjbNgKij40wDQYJKoZIhvcNAQELBQAEggIA
# IRUaRcyvqrr9T/70EQtx0ZnOXUsP9rARKPzA32iaJZofNX05its/PUHrRKDIuIat
# 8V/1W0TsaVhOWtqwsw1mOn4u/AJNDkODo+DErsF3qO0O3wRIeeIJCo1mfvPEVwDA
# FywXHxg8Beqn9bh9Q0HUy0ahJMGnYtgTXZK7p+F9gGmtHsNTsV8CbtNMh0qgoW6H
# tEIAvpAGDsJBRU+aZAJV0FvRxJ4IDSMuBwcfQ423yoCD9qQF5FWsv1i6cIFK5vog
# FXxCrZY+gsjL2c29yJBi+YQOPK6xlTN5jnuxKI71T4bPDEG9OsYF68Zh5echkddv
# /KtWUBJ/Yx7LWC1nRJjpbx8f0R0UhaqktNP2vyHLCF5JxRyrz5R2OsdIkZZ9S+Yb
# MSieDBK9csY1Yf35zX53AUWQXJhkVSHxGOsO4xGbAZct+/xOf9JszW4i+Kfs5Tf5
# HinP9TVM5fC0Hx/5mcUqtMWqeQT9OSl26eRvf83cRcByv2/DV5iKcva0lSkojFb6
# ClAq80nI2xt0904UEWsJaAyL6iWmzFvChwWjDQSKks+6n3VGBm3Vzp9d1TVo916z
# 02uA1pFYNQJYQpqWIutP9Z/k7f65/YoWZja6D9tqXtdQsdNPuSh3gok54awZGsgG
# KEhyfrQBuiyHVr45Vd10lbeMV8dj8IBz6X8peY4rLTU=
# SIG # End signature block