PSWritePDF.psm1

function ConvertFrom-Color { 
    [alias('Convert-FromColor')]
    [CmdletBinding()]
    param ([ValidateScript({ if ($($_ -in $Script:RGBColors.Keys -or $_ -match "^#([A-Fa-f0-9]{6})$" -or $_ -eq "") -eq $false) { throw "The Input value is not a valid colorname nor an valid color hex code." } else { $true } })]
        [alias('Colors')][string[]] $Color,
        [switch] $AsDecimal,
        [switch] $AsDrawingColor)
    $Colors = foreach ($C in $Color) {
        $Value = $Script:RGBColors."$C"
        if ($C -match "^#([A-Fa-f0-9]{6})$") {
            $C
            continue
        }
        if ($null -eq $Value) { continue }
        $HexValue = Convert-Color -RGB $Value
        Write-Verbose "Convert-FromColor - Color Name: $C Value: $Value HexValue: $HexValue"
        if ($AsDecimal) { [Convert]::ToInt64($HexValue, 16) } elseif ($AsDrawingColor) { [System.Drawing.Color]::FromArgb("#$($HexValue)") } else { "#$($HexValue)" }
    }
    $Colors
}
function Remove-EmptyValue { 
    [alias('Remove-EmptyValues')]
    [CmdletBinding()]
    param([alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable,
        [string[]] $ExcludeParameter,
        [switch] $Recursive,
        [int] $Rerun,
        [switch] $DoNotRemoveNull,
        [switch] $DoNotRemoveEmpty,
        [switch] $DoNotRemoveEmptyArray,
        [switch] $DoNotRemoveEmptyDictionary)
    foreach ($Key in [string[]] $Hashtable.Keys) { if ($Key -notin $ExcludeParameter) { if ($Recursive) { if ($Hashtable[$Key] -is [System.Collections.IDictionary]) { if ($Hashtable[$Key].Count -eq 0) { if (-not $DoNotRemoveEmptyDictionary) { $Hashtable.Remove($Key) } } else { Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } }
    if ($Rerun) { for ($i = 0; $i -lt $Rerun; $i++) { Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive } }
}
function Convert-Color { 
    <#
    .Synopsis
    This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX)
    .Description
    This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX). Use it to convert your colors and prepare your graphics and HTML web pages.
    .Parameter RBG
    Enter the Red Green Blue value comma separated. Red: 51 Green: 51 Blue: 204 for example needs to be entered as 51,51,204
    .Parameter HEX
    Enter the Hex value to be converted. Do not use the '#' symbol. (Ex: 3333CC converts to Red: 51 Green: 51 Blue: 204)
    .Example
    .\convert-color -hex FFFFFF
    Converts hex value FFFFFF to RGB
 
    .Example
    .\convert-color -RGB 123,200,255
    Converts Red = 123 Green = 200 Blue = 255 to Hex value
 
    #>

    param([Parameter(ParameterSetName = "RGB", Position = 0)]
        [ValidateScript({ $_ -match '^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$' })]
        $RGB,
        [Parameter(ParameterSetName = "HEX", Position = 0)]
        [ValidateScript({ $_ -match '[A-Fa-f0-9]{6}' })]
        [string]
        $HEX)
    switch ($PsCmdlet.ParameterSetName) {
        "RGB" {
            if ($null -eq $RGB[2]) { Write-Error "Value missing. Please enter all three values seperated by comma." }
            $red = [convert]::Tostring($RGB[0], 16)
            $green = [convert]::Tostring($RGB[1], 16)
            $blue = [convert]::Tostring($RGB[2], 16)
            if ($red.Length -eq 1) { $red = '0' + $red }
            if ($green.Length -eq 1) { $green = '0' + $green }
            if ($blue.Length -eq 1) { $blue = '0' + $blue }
            Write-Output $red$green$blue
        }
        "HEX" {
            $red = $HEX.Remove(2, 4)
            $Green = $HEX.Remove(4, 2)
            $Green = $Green.remove(0, 2)
            $Blue = $hex.Remove(0, 4)
            $Red = [convert]::ToInt32($red, 16)
            $Green = [convert]::ToInt32($green, 16)
            $Blue = [convert]::ToInt32($blue, 16)
            Write-Output $red, $Green, $blue
        }
    }
}
function Add-PDFDocumentContent {
    [CmdletBinding()]
    param(
        [object] $Object
    )
    if ($Script:Document) {
        $null = $Script:Document.Add($Object)
    } else {
        $Splat = $Script:PDFStart.DocumentSettings
        $Settings = New-PDFPage @Splat #-MarginTop $MarginTop -MarginBottom $MarginBottom -MarginLeft $MarginLeft -MarginRight $MarginRight -PageSize $PageSize -Rotate:$Rotate.IsPresent
        New-InternalPDFPage -PageSize $Settings.Settings.PageSize -Rotate:$Settings.Settings.Rotate -MarginTop $MarginTop -MarginBottom $MarginBottom -MarginLeft $MarginLeft -MarginRight $MarginRight
        $null = $Script:Document.Add($Object)
    }
}
class CustomSplitter : iText.Kernel.Utils.PdfSplitter {
    [int] $_order
    [string] $_destinationFolder
    [string] $_outputName

    CustomSplitter([iText.Kernel.Pdf.PdfDocument] $pdfDocument, [string] $destinationFolder, [string] $OutputName) : base($pdfDocument) {
        $this._destinationFolder = $destinationFolder
        $this._order = 0
        $this._outputName = $OutputName
    }

    [iText.Kernel.Pdf.PdfWriter] GetNextPdfWriter([iText.Kernel.Utils.PageRange] $documentPageRange) {
        $Name = -join ($this._outputName, $this._order++, ".pdf")
        $Path = [IO.Path]::Combine($this._destinationFolder, $Name)
        return [iText.Kernel.Pdf.PdfWriter]::new($Path)
    }
}

# [iText.Kernel.Geom.Vector]::I1
<#
    RenderText([iText.Kernel.Pdf.Canvas.Parser.Data.TextRenderInfo] $renderInfo) {
        [string] $curFont = $renderInfo.GetFont().PostscriptFontName
        #//Check if faux bold is used
        if ((renderInfo.GetTextRenderMode() == (int)TextRenderMode.FillThenStrokeText)) {
            $curFont += "-Bold";
        }
 
        #//This code assumes that if the baseline changes then we're on a newline
        [iText.Kernel.Geom.Vector] $curBaseline = $renderInfo.GetBaseline().GetStartPoint();
        [iText.Kernel.Geom.Vector] $topRight = $renderInfo.GetAscentLine().GetEndPoint();
        [iText.Kernel.Geom.Rectangle] $rect = [iText.Kernel.Geom.Rectangle]::new($curBaseline[Vector.I1], $curBaseline[Vector.I2], $topRight[Vector.I1], $topRight[Vector.I2]);
        [Single] $curFontSize = $rect.Height;
 
        #//See if something has changed, either the baseline, the font or the font size
        if (($this.lastBaseLine -eq $null) -or ($curBaseline[Vector.I2] -ne $lastBaseLine[Vector.I2]) -or ($curFontSize -ne $lastFontSize) -or ($curFont -ne $lastFont)) {
            #//if we've put down at least one span tag close it
            if (($this.lastBaseLine -ne $null)) {
                $this.result.AppendLine("</span>");
            }
            #//If the baseline has changed then insert a line break
            if (($this.lastBaseLine -ne $null) -and ($curBaseline[Vector.I2] -ne $lastBaseLine[Vector.I2]) {
                $this.result.AppendLine("<br />");
            }
            #//Create an HTML tag with appropriate styles
            $this.result.AppendFormat("<span style=`"font-family: { 0 }; font-size: { 1 }`">", $curFont, $curFontSize);
        }
        #//Append the current text
        $this.result.Append($renderInfo.GetText());
 
        #//Set currently used properties
        $this.lastBaseLine = curBaseline;
        $this.lastFontSize = curFontSize;
        $this.lastFont = curFont;
    }
#>

Enum TextRenderMode {
    FillText = 0
    StrokeText = 1
    FillThenStrokeText = 2
    Invisible = 3
    FillTextAndAddToPathForClipping = 4
    StrokeTextAndAddToPathForClipping = 5
    FillThenStrokeTextAndAddToPathForClipping = 6
    AddTextToPaddForClipping = 7
}
class TextWithFontExtractionStategy : iText.Kernel.Pdf.Canvas.Parser.Listener.ITextExtractionStrategy {
    #HTML buffer
    [System.Text.StringBuilder] $result = [System.Text.StringBuilder]::new()

    #Store last used properties
    [iText.Kernel.Geom.Vector] $lastBaseLine
    [string] $lastFont
    [single] $lastFontSize

    RenderText([iText.Kernel.Pdf.Canvas.Parser.Data.TextRenderInfo] $renderInfo) {
        [string] $curFont = $renderInfo.GetFont().PostscriptFontName;
        #//Check if faux bold is used
        if ($renderInfo.GetTextRenderMode() -eq [int][TextRenderMode]::FillThenStrokeText) {
            $curFont += "-Bold";
        }

        #//This code assumes that if the baseline changes then we're on a newline
        [iText.Kernel.Geom.Vector] $curBaseline = $renderInfo.GetBaseline().GetStartPoint();
        [iText.Kernel.Geom.Vector] $topRight = $renderInfo.GetAscentLine().GetEndPoint();
        [iText.Kernel.Geom.Rectangle] $rect = [iText.Kernel.Geom.Rectangle]::new($curBaseline, $curBaseline, $topRight, $topRight);
        [Single] $curFontSize = $rect.Height;

        #//See if something has changed, either the baseline, the font or the font size
        if (($null -eq $this.lastBaseLine) -or ($curBaseline -ne $this.lastBaseLine) -or ($curFontSize -ne $this.lastFontSize) -or ($curFont -ne $this.lastFont)) {
            #//if we've put down at least one span tag close it
            if ($null -ne $this.lastBaseLine) {
                $this.result.AppendLine("</span>");
            }
            #//If the baseline has changed then insert a line break
            if (($null -ne $this.lastBaseLine) -and ($curBaseline -ne $this.lastBaseLine)) {
                $this.result.AppendLine("<br />");
            }
            #//Create an HTML tag with appropriate styles
            $this.result.AppendFormat("<span style=`"font-family: { 0 }; font-size: { 1 }`">", $curFont, $curFontSize);
        }
        #//Append the current text
        $this.result.Append($renderInfo.GetText());

        #//Set currently used properties
        $this.lastBaseLine = $curBaseline;
        $this.lastFontSize = $curFontSize;
        $this.lastFont = $curFont;
    }

    [string] GetResultantText() {
        #//If we wrote anything then we'll always have a missing closing tag so close it here
        if ($this.result.Length -gt 0) {
            $this.result.Append("</span>");
        }
        return $this.result.ToString();
    }
    [System.Collections.Generic.ICollection[iText.Kernel.Pdf.Canvas.Parser.EventType]] GetSupportedEvents() {
        return $null
    }
    [void] EventOccurred([iText.Kernel.Pdf.Canvas.Parser.Data.IEventData] $data, [iText.Kernel.Pdf.Canvas.Parser.EventType] $type) {
        return
    }
}
# Validation for Fonts
$Script:PDFFont = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    ([iText.IO.Font.Constants.StandardFonts] | Get-Member -Static -MemberType Property).Name | Where-Object { $_ -like "*$wordToComplete*" }
}
$Script:PDFFontValidation = {
    $Array = @(
        (& $Script:PDFFont)
        ''
    )
    $_ -in $Array
}
$Script:PDFFontList = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    @(
        ([iText.IO.Font.Constants.StandardFonts] | Get-Member -Static -MemberType Property).Name
        if ($Script:Fonts.Keys) { $Script:Fonts.Keys }
    ) | Where-Object { $_ -like "*$wordToComplete*" }
}
$Script:PDFFontValidationList = {
    $Array = @(
        (& $Script:PDFFont)
        $Script:Fonts.Keys
        ''
    )
    $_ -in $Array
}
function Get-InternalPDFFont {
    [cmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFFontValidationList } )][string] $Font
    )
    if (-not $Script:Fonts[$Font]) {
        # If not defined font, we use contstant fonts
        $ConvertedFont = Get-PDFConstantFont -Font $Font
        $ApplyFont = [iText.Kernel.Font.PdfFontFactory]::CreateFont($ConvertedFont)
    } else {
        # if defined we use whatever we defined
        $ApplyFont = $Script:Fonts[$Font]
    }
    $ApplyFont
}

Register-ArgumentCompleter -CommandName Get-InternalPDFFont -ParameterName Font -ScriptBlock $Script:PDFFontList
function Get-PDFNamedPageSize {
    [CmdletBinding()]
    param(
        [int] $Height,
        [int] $Width
    )

    $PDFSizes = @{
        '33702384' = [PSCustomObject] @{ PageSize = 'A0'; Rotated = $false }
        '23843370' = [PSCustomObject] @{ PageSize = 'A0'; Rotated = $true }
        '23841684' = [PSCustomObject] @{ PageSize = 'A1'; Rotated = $false }
        '16842384' = [PSCustomObject] @{ PageSize = 'A1'; Rotated = $true }
        '10574'    = [PSCustomObject] @{ PageSize = 'A10'; Rotated = $false }
        '74105'    = [PSCustomObject] @{ PageSize = 'A10'; Rotated = $true }
        '16841190' = [PSCustomObject] @{ PageSize = 'A2'; Rotated = $false }
        '11901684' = [PSCustomObject] @{ PageSize = 'A2'; Rotated = $true }
        '1190842'  = [PSCustomObject] @{ PageSize = 'A3'; Rotated = $false }
        '8421190'  = [PSCustomObject] @{ PageSize = 'A3'; Rotated = $true }
        '842595'   = [PSCustomObject] @{ PageSize = 'A4'; Rotated = $false }
        '595842'   = [PSCustomObject] @{ PageSize = 'A4'; Rotated = $true }
        '595420'   = [PSCustomObject] @{ PageSize = 'A5'; Rotated = $false }
        '420595'   = [PSCustomObject] @{ PageSize = 'A5'; Rotated = $true }
        '420298'   = [PSCustomObject] @{ PageSize = 'A6'; Rotated = $false }
        '298420'   = [PSCustomObject] @{ PageSize = 'A6'; Rotated = $true }
        '298210'   = [PSCustomObject] @{ PageSize = 'A7'; Rotated = $false }
        '210298'   = [PSCustomObject] @{ PageSize = 'A7'; Rotated = $true }
        '210148'   = [PSCustomObject] @{ PageSize = 'A8'; Rotated = $false }
        '148210'   = [PSCustomObject] @{ PageSize = 'A8'; Rotated = $true }
        '547105'   = [PSCustomObject] @{ PageSize = 'A9'; Rotated = $false }
        '105547'   = [PSCustomObject] @{ PageSize = 'A9'; Rotated = $true }
        '40082834' = [PSCustomObject] @{ PageSize = 'B0'; Rotated = $false }
        '28344008' = [PSCustomObject] @{ PageSize = 'B0'; Rotated = $true }
        '28342004' = [PSCustomObject] @{ PageSize = 'B1'; Rotated = $false }
        '20042834' = [PSCustomObject] @{ PageSize = 'B1'; Rotated = $true }
        '12488'    = [PSCustomObject] @{ PageSize = 'B10'; Rotated = $false }
        '88124'    = [PSCustomObject] @{ PageSize = 'B10'; Rotated = $true }
        '20041417' = [PSCustomObject] @{ PageSize = 'B2'; Rotated = $false }
        '14172004' = [PSCustomObject] @{ PageSize = 'B2'; Rotated = $true }
        '14171000' = [PSCustomObject] @{ PageSize = 'B3'; Rotated = $false }
        '10001417' = [PSCustomObject] @{ PageSize = 'B3'; Rotated = $true }
        '1000708'  = [PSCustomObject] @{ PageSize = 'B4'; Rotated = $false }
        '7081000'  = [PSCustomObject] @{ PageSize = 'B4'; Rotated = $true }
        '708498'   = [PSCustomObject] @{ PageSize = 'B5'; Rotated = $false }
        '498708'   = [PSCustomObject] @{ PageSize = 'B5'; Rotated = $true }
        '498354'   = [PSCustomObject] @{ PageSize = 'B6'; Rotated = $false }
        '354498'   = [PSCustomObject] @{ PageSize = 'B6'; Rotated = $true }
        '354249'   = [PSCustomObject] @{ PageSize = 'B7'; Rotated = $false }
        '249354'   = [PSCustomObject] @{ PageSize = 'B7'; Rotated = $true }
        '249175'   = [PSCustomObject] @{ PageSize = 'B8'; Rotated = $false }
        '175249'   = [PSCustomObject] @{ PageSize = 'B8'; Rotated = $true }
        '175124'   = [PSCustomObject] @{ PageSize = 'B9'; Rotated = $false }
        '124175'   = [PSCustomObject] @{ PageSize = 'B9'; Rotated = $true }
        '756522'   = [PSCustomObject] @{ PageSize = 'EXECUTIVE'; Rotated = $false }
        '522756'   = [PSCustomObject] @{ PageSize = 'EXECUTIVE'; Rotated = $true }
        '7921224'  = [PSCustomObject] @{ PageSize = 'LEDGER or TABLOID'; Rotated = $false }
        '1224792'  = [PSCustomObject] @{ PageSize = 'LEDGER or TABLOID'; Rotated = $true }
        '1008612'  = [PSCustomObject] @{ PageSize = 'LEGAL'; Rotated = $false }
        '6121008'  = [PSCustomObject] @{ PageSize = 'LEGAL'; Rotated = $true }
        '792612'   = [PSCustomObject] @{ PageSize = 'LETTER'; Rotated = $false }
        '612792'   = [PSCustomObject] @{ PageSize = 'LETTER'; Rotated = $true }
    }
    $Size = $PDFSizes["$Height$Width"]
    if ($Size) {
        return $Size
    } else {
        return [PSCustomObject] @{ PageSize = 'Unknown'; $Rotated = $null }
    }
}
function Initialize-PDF {
    [CmdletBinding()]
    param(
        [Array] $Elements
    )
    foreach ($Element in $Elements) {
        $Splat = $Element.Settings
        if ($Splat) {
            Remove-EmptyValue -Hashtable $Splat
        }
        if ($Element.Type -eq 'Page') {
            if (-not $Script:PDFStart.FirstPageUsed) {
                #$Area = New-PDFArea -PageSize $Element.Settings.PageSize -Rotate:$Element.Settings.Rotate -AreaType ([iText.Layout.Properties.AreaBreakType]::LAST_PAGE)
                #New-InternalPDFPage -PageSize $Element.Settings.PageSize -Rotate:$Element.Settings.Rotate

                # This adds margings to first page if New-PDFOptions is used but no margins were defined on New-PDFPage
                if (-not $Splat.Margins.MarginBottom) {
                    $Splat.Margins.MarginBottom = $Script:PDFStart.DocumentSettings.MarginBottom
                }
                if (-not $Splat.Margins.MarginTop) {
                    $Splat.Margins.MarginTop = $Script:PDFStart.DocumentSettings.MarginTop
                }
                if (-not $Splat.Margins.MarginLeft) {
                    $Splat.Margins.MarginLeft = $Script:PDFStart.DocumentSettings.MarginLeft
                }
                if (-not $Splat.Margins.MarginRight) {
                    $Splat.Margins.MarginRight = $Script:PDFStart.DocumentSettings.MarginRight
                }
                New-InternalPDFPage -PageSize $Splat.PageSize -Rotate:$Splat.Rotate -MarginLeft $Splat.Margins.MarginLeft -MarginTop $Splat.Margins.MarginTop -MarginBottom $Splat.Margins.MarginBottom -MarginRight $Splat.Margins.MarginRight
                #Add-PDFDocumentContent -Object $Area
                $Script:PDFStart.FirstPageUsed = $true
            } else {
                # This fixes margins. Margins have to be added before new PageArea
                $SplatMargins = $Splat.Margins
                New-InternalPDFOptions @SplatMargins

                $Area = New-PDFArea -PageSize $Element.Settings.PageSize -Rotate:$Element.Settings.Rotate
                Add-PDFDocumentContent -Object $Area
            }
            # New-InternalPDFPage -PageSize $Element.Settings.PageSize -Rotate:$Element.Settings.Rotate
            # New-InternalPDFOptions -Settings $Element.Settings
            if ($Element.Settings.PageContent) {
                Initialize-PDF -Elements $Element.Settings.PageContent
            }
        } elseif ($Element.Type -eq 'Text') {
            $Paragraph = New-InternalPDFText @Splat
            foreach ($P in $Paragraph) {
                Add-PDFDocumentContent -Object $P
            }
        } elseif ($Element.Type -eq 'List') {
            New-InternalPDFList -Settings $Element.Settings
        } elseif ($Element.Type -eq 'Paragraph') {

        } elseif ($Element.Type -eq 'Options') {
            $SplatMargins = $Splat.Margins
            New-InternalPDFOptions @SplatMargins
        } elseif ($Element.Type -eq 'Table') {
            $Table = New-InteralPDFTable @Splat
            #$null = $Script:Document.Add($Table)
            Add-PDFDocumentContent -Object $Table
        } elseif ($Element.Type -eq 'Image') {
            New-InternalPDFImage @Splat
        }
    }
}
function New-InternalPDF {
    [CmdletBinding()]
    param(
        [string] $FilePath,
        [string] $Version #,
        # [ValidateScript( { & $Script:PDFPageSizeValidation } )][string] $PageSize,
        # [switch] $Rotate
    )

    if ($Version) {
        $PDFVersion = Get-PDFConstantVersion -Version $Version
        $WriterProperties = [iText.Kernel.Pdf.WriterProperties]::new()
        $null = $WriterProperties.SetPdfVersion($PDFVersion)
    }

    try {
        if ($Version) {
            $Script:Writer = [iText.Kernel.Pdf.PdfWriter]::new($FilePath, $WriterProperties)
        } else {
            $Script:Writer = [iText.Kernel.Pdf.PdfWriter]::new($FilePath)
        }
    } catch {
        if ($_.Exception.Message -like '*The process cannot access the file*because it is being used by another process.*') {
            Write-Warning "New-InternalPDF - File $FilePath is in use. Terminating."
            return
        } else {
            Write-Warning "New-InternalPDF - Terminating error: $($_.Exception.Message)"
            return
        }
    }

    if ($Script:Writer) {
        $PDF = [iText.Kernel.Pdf.PdfDocument]::new($Script:Writer)
    } else {
        Write-Warning "New-InternalPDF - Terminating as writer doesn't exists."
        return
    }
    return $PDF
}



<#
function New-InternalPDF {
    param(
 
    )
    if ($Script:Writer) {
        if ($Script:PDF) {
            #$Script:PDF.Close()
        }
        $Script:PDF = [iText.Kernel.Pdf.PdfDocument]::new($Script:Writer)
    } else {
        Write-Warning "New-InternalPDF - Terminating as writer doesn't exists."
        Exit
    }
}
#>

Register-ArgumentCompleter -CommandName New-InternalPDF -ParameterName PageSize -ScriptBlock $Script:PDFPageSize
Register-ArgumentCompleter -CommandName New-InternalPDF -ParameterName Version -ScriptBlock $Script:PDFVersion
function New-InternalPDFImage {
    [CmdletBinding()]
    param(
        [string] $ImagePath,
        [int] $Width,
        [int] $Height,
        [object] $BackgroundColor,
        [double] $BackgroundColorOpacity
    )

    $ImageData = [iText.IO.Image.ImageDataFactory]::Create($ImagePath)
    $Image = [iText.Layout.Element.Image]::new($ImageData)

    if ($Width) {
        $Image.SetWidth($Width)
    }
    if ($Height) {
        $Image.SetHeight($Height)

    }
    if ($BackgroundColor) {
        <#
        iText.Layout.Element.Image SetBackgroundColor(iText.Kernel.Colors.Color backgroundColor)
        iText.Layout.Element.Image SetBackgroundColor(iText.Kernel.Colors.Color backgroundColor, float opacity)
        iText.Layout.Element.Image SetBackgroundColor(iText.Kernel.Colors.Color backgroundColor, float extraLeft, float extraTop, float extraRight, float extraBottom)
        iText.Layout.Element.Image SetBackgroundColor(iText.Kernel.Colors.Color backgroundColor, float opacity, float extraLeft, float extraTop, float extraRight, float extraBottom)
        #>

        $RGB = [iText.Kernel.Colors.DeviceRgb]::new($BackgroundColor.R, $BackgroundColor.G, $BackgroundColor.B)
        $null = $Image.SetBackgroundColor($RGB)
        if ($BackgroundColorOpacity) {
            $null = $Image.SetOpacity($BackgroundColorOpacity)
        }
    }
    $null = $Script:Document.Add($Image)
}
function New-InternalPDFList {
    [CmdletBinding()]
    param(
        [System.Collections.IDictionary] $Settings
    )

    $List = [iText.Layout.Element.List]::new()
    if ($null -ne $Settings.Indent) {
        $null = $List.SetSymbolIndent($Settings.Indent)
    }
    if ($Settings.Symbol) {
        if ($Settings.Symbol -eq 'hyphen') {
            # Default
        } elseif ($Settings.Symbol -eq 'bullet') {
            $Symbol = [regex]::Unescape("\u2022")
            $null = $List.SetListSymbol($Symbol)
        }

    }
    foreach ($ItemSettings in $Settings.Items) {
        $Paragraph = New-InternalPDFText @ItemSettings
        $ListItem = [iText.Layout.Element.ListItem]::new()
        $null = $ListItem.Add($Paragraph)
        $null = $List.Add($ListItem)
    }
    $null = $Script:Document.Add($List)
}
function New-InternalPDFOptions {
    [CmdletBinding()]
    param(
        [nullable[float]] $MarginLeft,
        [nullable[float]] $MarginRight,
        [nullable[float]] $MarginTop,
        [nullable[float]] $MarginBottom
    )

    if ($Script:Document) {
        if ($MarginLeft) {
            $Script:Document.SetLeftMargin($MarginLeft)
        }
        if ($MarginRight) {
            $Script:Document.SetRightMargin($MarginRight)
        }
        if ($MarginTop) {
            $Script:Document.SetTopMargin($MarginTop)
        }
        if ($MarginBottom) {
            $Script:Document.SetBottomMargin($MarginBottom)
        }
    } else {
        # If Document doesn't exists it means we're using New-PDFOptions before New-PDFPage
        # We update DocumentSettings and use it just in case New-PDFPage doesn't have those values used.
        # Workaround, ugly but don't see a better way
        $Script:PDFStart['DocumentSettings']['MarginTop'] = $MarginTop
        $Script:PDFStart['DocumentSettings']['MarginBottom'] = $MarginBottom
        $Script:PDFStart['DocumentSettings']['MarginLeft'] = $MarginLeft
        $Script:PDFStart['DocumentSettings']['MarginRight'] = $MarginRight
    }

    #if ($Settings.PageSize) {
    # $Script:Document.GetPdfDocument().SetDefaultPageSize([iText.Kernel.Geom.PageSize]::($Settings.PageSize))
    # }
}
function New-InternalPDFPage {
    [CmdletBinding()]
    param(
        [string] $PageSize,
        [switch] $Rotate,
        [nullable[float]] $MarginLeft,
        [nullable[float]] $MarginRight,
        [nullable[float]] $MarginTop,
        [nullable[float]] $MarginBottom
    )

    if ($PageSize -or $Rotate) {
        if ($PageSize) {
            $Page = [iText.Kernel.Geom.PageSize]::($PageSize)
        } else {
            $Page = [iText.Kernel.Geom.PageSize]::Default
        }
        if ($Rotate) {
            $Page = $Page.Rotate()
        }
    }
    if ($Page) {
        $null = $Script:PDF.AddNewPage($Page)
    } else {
        $null = $Script:PDF.AddNewPage()
    }
    $Script:Document = [iText.Layout.Document]::new($Script:PDF)

    if ($Script:Document) {
        if ($MarginLeft) {
            $Script:Document.SetLeftMargin($MarginLeft)
        }
        if ($MarginRight) {
            $Script:Document.SetRightMargin($MarginRight)
        }
        if ($MarginTop) {
            $Script:Document.SetTopMargin($MarginTop)
        }
        if ($MarginBottom) {
            $Script:Document.SetBottomMargin($MarginBottom)
        }
    }
}

Register-ArgumentCompleter -CommandName New-InternalPDFPage -ParameterName PageSize -ScriptBlock $Script:PDFPageSize
function New-InteralPDFTable {
    [CmdletBinding()]
    param(
        [Array] $DataTable
    )

    if ($DataTable[0] -is [System.Collections.IDictionary]) {
        [Array] $ColumnNames = 'Name', 'Value' # $DataTable[0].Keys
        [Array] $TemporaryTable = foreach ($_ in $DataTable) {
            $_.GetEnumerator() | Select-Object Name, Value
        }
    } else {
        [Array] $ColumnNames = $DataTable[0].PSObject.Properties.Name
        [Array] $TemporaryTable = $DataTable
    }

    [iText.layout.element.Table] $Table = [iText.Layout.Element.Table]::new($ColumnNames.Count)
    $Table = $Table.UseAllAvailableWidth()

    foreach ($Column in $ColumnNames) {
        $Splat = @{
            Text = $Column
            #Font = $Font
            #FontFamily = $FontFamily
            #FontColor = $FontColor
            #FontBold = $FontBold
        }
        $Paragraph = New-InternalPDFText @Splat
        #$Paragraph = New-PDFText -Text $Column
        [iText.Layout.Element.Cell] $Cell = [iText.Layout.Element.Cell]::new().Add($Paragraph)
        $null = $Table.AddCell($Cell)
    }
    foreach ($_ in $TemporaryTable) {
        foreach ($Column in $ColumnNames) {
            $Splat = @{
                Text = $_.$Column
                #Font = $Font
                #FontFamily = $FontFamily
                #FontColor = $FontColor
                #FontBold = $FontBold
            }
            $Paragraph = New-InternalPDFText @Splat
            #$Paragraph = New-PDFText -Text $_.$Column
            [iText.Layout.Element.Cell] $Cell = [iText.Layout.Element.Cell]::new().Add($Paragraph)
            $null = $Table.AddCell($Cell)
        }
    }
    $Table
}
function New-InternalPDFText {
    [CmdletBinding()]
    param(
        [string[]] $Text,
        [ValidateScript( { & $Script:PDFFontValidationList } )][string[]] $Font,
        #[string[]] $FontFamily,
        [ValidateScript( { & $Script:PDFColorValidation } )][string[]] $FontColor,
        [nullable[bool][]] $FontBold
    )

    $Paragraph = [iText.Layout.Element.Paragraph]::new()

    if ($FontBold) {
        [Array] $FontBold = $FontBold
        $DefaultBold = $FontBold[0]
    }
    if ($FontColor) {
        [Array] $FontColor = $FontColor
        $DefaultColor = $FontColor[0]
    }
    if ($Font) {
        [Array] $Font = $Font
        $DefaultFont = $Font[0]
    }

    for ($i = 0; $i -lt $Text.Count; $i++) {
        [iText.Layout.Element.Text] $PDFText = $Text[$i]

        if ($FontBold) {
            if ($null -ne $FontBold[$i]) {
                if ($FontBold[$i]) {
                    $PDFText = $PDFText.SetBold()
                }
            } else {
                if ($DefaultBold) {
                    $PDFText = $PDFText.SetBold()
                }
            }
        }
        if ($FontColor) {
            if ($null -ne $FontColor[$i]) {
                if ($FontColor[$i]) {
                    $ConvertedColor = Get-PDFConstantColor -Color $FontColor[$i]
                    $PDFText = $PDFText.SetFontColor($ConvertedColor)
                }
            } else {
                if ($DefaultColor) {
                    $ConvertedColor = Get-PDFConstantColor -Color $DefaultColor
                    $PDFText = $PDFText.SetFontColor($ConvertedColor)
                }
            }
        }
        if ($Font) {
            if ($null -ne $Font[$i]) {
                if ($Font[$i]) {
                    #$ConvertedFont = Get-PDFConstantFont -Font $Font[$i]
                    #$ApplyFont = [iText.Kernel.Font.PdfFontFactory]::CreateFont($ConvertedFont, [iText.IO.Font.PdfEncodings]::IDENTITY_H, $false)
                    #$ApplyFont = [iText.Kernel.Font.PdfFontFactory]::CreateFont('TIMES_ROMAN', [iText.IO.Font.PdfEncodings]::IDENTITY_H, $false)
                    #$PDFText = $PDFText.SetFont($ApplyFont)
                    $ApplyFont = Get-InternalPDFFont -Font $Font[$i]
                    $PDFText = $PDFText.SetFont($ApplyFont)
                }
            } else {
                if ($DefaultColor) {
                    # $ConvertedFont = Get-PDFConstantFont -Font $DefaultFont
                    # $ApplyFont = [iText.Kernel.Font.PdfFontFactory]::CreateFont($ConvertedFont, [iText.IO.Font.PdfEncodings]::IDENTITY_H, $false)
                    # $PDFText = $PDFText.SetFont($ApplyFont)
                    $ApplyFont = Get-InternalPDFFont -Font $DefaultFont
                    $PDFText = $PDFText.SetFont($ApplyFont)
                }
            }
        } else {
            if ($Script:DefaultFont) {
                $PDFText = $PDFText.SetFont($Script:DefaultFont)
            }
        }
        $null = $Paragraph.Add($PDFText)
    }
    $Paragraph
}
$Script:RGBColors = [ordered] @{
    None                   = $null
    AirForceBlue           = 93, 138, 168
    Akaroa                 = 195, 176, 145
    AlbescentWhite         = 227, 218, 201
    AliceBlue              = 240, 248, 255
    Alizarin               = 227, 38, 54
    Allports               = 18, 97, 128
    Almond                 = 239, 222, 205
    AlmondFrost            = 159, 129, 112
    Amaranth               = 229, 43, 80
    Amazon                 = 59, 122, 87
    Amber                  = 255, 191, 0
    Amethyst               = 153, 102, 204
    AmethystSmoke          = 156, 138, 164
    AntiqueWhite           = 250, 235, 215
    Apple                  = 102, 180, 71
    AppleBlossom           = 176, 92, 82
    Apricot                = 251, 206, 177
    Aqua                   = 0, 255, 255
    Aquamarine             = 127, 255, 212
    Armygreen              = 75, 83, 32
    Arsenic                = 59, 68, 75
    Astral                 = 54, 117, 136
    Atlantis               = 164, 198, 57
    Atomic                 = 65, 74, 76
    AtomicTangerine        = 255, 153, 102
    Axolotl                = 99, 119, 91
    Azure                  = 240, 255, 255
    Bahia                  = 176, 191, 26
    BakersChocolate        = 93, 58, 26
    BaliHai                = 124, 152, 171
    BananaMania            = 250, 231, 181
    BattleshipGrey         = 85, 93, 80
    BayOfMany              = 35, 48, 103
    Beige                  = 245, 245, 220
    Bermuda                = 136, 216, 192
    Bilbao                 = 42, 128, 0
    BilobaFlower           = 181, 126, 220
    Bismark                = 83, 104, 114
    Bisque                 = 255, 228, 196
    Bistre                 = 61, 43, 31
    Bittersweet            = 254, 111, 94
    Black                  = 0, 0, 0
    BlackPearl             = 31, 38, 42
    BlackRose              = 85, 31, 47
    BlackRussian           = 23, 24, 43
    BlanchedAlmond         = 255, 235, 205
    BlizzardBlue           = 172, 229, 238
    Blue                   = 0, 0, 255
    BlueDiamond            = 77, 26, 127
    BlueMarguerite         = 115, 102, 189
    BlueSmoke              = 115, 130, 118
    BlueViolet             = 138, 43, 226
    Blush                  = 169, 92, 104
    BokaraGrey             = 22, 17, 13
    Bole                   = 121, 68, 59
    BondiBlue              = 0, 147, 175
    Bordeaux               = 88, 17, 26
    Bossanova              = 86, 60, 92
    Boulder                = 114, 116, 114
    Bouquet                = 183, 132, 167
    Bourbon                = 170, 108, 57
    Brass                  = 181, 166, 66
    BrickRed               = 199, 44, 72
    BrightGreen            = 102, 255, 0
    BrightRed              = 146, 43, 62
    BrightTurquoise        = 8, 232, 222
    BrilliantRose          = 243, 100, 162
    BrinkPink              = 250, 110, 121
    BritishRacingGreen     = 0, 66, 37
    Bronze                 = 205, 127, 50
    Brown                  = 165, 42, 42
    BrownPod               = 57, 24, 2
    BuddhaGold             = 202, 169, 6
    Buff                   = 240, 220, 130
    Burgundy               = 128, 0, 32
    BurlyWood              = 222, 184, 135
    BurntOrange            = 255, 117, 56
    BurntSienna            = 233, 116, 81
    BurntUmber             = 138, 51, 36
    ButteredRum            = 156, 124, 56
    CadetBlue              = 95, 158, 160
    California             = 224, 141, 60
    CamouflageGreen        = 120, 134, 107
    Canary                 = 255, 255, 153
    CanCan                 = 217, 134, 149
    CannonPink             = 145, 78, 117
    CaputMortuum           = 89, 39, 32
    Caramel                = 255, 213, 154
    Cararra                = 237, 230, 214
    Cardinal               = 179, 33, 52
    CardinGreen            = 18, 53, 36
    CareysPink             = 217, 152, 160
    CaribbeanGreen         = 0, 222, 164
    Carmine                = 175, 0, 42
    CarnationPink          = 255, 166, 201
    CarrotOrange           = 242, 142, 28
    Cascade                = 141, 163, 153
    CatskillWhite          = 226, 229, 222
    Cedar                  = 67, 48, 46
    Celadon                = 172, 225, 175
    Celeste                = 207, 207, 196
    Cello                  = 55, 79, 107
    Cement                 = 138, 121, 93
    Cerise                 = 222, 49, 99
    Cerulean               = 0, 123, 167
    CeruleanBlue           = 42, 82, 190
    Chantilly              = 239, 187, 204
    Chardonnay             = 255, 200, 124
    Charlotte              = 167, 216, 222
    Charm                  = 208, 116, 139
    Chartreuse             = 127, 255, 0
    ChartreuseYellow       = 223, 255, 0
    ChelseaCucumber        = 135, 169, 107
    Cherub                 = 246, 214, 222
    Chestnut               = 185, 78, 72
    ChileanFire            = 226, 88, 34
    Chinook                = 150, 200, 162
    Chocolate              = 210, 105, 30
    Christi                = 125, 183, 0
    Christine              = 181, 101, 30
    Cinnabar               = 235, 76, 66
    Citron                 = 159, 169, 31
    Citrus                 = 141, 182, 0
    Claret                 = 95, 25, 51
    ClassicRose            = 251, 204, 231
    ClayCreek              = 145, 129, 81
    Clinker                = 75, 54, 33
    Clover                 = 74, 93, 35
    Cobalt                 = 0, 71, 171
    CocoaBrown             = 44, 22, 8
    Cola                   = 60, 48, 36
    ColumbiaBlue           = 166, 231, 255
    CongoBrown             = 103, 76, 71
    Conifer                = 178, 236, 93
    Copper                 = 218, 138, 103
    CopperRose             = 153, 102, 102
    Coral                  = 255, 127, 80
    CoralRed               = 255, 64, 64
    CoralTree              = 173, 111, 105
    Coriander              = 188, 184, 138
    Corn                   = 251, 236, 93
    CornField              = 250, 240, 190
    Cornflower             = 147, 204, 234
    CornflowerBlue         = 100, 149, 237
    Cornsilk               = 255, 248, 220
    Cosmic                 = 132, 63, 91
    Cosmos                 = 255, 204, 203
    CostaDelSol            = 102, 93, 30
    CottonCandy            = 255, 188, 217
    Crail                  = 164, 90, 82
    Cranberry              = 205, 96, 126
    Cream                  = 255, 255, 204
    CreamCan               = 242, 198, 73
    Crimson                = 220, 20, 60
    Crusta                 = 232, 142, 90
    Cumulus                = 255, 255, 191
    Cupid                  = 246, 173, 198
    CuriousBlue            = 40, 135, 200
    Cyan                   = 0, 255, 255
    Cyprus                 = 6, 78, 64
    DaisyBush              = 85, 53, 146
    Dandelion              = 250, 218, 94
    Danube                 = 96, 130, 182
    DarkBlue               = 0, 0, 139
    DarkBrown              = 101, 67, 33
    DarkCerulean           = 8, 69, 126
    DarkChestnut           = 152, 105, 96
    DarkCoral              = 201, 90, 73
    DarkCyan               = 0, 139, 139
    DarkGoldenrod          = 184, 134, 11
    DarkGray               = 169, 169, 169
    DarkGreen              = 0, 100, 0
    DarkGreenCopper        = 73, 121, 107
    DarkGrey               = 169, 169, 169
    DarkKhaki              = 189, 183, 107
    DarkMagenta            = 139, 0, 139
    DarkOliveGreen         = 85, 107, 47
    DarkOrange             = 255, 140, 0
    DarkOrchid             = 153, 50, 204
    DarkPastelGreen        = 3, 192, 60
    DarkPink               = 222, 93, 131
    DarkPurple             = 150, 61, 127
    DarkRed                = 139, 0, 0
    DarkSalmon             = 233, 150, 122
    DarkSeaGreen           = 143, 188, 143
    DarkSlateBlue          = 72, 61, 139
    DarkSlateGray          = 47, 79, 79
    DarkSlateGrey          = 47, 79, 79
    DarkSpringGreen        = 23, 114, 69
    DarkTangerine          = 255, 170, 29
    DarkTurquoise          = 0, 206, 209
    DarkViolet             = 148, 0, 211
    DarkWood               = 130, 102, 68
    DeepBlush              = 245, 105, 145
    DeepCerise             = 224, 33, 138
    DeepKoamaru            = 51, 51, 102
    DeepLilac              = 153, 85, 187
    DeepMagenta            = 204, 0, 204
    DeepPink               = 255, 20, 147
    DeepSea                = 14, 124, 97
    DeepSkyBlue            = 0, 191, 255
    DeepTeal               = 24, 69, 59
    Denim                  = 36, 107, 206
    DesertSand             = 237, 201, 175
    DimGray                = 105, 105, 105
    DimGrey                = 105, 105, 105
    DodgerBlue             = 30, 144, 255
    Dolly                  = 242, 242, 122
    Downy                  = 95, 201, 191
    DutchWhite             = 239, 223, 187
    EastBay                = 76, 81, 109
    EastSide               = 178, 132, 190
    EchoBlue               = 169, 178, 195
    Ecru                   = 194, 178, 128
    Eggplant               = 162, 0, 109
    EgyptianBlue           = 16, 52, 166
    ElectricBlue           = 125, 249, 255
    ElectricIndigo         = 111, 0, 255
    ElectricLime           = 208, 255, 20
    ElectricPurple         = 191, 0, 255
    Elm                    = 47, 132, 124
    Emerald                = 80, 200, 120
    Eminence               = 108, 48, 130
    Endeavour              = 46, 88, 148
    EnergyYellow           = 245, 224, 80
    Espresso               = 74, 44, 42
    Eucalyptus             = 26, 162, 96
    Falcon                 = 126, 94, 96
    Fallow                 = 204, 153, 102
    FaluRed                = 128, 24, 24
    Feldgrau               = 77, 93, 83
    Feldspar               = 205, 149, 117
    Fern                   = 113, 188, 120
    FernGreen              = 79, 121, 66
    Festival               = 236, 213, 64
    Finn                   = 97, 64, 81
    FireBrick              = 178, 34, 34
    FireBush               = 222, 143, 78
    FireEngineRed          = 211, 33, 45
    Flamingo               = 233, 92, 75
    Flax                   = 238, 220, 130
    FloralWhite            = 255, 250, 240
    ForestGreen            = 34, 139, 34
    Frangipani             = 250, 214, 165
    FreeSpeechAquamarine   = 0, 168, 119
    FreeSpeechRed          = 204, 0, 0
    FrenchLilac            = 230, 168, 215
    FrenchRose             = 232, 83, 149
    FriarGrey              = 135, 134, 129
    Froly                  = 228, 113, 122
    Fuchsia                = 255, 0, 255
    FuchsiaPink            = 255, 119, 255
    Gainsboro              = 220, 220, 220
    Gallery                = 219, 215, 210
    Galliano               = 204, 160, 29
    Gamboge                = 204, 153, 0
    Ghost                  = 196, 195, 208
    GhostWhite             = 248, 248, 255
    Gin                    = 216, 228, 188
    GinFizz                = 247, 231, 206
    Givry                  = 230, 208, 171
    Glacier                = 115, 169, 194
    Gold                   = 255, 215, 0
    GoldDrop               = 213, 108, 43
    GoldenBrown            = 150, 113, 23
    GoldenFizz             = 240, 225, 48
    GoldenGlow             = 248, 222, 126
    GoldenPoppy            = 252, 194, 0
    Goldenrod              = 218, 165, 32
    GoldenSand             = 233, 214, 107
    GoldenYellow           = 253, 238, 0
    GoldTips               = 225, 189, 39
    GordonsGreen           = 37, 53, 41
    Gorse                  = 255, 225, 53
    Gossamer               = 49, 145, 119
    GrannySmithApple       = 168, 228, 160
    Gray                   = 128, 128, 128
    GrayAsparagus          = 70, 89, 69
    Green                  = 0, 128, 0
    GreenLeaf              = 76, 114, 29
    GreenVogue             = 38, 67, 72
    GreenYellow            = 173, 255, 47
    Grey                   = 128, 128, 128
    GreyAsparagus          = 70, 89, 69
    GuardsmanRed           = 157, 41, 51
    GumLeaf                = 178, 190, 181
    Gunmetal               = 42, 52, 57
    Hacienda               = 155, 135, 12
    HalfAndHalf            = 232, 228, 201
    HalfBaked              = 95, 138, 139
    HalfColonialWhite      = 246, 234, 190
    HalfPearlLusta         = 240, 234, 214
    HanPurple              = 63, 0, 255
    Harlequin              = 74, 255, 0
    HarleyDavidsonOrange   = 194, 59, 34
    Heather                = 174, 198, 207
    Heliotrope             = 223, 115, 255
    Hemp                   = 161, 122, 116
    Highball               = 134, 126, 54
    HippiePink             = 171, 75, 82
    Hoki                   = 110, 127, 128
    HollywoodCerise        = 244, 0, 161
    Honeydew               = 240, 255, 240
    Hopbush                = 207, 113, 175
    HorsesNeck             = 108, 84, 30
    HotPink                = 255, 105, 180
    HummingBird            = 201, 255, 229
    HunterGreen            = 53, 94, 59
    Illusion               = 244, 152, 173
    InchWorm               = 202, 224, 13
    IndianRed              = 205, 92, 92
    Indigo                 = 75, 0, 130
    InternationalKleinBlue = 0, 24, 168
    InternationalOrange    = 255, 79, 0
    IrisBlue               = 28, 169, 201
    IrishCoffee            = 102, 66, 40
    IronsideGrey           = 113, 112, 110
    IslamicGreen           = 0, 144, 0
    Ivory                  = 255, 255, 240
    Jacarta                = 61, 50, 93
    JackoBean              = 65, 54, 40
    JacksonsPurple         = 46, 45, 136
    Jade                   = 0, 171, 102
    JapaneseLaurel         = 47, 117, 50
    Jazz                   = 93, 43, 44
    JazzberryJam           = 165, 11, 94
    JellyBean              = 68, 121, 142
    JetStream              = 187, 208, 201
    Jewel                  = 0, 107, 60
    Jon                    = 79, 58, 60
    JordyBlue              = 124, 185, 232
    Jumbo                  = 132, 132, 130
    JungleGreen            = 41, 171, 135
    KaitokeGreen           = 30, 77, 43
    Karry                  = 255, 221, 202
    KellyGreen             = 70, 203, 24
    Keppel                 = 93, 164, 147
    Khaki                  = 240, 230, 140
    Killarney              = 77, 140, 87
    KingfisherDaisy        = 85, 27, 140
    Kobi                   = 230, 143, 172
    LaPalma                = 60, 141, 13
    LaserLemon             = 252, 247, 94
    Laurel                 = 103, 146, 103
    Lavender               = 230, 230, 250
    LavenderBlue           = 204, 204, 255
    LavenderBlush          = 255, 240, 245
    LavenderPink           = 251, 174, 210
    LavenderRose           = 251, 160, 227
    LawnGreen              = 124, 252, 0
    LemonChiffon           = 255, 250, 205
    LightBlue              = 173, 216, 230
    LightCoral             = 240, 128, 128
    LightCyan              = 224, 255, 255
    LightGoldenrodYellow   = 250, 250, 210
    LightGray              = 211, 211, 211
    LightGreen             = 144, 238, 144
    LightGrey              = 211, 211, 211
    LightPink              = 255, 182, 193
    LightSalmon            = 255, 160, 122
    LightSeaGreen          = 32, 178, 170
    LightSkyBlue           = 135, 206, 250
    LightSlateGray         = 119, 136, 153
    LightSlateGrey         = 119, 136, 153
    LightSteelBlue         = 176, 196, 222
    LightYellow            = 255, 255, 224
    Lilac                  = 204, 153, 204
    Lime                   = 0, 255, 0
    LimeGreen              = 50, 205, 50
    Limerick               = 139, 190, 27
    Linen                  = 250, 240, 230
    Lipstick               = 159, 43, 104
    Liver                  = 83, 75, 79
    Lochinvar              = 86, 136, 125
    Lochmara               = 38, 97, 156
    Lola                   = 179, 158, 181
    LondonHue              = 170, 152, 169
    Lotus                  = 124, 72, 72
    LuckyPoint             = 29, 41, 81
    MacaroniAndCheese      = 255, 189, 136
    Madang                 = 193, 249, 162
    Madras                 = 81, 65, 0
    Magenta                = 255, 0, 255
    MagicMint              = 170, 240, 209
    Magnolia               = 248, 244, 255
    Mahogany               = 215, 59, 62
    Maire                  = 27, 24, 17
    Maize                  = 230, 190, 138
    Malachite              = 11, 218, 81
    Malibu                 = 93, 173, 236
    Malta                  = 169, 154, 134
    Manatee                = 140, 146, 172
    Mandalay               = 176, 121, 57
    MandarianOrange        = 146, 39, 36
    Mandy                  = 191, 79, 81
    Manhattan              = 229, 170, 112
    Mantis                 = 125, 194, 66
    Manz                   = 217, 230, 80
    MardiGras              = 48, 25, 52
    Mariner                = 57, 86, 156
    Maroon                 = 128, 0, 0
    Matterhorn             = 85, 85, 85
    Mauve                  = 244, 187, 255
    Mauvelous              = 255, 145, 175
    MauveTaupe             = 143, 89, 115
    MayaBlue               = 119, 181, 254
    McKenzie               = 129, 97, 60
    MediumAquamarine       = 102, 205, 170
    MediumBlue             = 0, 0, 205
    MediumCarmine          = 175, 64, 53
    MediumOrchid           = 186, 85, 211
    MediumPurple           = 147, 112, 219
    MediumRedViolet        = 189, 51, 164
    MediumSeaGreen         = 60, 179, 113
    MediumSlateBlue        = 123, 104, 238
    MediumSpringGreen      = 0, 250, 154
    MediumTurquoise        = 72, 209, 204
    MediumVioletRed        = 199, 21, 133
    MediumWood             = 166, 123, 91
    Melon                  = 253, 188, 180
    Merlot                 = 112, 54, 66
    MetallicGold           = 211, 175, 55
    Meteor                 = 184, 115, 51
    MidnightBlue           = 25, 25, 112
    MidnightExpress        = 0, 20, 64
    Mikado                 = 60, 52, 31
    MilanoRed              = 168, 55, 49
    Ming                   = 54, 116, 125
    MintCream              = 245, 255, 250
    MintGreen              = 152, 255, 152
    Mischka                = 168, 169, 173
    MistyRose              = 255, 228, 225
    Moccasin               = 255, 228, 181
    Mojo                   = 149, 69, 53
    MonaLisa               = 255, 153, 153
    Mongoose               = 179, 139, 109
    Montana                = 53, 56, 57
    MoodyBlue              = 116, 108, 192
    MoonYellow             = 245, 199, 26
    MossGreen              = 173, 223, 173
    MountainMeadow         = 28, 172, 120
    MountainMist           = 161, 157, 148
    MountbattenPink        = 153, 122, 141
    Mulberry               = 211, 65, 157
    Mustard                = 255, 219, 88
    Myrtle                 = 25, 89, 5
    MySin                  = 255, 179, 71
    NavajoWhite            = 255, 222, 173
    Navy                   = 0, 0, 128
    NavyBlue               = 2, 71, 254
    NeonCarrot             = 255, 153, 51
    NeonPink               = 255, 92, 205
    Nepal                  = 145, 163, 176
    Nero                   = 20, 20, 20
    NewMidnightBlue        = 0, 0, 156
    Niagara                = 58, 176, 158
    NightRider             = 59, 47, 47
    Nobel                  = 152, 152, 152
    Norway                 = 169, 186, 157
    Nugget                 = 183, 135, 39
    OceanGreen             = 95, 167, 120
    Ochre                  = 202, 115, 9
    OldCopper              = 111, 78, 55
    OldGold                = 207, 181, 59
    OldLace                = 253, 245, 230
    OldLavender            = 121, 104, 120
    OldRose                = 195, 33, 72
    Olive                  = 128, 128, 0
    OliveDrab              = 107, 142, 35
    OliveGreen             = 181, 179, 92
    Olivetone              = 110, 110, 48
    Olivine                = 154, 185, 115
    Onahau                 = 196, 216, 226
    Opal                   = 168, 195, 188
    Orange                 = 255, 165, 0
    OrangePeel             = 251, 153, 2
    OrangeRed              = 255, 69, 0
    Orchid                 = 218, 112, 214
    OuterSpace             = 45, 56, 58
    OutrageousOrange       = 254, 90, 29
    Oxley                  = 95, 167, 119
    PacificBlue            = 0, 136, 220
    Padua                  = 128, 193, 151
    PalatinatePurple       = 112, 41, 99
    PaleBrown              = 160, 120, 90
    PaleChestnut           = 221, 173, 175
    PaleCornflowerBlue     = 188, 212, 230
    PaleGoldenrod          = 238, 232, 170
    PaleGreen              = 152, 251, 152
    PaleMagenta            = 249, 132, 239
    PalePink               = 250, 218, 221
    PaleSlate              = 201, 192, 187
    PaleTaupe              = 188, 152, 126
    PaleTurquoise          = 175, 238, 238
    PaleVioletRed          = 219, 112, 147
    PalmLeaf               = 53, 66, 48
    Panache                = 233, 255, 219
    PapayaWhip             = 255, 239, 213
    ParisDaisy             = 255, 244, 79
    Parsley                = 48, 96, 48
    PastelGreen            = 119, 221, 119
    PattensBlue            = 219, 233, 244
    Peach                  = 255, 203, 164
    PeachOrange            = 255, 204, 153
    PeachPuff              = 255, 218, 185
    PeachYellow            = 250, 223, 173
    Pear                   = 209, 226, 49
    PearlLusta             = 234, 224, 200
    Pelorous               = 42, 143, 189
    Perano                 = 172, 172, 230
    Periwinkle             = 197, 203, 225
    PersianBlue            = 34, 67, 182
    PersianGreen           = 0, 166, 147
    PersianIndigo          = 51, 0, 102
    PersianPink            = 247, 127, 190
    PersianRed             = 192, 54, 44
    PersianRose            = 233, 54, 167
    Persimmon              = 236, 88, 0
    Peru                   = 205, 133, 63
    Pesto                  = 128, 117, 50
    PictonBlue             = 102, 153, 204
    PigmentGreen           = 0, 173, 67
    PigPink                = 255, 218, 233
    PineGreen              = 1, 121, 111
    PineTree               = 42, 47, 35
    Pink                   = 255, 192, 203
    PinkFlare              = 191, 175, 178
    PinkLace               = 240, 211, 220
    PinkSwan               = 179, 179, 179
    Plum                   = 221, 160, 221
    Pohutukawa             = 102, 12, 33
    PoloBlue               = 119, 158, 203
    Pompadour              = 129, 20, 83
    Portage                = 146, 161, 207
    PotPourri              = 241, 221, 207
    PottersClay            = 132, 86, 60
    PowderBlue             = 176, 224, 230
    Prim                   = 228, 196, 207
    PrussianBlue           = 0, 58, 108
    PsychedelicPurple      = 223, 0, 255
    Puce                   = 204, 136, 153
    Pueblo                 = 108, 46, 31
    PuertoRico             = 67, 179, 174
    Pumpkin                = 255, 99, 28
    Purple                 = 128, 0, 128
    PurpleMountainsMajesty = 150, 123, 182
    PurpleTaupe            = 93, 57, 84
    QuarterSpanishWhite    = 230, 224, 212
    Quartz                 = 220, 208, 255
    Quincy                 = 106, 84, 69
    RacingGreen            = 26, 36, 33
    RadicalRed             = 255, 32, 82
    Rajah                  = 251, 171, 96
    RawUmber               = 123, 63, 0
    RazzleDazzleRose       = 254, 78, 218
    Razzmatazz             = 215, 10, 83
    Red                    = 255, 0, 0
    RedBerry               = 132, 22, 23
    RedDamask              = 203, 109, 81
    RedOxide               = 99, 15, 15
    RedRobin               = 128, 64, 64
    RichBlue               = 84, 90, 167
    Riptide                = 141, 217, 204
    RobinsEggBlue          = 0, 204, 204
    RobRoy                 = 225, 169, 95
    RockSpray              = 171, 56, 31
    RomanCoffee            = 131, 105, 83
    RoseBud                = 246, 164, 148
    RoseBudCherry          = 135, 50, 96
    RoseTaupe              = 144, 93, 93
    RosyBrown              = 188, 143, 143
    Rouge                  = 176, 48, 96
    RoyalBlue              = 65, 105, 225
    RoyalHeath             = 168, 81, 110
    RoyalPurple            = 102, 51, 152
    Ruby                   = 215, 24, 104
    Russet                 = 128, 70, 27
    Rust                   = 192, 64, 0
    RusticRed              = 72, 6, 7
    Saddle                 = 99, 81, 71
    SaddleBrown            = 139, 69, 19
    SafetyOrange           = 255, 102, 0
    Saffron                = 244, 196, 48
    Sage                   = 143, 151, 121
    Sail                   = 161, 202, 241
    Salem                  = 0, 133, 67
    Salmon                 = 250, 128, 114
    SandyBeach             = 253, 213, 177
    SandyBrown             = 244, 164, 96
    Sangria                = 134, 1, 17
    SanguineBrown          = 115, 54, 53
    SanMarino              = 80, 114, 167
    SanteFe                = 175, 110, 77
    Sapphire               = 6, 42, 120
    Saratoga               = 84, 90, 44
    Scampi                 = 102, 102, 153
    Scarlet                = 255, 36, 0
    ScarletGum             = 67, 28, 83
    SchoolBusYellow        = 255, 216, 0
    Schooner               = 139, 134, 128
    ScreaminGreen          = 102, 255, 102
    Scrub                  = 59, 60, 54
    SeaBuckthorn           = 249, 146, 69
    SeaGreen               = 46, 139, 87
    Seagull                = 140, 190, 214
    SealBrown              = 61, 12, 2
    Seance                 = 96, 47, 107
    SeaPink                = 215, 131, 127
    SeaShell               = 255, 245, 238
    Selago                 = 250, 230, 250
    SelectiveYellow        = 242, 180, 0
    SemiSweetChocolate     = 107, 68, 35
    Sepia                  = 150, 90, 62
    Serenade               = 255, 233, 209
    Shadow                 = 133, 109, 77
    Shakespeare            = 114, 160, 193
    Shalimar               = 252, 255, 164
    Shamrock               = 68, 215, 168
    ShamrockGreen          = 0, 153, 102
    SherpaBlue             = 0, 75, 73
    SherwoodGreen          = 27, 77, 62
    Shilo                  = 222, 165, 164
    ShipCove               = 119, 139, 165
    Shocking               = 241, 156, 187
    ShockingPink           = 255, 29, 206
    ShuttleGrey            = 84, 98, 111
    Sidecar                = 238, 224, 177
    Sienna                 = 160, 82, 45
    Silk                   = 190, 164, 147
    Silver                 = 192, 192, 192
    SilverChalice          = 175, 177, 174
    SilverTree             = 102, 201, 146
    SkyBlue                = 135, 206, 235
    SlateBlue              = 106, 90, 205
    SlateGray              = 112, 128, 144
    SlateGrey              = 112, 128, 144
    Smalt                  = 0, 48, 143
    SmaltBlue              = 74, 100, 108
    Snow                   = 255, 250, 250
    SoftAmber              = 209, 190, 168
    Solitude               = 235, 236, 240
    Sorbus                 = 233, 105, 44
    Spectra                = 53, 101, 77
    SpicyMix               = 136, 101, 78
    Spray                  = 126, 212, 230
    SpringBud              = 150, 255, 0
    SpringGreen            = 0, 255, 127
    SpringSun              = 236, 235, 189
    SpunPearl              = 170, 169, 173
    Stack                  = 130, 142, 132
    SteelBlue              = 70, 130, 180
    Stiletto               = 137, 63, 69
    Strikemaster           = 145, 92, 131
    StTropaz               = 50, 82, 123
    Studio                 = 115, 79, 150
    Sulu                   = 201, 220, 135
    SummerSky              = 33, 171, 205
    Sun                    = 237, 135, 45
    Sundance               = 197, 179, 88
    Sunflower              = 228, 208, 10
    Sunglow                = 255, 204, 51
    SunsetOrange           = 253, 82, 64
    SurfieGreen            = 0, 116, 116
    Sushi                  = 111, 153, 64
    SuvaGrey               = 140, 140, 140
    Swamp                  = 35, 43, 43
    SweetCorn              = 253, 219, 109
    SweetPink              = 243, 153, 152
    Tacao                  = 236, 177, 118
    TahitiGold             = 235, 97, 35
    Tan                    = 210, 180, 140
    Tangaroa               = 0, 28, 61
    Tangerine              = 228, 132, 0
    TangerineYellow        = 253, 204, 13
    Tapestry               = 183, 110, 121
    Taupe                  = 72, 60, 50
    TaupeGrey              = 139, 133, 137
    TawnyPort              = 102, 66, 77
    TaxBreak               = 79, 102, 106
    TeaGreen               = 208, 240, 192
    Teak                   = 176, 141, 87
    Teal                   = 0, 128, 128
    TeaRose                = 255, 133, 207
    Temptress              = 60, 20, 33
    Tenne                  = 200, 101, 0
    TerraCotta             = 226, 114, 91
    Thistle                = 216, 191, 216
    TickleMePink           = 245, 111, 161
    Tidal                  = 232, 244, 140
    TitanWhite             = 214, 202, 221
    Toast                  = 165, 113, 100
    Tomato                 = 255, 99, 71
    TorchRed               = 255, 3, 62
    ToryBlue               = 54, 81, 148
    Tradewind              = 110, 174, 161
    TrendyPink             = 133, 96, 136
    TropicalRainForest     = 0, 127, 102
    TrueV                  = 139, 114, 190
    TulipTree              = 229, 183, 59
    Tumbleweed             = 222, 170, 136
    Turbo                  = 255, 195, 36
    TurkishRose            = 152, 119, 123
    Turquoise              = 64, 224, 208
    TurquoiseBlue          = 118, 215, 234
    Tuscany                = 175, 89, 62
    TwilightBlue           = 253, 255, 245
    Twine                  = 186, 135, 89
    TyrianPurple           = 102, 2, 60
    Ultramarine            = 10, 17, 149
    UltraPink              = 255, 111, 255
    Valencia               = 222, 82, 70
    VanCleef               = 84, 61, 55
    VanillaIce             = 229, 204, 201
    VenetianRed            = 209, 0, 28
    Venus                  = 138, 127, 128
    Vermilion              = 251, 79, 20
    VeryLightGrey          = 207, 207, 207
    VidaLoca               = 94, 140, 49
    Viking                 = 71, 171, 204
    Viola                  = 180, 131, 149
    ViolentViolet          = 50, 23, 77
    Violet                 = 238, 130, 238
    VioletRed              = 255, 57, 136
    Viridian               = 64, 130, 109
    VistaBlue              = 159, 226, 191
    VividViolet            = 127, 62, 152
    WaikawaGrey            = 83, 104, 149
    Wasabi                 = 150, 165, 60
    Watercourse            = 0, 106, 78
    Wedgewood              = 67, 107, 149
    WellRead               = 147, 61, 65
    Wewak                  = 255, 152, 153
    Wheat                  = 245, 222, 179
    Whiskey                = 217, 154, 108
    WhiskeySour            = 217, 144, 88
    White                  = 255, 255, 255
    WhiteSmoke             = 245, 245, 245
    WildRice               = 228, 217, 111
    WildSand               = 229, 228, 226
    WildStrawberry         = 252, 65, 154
    WildWatermelon         = 255, 84, 112
    WildWillow             = 172, 191, 96
    Windsor                = 76, 40, 130
    Wisteria               = 191, 148, 228
    Wistful                = 162, 162, 208
    Yellow                 = 255, 255, 0
    YellowGreen            = 154, 205, 50
    YellowOrange           = 255, 174, 66
    YourPink               = 244, 194, 194
}
$Script:ScriptBlockColors = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    $Script:RGBColors.Keys | Where-Object { $_ -like "*$wordToComplete*" }
}
# Validation for Actions
$Script:PDFAction = {
    ([iText.Kernel.Pdf.Action.PdfAction] | Get-Member -Static -MemberType Property).Name
}
$Script:PDFActionValidation = {
    $Array = @(
        (& $Script:PDFAction)
        ''
    )
    $_ -in $Array
}

function Get-PDFConstantAction {
    [CmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFActionValidation } )][string] $Action
    )
    return [iText.Kernel.Pdf.Action.PdfAction]::$Action
}

Register-ArgumentCompleter -CommandName Get-PDFConstantAction -ParameterName Action -ScriptBlock $Script:PDFAction
# Validation for Colors
$Script:PDFColor = {
    ([iText.Kernel.Colors.ColorConstants] | Get-Member -Static -MemberType Property).Name
}
$Script:PDFColorValidation = {
    $Array = @(
        (& $Script:PDFColor)
        ''
    )
    $_ -in $Array
}

function Get-PDFConstantColor {
    [CmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFColorValidation } )][string] $Color
    )
    return [iText.Kernel.Colors.ColorConstants]::$Color
}

Register-ArgumentCompleter -CommandName Get-PDFConstantColor -ParameterName Color -ScriptBlock $Script:PDFColor
function Get-PDFConstantFont {
    [CmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFFontValidation } )][string] $Font
    )
    return [iText.IO.Font.Constants.StandardFonts]::$Font
}

Register-ArgumentCompleter -CommandName Get-PDFConstantFont -ParameterName Font -ScriptBlock $Script:PDFFont
# Validation for PageSize
$Script:PDFPageSize = {
    ([iText.Kernel.Geom.PageSize] | Get-Member -Static -MemberType Property).Name
}
$Script:PDFPageSizeValidation = {
    # Empty element is added to allow no parameter value
    $Array = @(
        (& $Script:PDFPageSize)
        ''
    )
    $_ -in $Array
}

function Get-PDFConstantPageSize {
    [CmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFPageSizeValidation } )][string] $PageSize,
        [switch] $All
    )
    if (-not $All) {
        return [iText.Kernel.Geom.PageSize]::$PageSize
    } else {
        return & $Script:PDFPageSize
    }
}

Register-ArgumentCompleter -CommandName Get-PDFConstantPageSize  -ParameterName Version -ScriptBlock $Script:PDFPageSize
# Validation for Fonts
$Script:PDFVersion = {
    ([iText.Kernel.Pdf.PdfVersion] | Get-Member -Static -MemberType Property).Name
}
$Script:PDFVersionValidation = {
    $Array = @(
        (& $Script:PDFVersion)
        ''
    )
    $_ -in $Array
}

function Get-PDFConstantVersion {
    [CmdletBinding()]
    param(
        [ValidateScript( { & $Script:PDFVersionValidation } )][string] $Version
    )
    return [iText.Kernel.Pdf.PdfVersion]::$Version
}

Register-ArgumentCompleter -CommandName Get-PDFConstantVersion -ParameterName Version -ScriptBlock $Script:PDFVersion
function Convert-HTMLToPDF {
    <#
    .SYNOPSIS
    Converts HTML to PDF.
 
    .DESCRIPTION
    Converts HTML to PDF from one of three sources:
    1. A file on the local file system.
    2. A URL.
    3. A string of HTML.
 
    .PARAMETER Uri
    The URI of the HTML to convert.
 
    .PARAMETER Content
    The HTML (as a string) to convert.
 
    .PARAMETER FilePath
    The path to the file containing the HTML to convert.
 
    .PARAMETER OutputFilePath
    The path to the file to write the PDF to.
 
    .PARAMETER Open
    If true, opens the PDF after it is created.
 
    .EXAMPLE
    Convert-HTMLToPDF -Uri 'https://evotec.xyz/hub/scripts/pswritehtml-powershell-module/' -OutputFilePath "$PSScriptRoot\Example10-FromURL.pdf" -Open
 
    .EXAMPLE
    $HTMLInput = New-HTML {
        New-HTMLText -Text 'Test 1'
        New-HTMLTable -DataTable (Get-Process | Select-Object -First 3)
    }
 
    Convert-HTMLToPDF -Content $HTMLInput -OutputFilePath "$PSScriptRoot\Example10-FromHTML.pdf" -Open
 
    .EXAMPLE
    New-HTML {
        New-HTMLTable -DataTable (Get-Process | Select-Object -First 3)
    } -FilePath "$PSScriptRoot\Example10-FromFilePath.html" -Online
 
    Convert-HTMLToPDF -FilePath "$PSScriptRoot\Example10-FromFilePath.html" -OutputFilePath "$PSScriptRoot\Example10-FromFilePath.pdf" -Open
 
    .NOTES
    General notes
    #>

    [CmdletBinding(DefaultParameterSetName = 'Uri')]
    param(
        [Parameter(Mandatory, ParameterSetName = 'Uri')][alias('Url')][string] $Uri,
        [Parameter(Mandatory, ParameterSetName = 'Content')][string] $Content,
        [Parameter(Mandatory, ParameterSetName = 'FilePath')][string] $FilePath,
        [Parameter(Mandatory)][string] $OutputFilePath,
        [switch] $Open
    )
    # Load from file or text
    if ($FilePath) {
        if (Test-Path -LiteralPath $FilePath) {
            $Content = [IO.File]::ReadAllText($FilePath)
        } else {
            Write-Warning "Convert-HTMLToPDF - File $FilePath doesn't exists"
            return
        }
    } elseif ($Content) {

    } elseif ($Uri) {
        $ProgressPreference = 'SilentlyContinue'
        $Content = (Invoke-WebRequest -Uri $Uri).Content
    } else {
        Write-Warning 'Convert-HTMLToPDF - No choice file or content or url. Termninated.'
        return
    }
    if (-not $Content) {
        return
    }

    $OutputFile = [System.IO.FileInfo]::new($OutputFilePath)
    <#
    static void ConvertToPdf(string html, System.IO.Stream pdfStream)
    static void ConvertToPdf(string html, System.IO.Stream pdfStream, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(string html, iText.Kernel.Pdf.PdfWriter pdfWriter)
    static void ConvertToPdf(string html, iText.Kernel.Pdf.PdfWriter pdfWriter, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(string html, iText.Kernel.Pdf.PdfDocument pdfDocument, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(System.IO.FileInfo htmlFile, System.IO.FileInfo pdfFile)
    static void ConvertToPdf(System.IO.FileInfo htmlFile, System.IO.FileInfo pdfFile, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(System.IO.Stream htmlStream, System.IO.Stream pdfStream)
    static void ConvertToPdf(System.IO.Stream htmlStream, System.IO.Stream pdfStream, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(System.IO.Stream htmlStream, iText.Kernel.Pdf.PdfDocument pdfDocument)
    static void ConvertToPdf(System.IO.Stream htmlStream, iText.Kernel.Pdf.PdfWriter pdfWriter)
    static void ConvertToPdf(System.IO.Stream htmlStream, iText.Kernel.Pdf.PdfWriter pdfWriter, iText.Html2pdf.ConverterProperties converterProperties)
    static void ConvertToPdf(System.IO.Stream htmlStream, iText.Kernel.Pdf.PdfDocument pdfDocument, iText.Html2pdf.ConverterProperties converterProperties)
    #>

    try {
        [iText.Html2pdf.HtmlConverter]::ConvertToPdf($Content, $OutputFile)
    } catch {
        Write-Warning "Convert-HTMLToPDF - Error converting to PDF. Error: $($_.Exception.Message)"
        return
    }
    if ($Open) {
        Start-Process -FilePath $OutputFilePath -Wait
    }
}
function Convert-PDFToText {
    <#
    .SYNOPSIS
    Converts PDF to TEXT
 
    .DESCRIPTION
    Converts PDF to TEXT
 
    .PARAMETER FilePath
    The path to the PDF file to convert
 
    .PARAMETER Page
    The page number to convert (default is all pages)
 
    .PARAMETER ExtractionStrategy
    The iText Extractiostrategey that is used to parse the text. Currently supports LocationTextExtractionStrategy (LT) and SimpleTextExtractionStrategy (ST)(Default).
     
    .PARAMETER IgnoreProtection
    The switch will allow reading of PDF files that are "owner password" encrypted for protection/security (e.g. preventing copying of text, printing etc).
    The switch doesn't allow reading of PDF files that are "user password" encrypted (i.e. you cannot open them without the password)
 
    .EXAMPLE
    # Get all pages text
    Convert-PDFToText -FilePath "$PSScriptRoot\Example04.pdf"
     
    .EXAMPLE
    # Get all pages text with Location-Extractionstrategy
    Convert-PDFToText -FilePath "$PSScriptRoot\Example04.pdf" -ExtractionStrategy "LT"
 
    .EXAMPLE
    # Get page 1 text only
    Convert-PDFToText -FilePath "$PSScriptRoot\Example04.pdf" -Page 1
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param(
        [string] $FilePath,
        [int[]] $Page,
        [ValidateSet("SimpleTextExtractionStrategy", "LocationTextExtractionStrategy", "ST", "LT")]
        [string] $ExtractionStrategy = "SimpleTextExtractionStrategy",
        [switch] $IgnoreProtection
    )
    if ($FilePath -and (Test-Path -LiteralPath $FilePath)) {
        $ResolvedPath = Convert-Path -LiteralPath $FilePath
        $Source = [iText.Kernel.Pdf.PdfReader]::new($ResolvedPath)
        if ($IgnoreProtection) {
            $null = $Source.SetUnethicalReading($true)
        }
        try {
            [iText.Kernel.Pdf.PdfDocument] $SourcePDF = [iText.Kernel.Pdf.PdfDocument]::new($Source);
            if ($ExtractionStrategy -eq "SimpleTextExtractionStrategy" -or $ExtractionStrategy -eq "ST") {
                [iText.Kernel.Pdf.Canvas.Parser.Listener.SimpleTextExtractionStrategy] $iTextExtractionStrategy = [iText.Kernel.Pdf.Canvas.Parser.Listener.SimpleTextExtractionStrategy]::new()
            } elseif ($ExtractionStrategy -eq "LocationTextExtractionStrategy" -or $ExtractionStrategy -eq "LT") {
                [iText.Kernel.Pdf.Canvas.Parser.Listener.LocationTextExtractionStrategy] $iTextExtractionStrategy = [iText.Kernel.Pdf.Canvas.Parser.Listener.LocationTextExtractionStrategy]::new()
            }
        } catch {
            $ErrorMessage = $_.Exception.Message
            Write-Warning "Convert-PDFToText - Processing document $ResolvedPath failed with error: $ErrorMessage"
        }

        $PagesCount = $SourcePDF.GetNumberOfPages()
        if ($Page.Count -eq 0) {
            for ($Count = 1; $Count -le $PagesCount; $Count++) {
                try {
                    $ExtractedPage = $SourcePDF.GetPage($Count)
                    [iText.Kernel.Pdf.Canvas.Parser.PdfTextExtractor]::GetTextFromPage($ExtractedPage, $iTextExtractionStrategy)
                } catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Warning "Convert-PDFToText - Processing document $ResolvedPath failed with error: $ErrorMessage"
                }
            }
        } else {
            foreach ($Count in $Page) {
                if ($Count -le $PagesCount -and $Count -gt 0) {
                    try {
                        $ExtractedPage = $SourcePDF.GetPage($Count)
                        [iText.Kernel.Pdf.Canvas.Parser.PdfTextExtractor]::GetTextFromPage($ExtractedPage, $iTextExtractionStrategy)
                    } catch {
                        $ErrorMessage = $_.Exception.Message
                        Write-Warning "Convert-PDFToText - Processing document $ResolvedPath failed with error: $ErrorMessage"
                    }
                } else {
                    Write-Warning "Convert-PDFToText - File $ResolvedPath doesn't contain page number $Count. Skipping."
                }
            }
        }
        try {
            $SourcePDF.Close()
        } catch {
            $ErrorMessage = $_.Exception.Message
            Write-Warning "Convert-PDFToText - Closing document $FilePath failed with error: $ErrorMessage"
        }
    } else {
        Write-Warning "Convert-PDFToText - Path $FilePath doesn't exists. Terminating."
    }
}

function Merge-PDF {
    <#
    .SYNOPSIS
    Merge PDF files into one.
 
    .DESCRIPTION
    Merge PDF files into one.
 
    .PARAMETER InputFile
    The PDF files to be merged.
 
    .PARAMETER OutputFile
    The output file path.
 
    .PARAMETER IgnoreProtection
    The switch will allow reading of PDF files that are "owner password" encrypted for protection/security (e.g. preventing copying of text, printing etc).
    The switch doesn't allow reading of PDF files that are "user password" encrypted (i.e. you cannot open them without the password)
 
    .EXAMPLE
    $FilePath1 = "$PSScriptRoot\Input\OutputDocument0.pdf"
    $FilePath2 = "$PSScriptRoot\Input\OutputDocument1.pdf"
 
    $OutputFile = "$PSScriptRoot\Output\OutputDocument.pdf" # Shouldn't exist / will be overwritten
 
    Merge-PDF -InputFile $FilePath1, $FilePath2 -OutputFile $OutputFile
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param(
        [string[]] $InputFile,
        [string] $OutputFile,
        [switch] $IgnoreProtection
    )

    if ($OutputFile) {
        try {
            [iText.Kernel.Pdf.PdfWriter] $Writer = [iText.Kernel.Pdf.PdfWriter]::new($OutputFile)
            [iText.Kernel.Pdf.PdfDocument] $PDF = [iText.Kernel.Pdf.PdfDocument]::new($Writer);
            [iText.Kernel.Utils.PdfMerger] $Merger = [iText.Kernel.Utils.PdfMerger]::new($PDF)
        } catch {
            $ErrorMessage = $_.Exception.Message
            Write-Warning "Merge-PDF - Processing document $OutputFile failed with error: $ErrorMessage"
        }
        foreach ($File in $InputFile) {
            if ($File -and (Test-Path -LiteralPath $File)) {
                $ResolvedFile = Convert-Path -LiteralPath $File
                try {
                    $Source = [iText.Kernel.Pdf.PdfReader]::new($ResolvedFile)
                    if ($IgnoreProtection) {
                        $null = $Source.SetUnethicalReading($true)
                    }
                    [iText.Kernel.Pdf.PdfDocument] $SourcePDF = [iText.Kernel.Pdf.PdfDocument]::new($Source);
                    $null = $Merger.merge($SourcePDF, 1, $SourcePDF.getNumberOfPages())
                    $SourcePDF.close()
                } catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Warning "Merge-PDF - Processing document $ResolvedFile failed with error: $ErrorMessage"
                }
            }
        }
        try {
            $PDF.Close()
        } catch {
            $ErrorMessage = $_.Exception.Message
            Write-Warning "Merge-PDF - Saving document $OutputFile failed with error: $ErrorMessage"
        }
    } else {
        Write-Warning "Merge-PDF - Output file was empty. Please give a name to file. Terminating."
    }
}
function Set-PDFForm {
    <#
    .SYNOPSIS
    Will try to fill form fields in source PDF with values from hash table.
    Can also flatten the form to prevent changes with -flatten.
 
    .DESCRIPTION
    Adds a file name extension to a supplied name.
    Takes any strings for the file name or extension.
 
    .PARAMETER SourceFilePath
    Specifies the to be filled in PDF Form.
 
    .PARAMETER DestinationFilePath
    Specifies the output filepath for the completed form.
 
    .PARAMETER FieldNameAndValueHashTable
    Specifies the hashtable for the fields data. Key in the hashtable needs to match the feild name in the PDF.
 
    .PARAMETER Flatten
    Will flatten the output PDF so form fields will no longer be able to be changed.
 
    .PARAMETER IgnoreProtection
    The switch will allow reading of PDF files that are "owner password" encrypted for protection/security (e.g. preventing copying of text, printing etc).
    The switch doesn't allow reading of PDF files that are "user password" encrypted (i.e. you cannot open them without the password)
 
    .EXAMPLE
    $FilePath = [IO.Path]::Combine("$PSScriptRoot", "Output", "SampleAcroFormOutput.pdf")
    $FilePathSource = [IO.Path]::Combine("$PSScriptRoot", "Input", "SampleAcroForm.pdf")
 
    $FieldNameAndValueHashTable = [ordered] @{
        "Text 1" = "Text 1 input"
        "Text 2" = "Text 2 input"
        "Text 3" = "Text 3 input"
        "Check Box 1 True" = $true
        "Check Box 2 False" = $false
        "Check Box 3 False" = $false
        "Check Box 4 True" = $true
        "Doesn't Exist" = "will not be used"
    }
    Set-PDFForm -SourceFilePath $FilePathSource -DestinationFilePath $FilePath -FieldNameAndValueHashTable $FieldNameAndValueHashTable -Flatten
 
    .EXAMPLE
    $FilePath = [IO.Path]::Combine("$PSScriptRoot", "Output", "SampleAcroFormOutput.pdf")
    $FilePathSource = [IO.Path]::Combine("$PSScriptRoot", "Input", "SampleAcroForm.pdf")
    Set-PDFForm -SourceFilePath $FilePathSource -DestinationFilePath $FilePath -Flatten
 
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][ValidateNotNullOrEmpty()] $SourceFilePath,
        [Parameter(Mandatory)][ValidateNotNullOrEmpty()] $DestinationFilePath,
        [System.Collections.IDictionary] $FieldNameAndValueHashTable,
        [alias('FlattenFields')][Switch] $Flatten,
        [switch] $IgnoreProtection
    )
    $SourceFilePath = Convert-Path -LiteralPath $SourceFilePath
    $DestinationFolder = Split-Path -LiteralPath $DestinationFilePath
    $DestinationFolderPath = Convert-Path -LiteralPath $DestinationFolder -ErrorAction SilentlyContinue

    if ($DestinationFolderPath -and (Test-Path -LiteralPath $SourceFilePath) -and (Test-Path -LiteralPath $DestinationFolderPath)) {
        $File = Split-Path -Path $DestinationFilePath -Leaf
        $DestinationFilePath = Join-Path -Path $DestinationFolderPath -ChildPath $File

        try {
            $Script:Reader = [iText.Kernel.Pdf.PdfReader]::new($SourceFilePath)
            if ($IgnoreProtection) {
                $null = $Script:Reader.SetUnethicalReading($true)
            }
            $Script:Writer = [iText.Kernel.Pdf.PdfWriter]::new($DestinationFilePath)
            $PDF = [iText.Kernel.Pdf.PdfDocument]::new($Script:Reader, $Script:Writer)
            $PDFAcroForm = [iText.Forms.PdfAcroForm]::getAcroForm($PDF, $true)
        } catch {
            Write-Warning "Set-PDFForm - Error has occured: $($_.Exception.Message)"
        }
        foreach ($Key in $FieldNameAndValueHashTable.Keys) {
            $FormField = $PDFAcroForm.getField($Key)
            if ( -not $FormField) {
                Write-Warning "Set-PDFForm - No form field with name '$Key' found"
                continue
            }

            if ($FormField.GetType().Name -match "Button") {
                $null = $FormField.setValue(
                    $FormField.GetAppearanceStates()[[Int]$FieldNameAndValueHashTable[$Key]]
                )
            } else {
                $null = $FormField.setValue($FieldNameAndValueHashTable[$Key])
            }
        }

        if ($Flatten) {
            $PDFAcroForm.flattenFields()
        }

        try {
            $PDF.Close()
        } catch {
            if ($PSBoundParameters.ErrorAction -eq 'Stop') {
                Write-Error $_
                return
            } else {
                $ErrorMessage = $_.Exception.Message
                Write-Warning "Set-PDFForm - Error has occured: $ErrorMessage"
            }
        }
    } else {
        if (-not (Test-Path -LiteralPath $SourceFilePath)) {
            Write-Warning "Set-PDFForm - Path $SourceFilePath doesn't exists. Terminating."
        }

        if (-not (Test-Path -LiteralPath $DestinationFolder)) {
            Write-Warning "Set-PDFForm - Folder $DestinationFolder doesn't exists. Terminating."
        }
    }
}

function Split-PDF {
    <#
    .SYNOPSIS
    Split PDF file into multiple files.
 
    .DESCRIPTION
    Split PDF file into multiple files. The output files will be named based on OutputName variable with appended numbers
 
    .PARAMETER FilePath
    The path to the PDF file to split.
 
    .PARAMETER OutputFolder
    The folder to output the split files to.
 
    .PARAMETER OutputName
    The name of the output files. Default is OutputDocument
 
    .PARAMETER SplitCount
    The number of pages to split the PDF file into. Default is 1
 
    .PARAMETER IgnoreProtection
    The switch will allow reading of PDF files that are "owner password" encrypted for protection/security (e.g. preventing copying of text, printing etc).
    The switch doesn't allow reading of PDF files that are "user password" encrypted (i.e. you cannot open them without the password)
 
    .EXAMPLE
    Split-PDF -FilePath "$PSScriptRoot\SampleToSplit.pdf" -OutputFolder "$PSScriptRoot\Output"
 
    .EXAMPLE
    Split-PDF -FilePath "\\ad1\c$\SampleToSplit.pdf" -OutputFolder "\\ad1\c$\Output"
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string] $FilePath,
        [Parameter(Mandatory)][string] $OutputFolder,
        [string] $OutputName = 'OutputDocument',
        [int] $SplitCount = 1,
        [switch] $IgnoreProtection
    )
    if ($SplitCount -eq 0) {
        Write-Warning "Split-PDF - SplitCount is 0. Terminating."
        return
    }

    if ($FilePath -and (Test-Path -LiteralPath $FilePath)) {
        $ResolvedPath = Convert-Path -LiteralPath $FilePath
        if ($OutputFolder -and (Test-Path -LiteralPath $OutputFolder)) {
            try {
                $PDFFile = [iText.Kernel.Pdf.PdfReader]::new($ResolvedPath)
                if ($IgnoreProtection) {
                    $null = $PDFFile.SetUnethicalReading($true)
                }
                $Document = [iText.Kernel.Pdf.PdfDocument]::new($PDFFile)
                $Splitter = [CustomSplitter]::new($Document, $OutputFolder, $OutputName)
                $List = $Splitter.SplitByPageCount($SplitCount)
                foreach ($_ in $List) {
                    $_.Close()
                }
            } catch {
                $ErrorMessage = $_.Exception.Message
                Write-Warning "Split-PDF - Error has occured: $ErrorMessage"
            }
            try {
                $PDFFile.Close()
            } catch {
                $ErrorMessage = $_.Exception.Message
                Write-Warning "Split-PDF - Closing document $FilePath failed with error: $ErrorMessage"
            }
        } else {
            Write-Warning "Split-PDF - Destination folder $OutputFolder doesn't exists. Terminating."
        }
    } else {
        Write-Warning "Split-PDF - Path $FilePath doesn't exists. Terminating."
    }
}
function Close-PDF {
    [CmdletBinding()]
    param(
        [iText.Kernel.Pdf.PdfDocument] $Document
    )
    if ($Document) {
        $Document.Close()
    }
}
function Get-PDF {
    <#
    .SYNOPSIS
    Gets PDF file and returns it as an PDF object
 
    .DESCRIPTION
    Gets PDF file and returns it as an PDF object
 
    .PARAMETER FilePath
    Path to the PDF file to be processed
 
    .PARAMETER IgnoreProtection
    The switch will allow reading of PDF files that are "owner password" encrypted for protection/security (e.g. preventing copying of text, printing etc).
    The switch doesn't allow reading of PDF files that are "user password" encrypted (i.e. you cannot open them without the password)
 
    .EXAMPLE
    $Document = Get-PDF -FilePath "C:\Users\przemyslaw.klys\OneDrive - Evotec\Support\GitHub\PSWritePDF\Example\Example01.HelloWorld\Example01_WithSectionsMix.pdf"
    $Details = Get-PDFDetails -Document $Document
    $Details | Format-List
    $Details.Pages | Format-Table
 
    Close-PDF -Document $Document
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param(
        [string] $FilePath,
        [switch] $IgnoreProtection
    )

    if ($FilePath -and (Test-Path -LiteralPath $FilePath)) {
        $ResolvedPath = Convert-Path -LiteralPath $FilePath

        try {
            $PDFFile = [iText.Kernel.Pdf.PdfReader]::new($ResolvedPath)
            if ($IgnoreProtection) {
                $null = $PDFFile.SetUnethicalReading($true)
            }
            $Document = [iText.Kernel.Pdf.PdfDocument]::new($PDFFile)
        } catch {
            $ErrorMessage = $_.Exception.Message
            Write-Warning "Get-PDF - Processing document $FilePath failed with error: $ErrorMessage"
        }
        $Document

    }
}
function Get-PDFDetails {
    [CmdletBinding()]
    param(
        [iText.Kernel.Pdf.PdfDocument] $Document
    )
    if ($Document) {
        [iText.Layout.Document] $LayoutDocument = [iText.Layout.Document]::new($Document)

        $Output = [ordered] @{
            Author       = $Document.GetDocumentInfo().GetAuthor()
            Creator      = $Document.GetDocumentInfo().GetCreator()
            HashCode     = $Document.GetDocumentInfo().GetHashCode()
            Keywords     = $Document.GetDocumentInfo().GetKeywords()
            Producer     = $Document.GetDocumentInfo().GetProducer()
            Subject      = $Document.GetDocumentInfo().GetSubject()
            Title        = $Document.GetDocumentInfo().GetTitle()
            Trapped      = $Document.GetDocumentInfo().GetTrapped()
            Version      = $Document.GetPdfVersion()
            PagesNumber  = $Document.GetNumberOfPages()
            MarginLeft   = $LayoutDocument.GetLeftMargin()
            MarginRight  = $LayoutDocument.GetRightMargin()
            MarginBottom = $LayoutDocument.GetBottomMargin()
            MarginTop    = $LayoutDocument.GetTopMargin()
            Pages        = [ordered] @{ }
        }
        for ($a = 1; $a -le $Output.PagesNumber; $a++) {
            $Height = $Document.GetPage($a).GetPageSizeWithRotation().GetHeight()
            $Width = $Document.GetPage($a).GetPageSizeWithRotation().GetWidth()
            $NamedSize = Get-PDFNamedPageSize -Height $Height -Width $Width
            $Output['Pages']["$a"] = [PSCustomObject] @{
                Height   = $Height
                Width    = $Width
                Rotation = $Document.GetPage($a).GetRotation()
                Size     = $NamedSize.PageSize
                Rotated  = $NamedSize.Rotated
            }
        }
        [PSCustomObject] $Output
    }
}
function Get-PDFFormField {
    [CmdletBinding()]
    param(
        [iText.Kernel.Pdf.PdfDocument]$PDF
    )
    try {
        $PDFAcroForm = [iText.Forms.PdfAcroForm]::getAcroForm($PDF, $true)
        $PDFAcroForm.GetFormFields()
    } catch {
        if ($PSBoundParameters.ErrorAction -eq 'Stop') {
            Write-Error $_
            return
        } else {
            Write-Warning -Message "Get-PDFFormField - There was an error reading forms or no form exists. Exception: $($_.Error.Exception)"
        }
    }
}
function New-PDF {
    [CmdletBinding()]
    param(
        [scriptblock] $PDFContent,
        [Parameter(Mandatory)][string] $FilePath,
        [string] $Version,

        [nullable[float]] $MarginLeft,
        [nullable[float]] $MarginRight,
        [nullable[float]] $MarginTop,
        [nullable[float]] $MarginBottom,
        [ValidateScript( { & $Script:PDFPageSizeValidation } )][string] $PageSize,
        [switch] $Rotate,

        [alias('Open')][switch] $Show
    )
    # The types needs filling in for the workaround below. DONT FORGET!
    $Script:Types = 'Text', 'List', 'Paragraph', 'Table', 'Image'
    $Script:PDFStart = @{
        Start            = $true
        FilePath         = $FilePath
        DocumentSettings = @{
            MarginTop    = $MarginTop
            MarginBottom = $MarginBottom
            MarginLeft   = $MarginLeft
            MarginRight  = $MarginRight
            PageSize     = $PageSize
            Rotate       = $Rotate.IsPresent
        }
        FirstPageFound   = $false
        FirstPageUsed    = $false
        UsedTypes        = [System.Collections.Generic.List[string]]::new()
    }
    if ($PDFContent) {
        [Array] $Elements = @(
            [Array] $Content = & $PDFContent
            # This is workaround to support multiple scenarios:
            # New-PDF { New-PDFPage, New-PDFPage }
            # New-PDF { }
            # New-PDF { New-PDFText, New-PDFPage }
            # This is there to make sure we allow for New-PDF to allow control for -Rotate/PageSize to either whole document or to text/tables
            # and other types until New-PDFPage is given
            # It's ugly but seems to wrok
            foreach ($_ in $Content) {
                if ($_.Type -in $Script:Types) {
                    $Script:PDFStart.UsedTypes.Add($_.Type)
                } elseif ($_.Type -eq 'Page') {
                    if ($Script:PDFStart.UsedTypes.Count -ne 0) {
                        New-PDFPage -PageSize $PageSize -Rotate:$Rotate -MarginLeft $MarginLeft -MarginTop $MarginTop -MarginBottom $MarginBottom -MarginRight $MarginRight
                        $Script:PDFStart.FirstPageFound = $true
                    }
                    break
                }
            }
            if (-not $Script:PDFStart.FirstPageFound -and $Script:PDFStart.UsedTypes.Count -ne 0) {
                New-PDFPage -PageSize $PageSize -Rotate:$Rotate -MarginLeft $MarginLeft -MarginTop $MarginTop -MarginBottom $MarginBottom -MarginRight $MarginRight
                $Script:PDFStart.FirstPageFound = $true
            }
            $Content
        )
        if ($Elements) {
            $Script:PDF = New-InternalPDF -FilePath $FilePath -Version $Version #-PageSize $PageSize -Rotate:$Rotate
            if (-not $Script:PDF) {
                return
            }
        } else {
            Write-Warning "New-PDF - No content was provided. Terminating."
            return
        }
    } else {
        $Script:PDFStart['Start'] = $false
        # if there's no scriptblock that means we're using standard way of working with PDF
        $Script:PDF = New-InternalPDF -FilePath $FilePath -Version $Version #-PageSize $PageSize -Rotate:$Rotate
        return $Script:PDF
    }

    $Script:PDFStart['Start'] = $true
    #[iText.Layout.Document] $Script:Document = New-PDFDocument -PDF $Script:PDF
    #New-InternalPDFOptions -MarginLeft $MarginLeft -MarginRight $MarginRight -MarginTop $MarginTop -MarginBottom $MarginBottom

    Initialize-PDF -Elements $Elements
    if ($Script:Document) {
        $Script:Document.Close();
    }
    if ($Show) {
        if (Test-Path -LiteralPath $FilePath) {
            Invoke-Item -LiteralPath $FilePath
        }
    }
    $Script:PDFStart = $null
    #$Script:PDFStart['Start'] = $false
}

Register-ArgumentCompleter -CommandName New-PDF -ParameterName PageSize -ScriptBlock $Script:PDFPageSize
Register-ArgumentCompleter -CommandName New-PDF -ParameterName Version -ScriptBlock $Script:PDFVersion
function New-PDFArea {
    [CmdletBinding()]
    param(
        [iText.Layout.Properties.AreaBreakType] $AreaType = [iText.Layout.Properties.AreaBreakType]::NEXT_AREA,
        [string] $PageSize,
        [switch] $Rotate
    )
    # https://api.itextpdf.com/iText7/dotnet/7.1.8/classi_text_1_1_kernel_1_1_geom_1_1_page_size.html
    $AreaBreak = [iText.Layout.Element.AreaBreak]::new($AreaType)
    if ($PageSize) {
        $Page = [iText.Kernel.Geom.PageSize]::($PageSize)
    } else {
        $Page = [iText.Kernel.Geom.PageSize]::Default
    }
    if ($Rotate) {
        $Page = $Page.Rotate()
    }
    $AreaBreak.SetPageSize($Page)
    return $AreaBreak
}

Register-ArgumentCompleter -CommandName New-PDFArea  -ParameterName PageSize -ScriptBlock $Script:PDFPageSize

<#
   TypeName: iText.Layout.Element.AreaBreak
 
Name MemberType Definition
---- ---------- ----------
AddStyle Method iText.Layout.Element.AreaBreak AddStyle(iText.Layout.Style style)
CreateRendererSubTree Method iText.Layout.Renderer.IRenderer CreateRendererSubTree(), iText.Layout.Renderer.IRenderer IElement.CreateRendererSubTree()
DeleteOwnProperty Method void DeleteOwnProperty(int property), void IPropertyContainer.DeleteOwnProperty(int property)
Equals Method bool Equals(System.Object obj)
GetAreaType Method System.Nullable[iText.Layout.Properties.AreaBreakType] GetAreaType()
GetChildren Method System.Collections.Generic.IList[iText.Layout.Element.IElement] GetChildren()
GetDefaultProperty Method T1 GetDefaultProperty[T1](int property), T1 IPropertyContainer.GetDefaultProperty[T1](int property)
GetHashCode Method int GetHashCode()
GetOwnProperty Method T1 GetOwnProperty[T1](int property), T1 IPropertyContainer.GetOwnProperty[T1](int property)
GetPageSize Method iText.Kernel.Geom.PageSize GetPageSize()
GetProperty Method T1 GetProperty[T1](int property), T1 IPropertyContainer.GetProperty[T1](int property)
GetRenderer Method iText.Layout.Renderer.IRenderer GetRenderer(), iText.Layout.Renderer.IRenderer IElement.GetRenderer()
GetSplitCharacters Method iText.Layout.Splitting.ISplitCharacters GetSplitCharacters()
GetStrokeColor Method iText.Kernel.Colors.Color GetStrokeColor()
GetStrokeWidth Method System.Nullable[float] GetStrokeWidth()
GetTextRenderingMode Method System.Nullable[int] GetTextRenderingMode()
GetType Method type GetType()
HasOwnProperty Method bool HasOwnProperty(int property), bool IPropertyContainer.HasOwnProperty(int property)
HasProperty Method bool HasProperty(int property), bool IPropertyContainer.HasProperty(int property)
IsEmpty Method bool IsEmpty()
SetAction Method iText.Layout.Element.AreaBreak SetAction(iText.Kernel.Pdf.Action.PdfAction action)
SetBackgroundColor Method iText.Layout.Element.AreaBreak SetBackgroundColor(iText.Kernel.Colors.Color backgroundColor), iText.Layout.Element.AreaBreak SetBackgroun...
SetBaseDirection Method iText.Layout.Element.AreaBreak SetBaseDirection(System.Nullable[iText.Layout.Properties.BaseDirection] baseDirection)
SetBold Method iText.Layout.Element.AreaBreak SetBold()
SetBorder Method iText.Layout.Element.AreaBreak SetBorder(iText.Layout.Borders.Border border)
SetBorderBottom Method iText.Layout.Element.AreaBreak SetBorderBottom(iText.Layout.Borders.Border border)
SetBorderBottomLeftRadius Method iText.Layout.Element.AreaBreak SetBorderBottomLeftRadius(iText.Layout.Properties.BorderRadius borderRadius)
SetBorderBottomRightRadius Method iText.Layout.Element.AreaBreak SetBorderBottomRightRadius(iText.Layout.Properties.BorderRadius borderRadius)
SetBorderLeft Method iText.Layout.Element.AreaBreak SetBorderLeft(iText.Layout.Borders.Border border)
SetBorderRadius Method iText.Layout.Element.AreaBreak SetBorderRadius(iText.Layout.Properties.BorderRadius borderRadius)
SetBorderRight Method iText.Layout.Element.AreaBreak SetBorderRight(iText.Layout.Borders.Border border)
SetBorderTop Method iText.Layout.Element.AreaBreak SetBorderTop(iText.Layout.Borders.Border border)
SetBorderTopLeftRadius Method iText.Layout.Element.AreaBreak SetBorderTopLeftRadius(iText.Layout.Properties.BorderRadius borderRadius)
SetBorderTopRightRadius Method iText.Layout.Element.AreaBreak SetBorderTopRightRadius(iText.Layout.Properties.BorderRadius borderRadius)
SetCharacterSpacing Method iText.Layout.Element.AreaBreak SetCharacterSpacing(float charSpacing)
SetDestination Method iText.Layout.Element.AreaBreak SetDestination(string destination)
SetFixedPosition Method iText.Layout.Element.AreaBreak SetFixedPosition(float left, float bottom, float width), iText.Layout.Element.AreaBreak SetFixedPosition(f...
SetFont Method iText.Layout.Element.AreaBreak SetFont(iText.Kernel.Font.PdfFont font), iText.Layout.Element.AreaBreak SetFont(string font)
SetFontColor Method iText.Layout.Element.AreaBreak SetFontColor(iText.Kernel.Colors.Color fontColor), iText.Layout.Element.AreaBreak SetFontColor(iText.Kerne...
SetFontFamily Method iText.Layout.Element.AreaBreak SetFontFamily(Params string[] fontFamilyNames), iText.Layout.Element.AreaBreak SetFontFamily(System.Collec...
SetFontKerning Method iText.Layout.Element.AreaBreak SetFontKerning(iText.Layout.Properties.FontKerning fontKerning)
SetFontScript Method iText.Layout.Element.AreaBreak SetFontScript(System.Nullable[iText.IO.Util.UnicodeScript] script)
SetFontSize Method iText.Layout.Element.AreaBreak SetFontSize(float fontSize)
SetHorizontalAlignment Method iText.Layout.Element.AreaBreak SetHorizontalAlignment(System.Nullable[iText.Layout.Properties.HorizontalAlignment] horizontalAlignment)
SetHyphenation Method iText.Layout.Element.AreaBreak SetHyphenation(iText.Layout.Hyphenation.HyphenationConfig hyphenationConfig)
SetItalic Method iText.Layout.Element.AreaBreak SetItalic()
SetLineThrough Method iText.Layout.Element.AreaBreak SetLineThrough()
SetNextRenderer Method void SetNextRenderer(iText.Layout.Renderer.IRenderer renderer), void IElement.SetNextRenderer(iText.Layout.Renderer.IRenderer renderer)
SetOpacity Method iText.Layout.Element.AreaBreak SetOpacity(System.Nullable[float] opacity)
SetPageNumber Method iText.Layout.Element.AreaBreak SetPageNumber(int pageNumber)
SetPageSize Method void SetPageSize(iText.Kernel.Geom.PageSize pageSize)
SetProperty Method void SetProperty(int property, System.Object value), void IPropertyContainer.SetProperty(int property, System.Object value)
SetRelativePosition Method iText.Layout.Element.AreaBreak SetRelativePosition(float left, float top, float right, float bottom)
SetSplitCharacters Method iText.Layout.Element.AreaBreak SetSplitCharacters(iText.Layout.Splitting.ISplitCharacters splitCharacters)
SetStrokeColor Method iText.Layout.Element.AreaBreak SetStrokeColor(iText.Kernel.Colors.Color strokeColor)
SetStrokeWidth Method iText.Layout.Element.AreaBreak SetStrokeWidth(float strokeWidth)
SetTextAlignment Method iText.Layout.Element.AreaBreak SetTextAlignment(System.Nullable[iText.Layout.Properties.TextAlignment] alignment)
SetTextRenderingMode Method iText.Layout.Element.AreaBreak SetTextRenderingMode(int textRenderingMode)
SetUnderline Method iText.Layout.Element.AreaBreak SetUnderline(), iText.Layout.Element.AreaBreak SetUnderline(float thickness, float yPosition), iText.Layou...
SetWordSpacing Method iText.Layout.Element.AreaBreak SetWordSpacing(float wordSpacing)
ToString Method string ToString()
#>

function New-PDFDocument {
    [CmdletBinding()]
    param(
        [iText.Kernel.Pdf.PdfDocument] $PDF
    )
    [iText.Layout.Document] $Document = [iText.Layout.Document]::new($PDF)
    return $Document
}
function New-PDFImage {
    [CmdletBinding()]
    param(
        [string] $ImagePath,
        [int] $Width,
        [int] $Height,
        [string] $BackgroundColor,
        [double] $BackgroundColorOpacity
    )

    [PSCustomObject] @{
        Type     = 'Image'
        Settings = @{
            ImagePath              = $ImagePath
            Width                  = $Width
            Height                 = $Height
            BackgroundColor        = ConvertFrom-Color -Color $BackgroundColor -AsDrawingColor
            BackgroundColorOpacity = $BackgroundColorOpacity
        }
    }
}

Register-ArgumentCompleter -CommandName New-PDFImage -ParameterName BackgroundColor -ScriptBlock $Script:ScriptBlockColors
function New-PDFInfo {
    [CmdletBinding()]
    param(
        [iText.Kernel.Pdf.PdfDocument] $PDF,
        [string] $Title,
        [string] $Author,
        [string] $Creator,
        [string] $Subject,
        [string[]] $Keywords,
        [switch] $AddCreationDate,
        [switch] $AddModificationDate
    )

    try {
        [iText.Kernel.Pdf.PdfDocumentInfo] $info = $pdf.GetDocumentInfo()
    } catch {
        Write-Warning "New-PDFInfo - Error: $($_.Exception.Message)"
        return
    }

    if ($Title) {
        $null = $info.SetTitle($Title)
    }
    if ($AddCreationDate) {
        $null = $info.AddCreationDate()
    }
    if ($AddModificationDate) {
        $null = $info.AddModDate()
    }
    if ($Author) {
        $null = $info.SetAuthor($Author)
    }
    if ($Creator) {
        $null = $info.SetCreator($Creator)
    }
    if ($Subject) {
        $null = $info.SetSubject($Subject)
    }
    if ($Keywords) {
        $KeywordsString = $Keywords -join ','
        $null = $info.SetKeywords($KeywordsString)
    }
}
function New-PDFList {
    [CmdletBinding()]
    param(
        [ScriptBlock] $ListItems,
        [nullable[float]] $Indent,
        [ValidateSet('bullet', 'hyphen')][string] $Symbol = 'hyphen'
    )

    $Output = & $ListItems
    $Items = foreach ($_ in $Output) {
        if ($_.Type -eq 'ListItem') {
            $_.Settings
        }
    }

    [PSCustomObject] @{
        Type     = 'List'
        Settings = @{
            Items  = $Items
            Indent = $Indent
            Symbol = $Symbol
        }
    }
}
function New-PDFListItem {
    [CmdletBinding()]
    param(
        [string[]] $Text,
        [ValidateScript( { & $Script:PDFFontValidationList } )][string[]] $Font,
        [ValidateScript( { & $Script:PDFColorValidation } )][string[]] $FontColor,
        [nullable[bool][]] $FontBold
    )

    $Splat = @{ }
    if ($Text) {
        $Splat['Text'] = $Text
    }
    if ($Font) {
        $Splat['Font'] = $Font
    }
    if ($FontColor) {
        $Splat['FontColor'] = $FontColor
    }
    if ($FontBold) {
        $Splat['FontBold'] = $FontBold
    }

    [PSCustomObject] @{
        Type     = 'ListItem'
        Settings = $Splat
    }
}

Register-ArgumentCompleter -CommandName New-PDFListItem -ParameterName Font -ScriptBlock $Script:PDFFontList
Register-ArgumentCompleter -CommandName New-PDFListItem -ParameterName FontColor -ScriptBlock $Script:PDFColor
function New-PDFOptions {
    [CmdletBinding()]
    param(
        [nullable[float]] $MarginLeft,
        [nullable[float]] $MarginRight,
        [nullable[float]] $MarginTop,
        [nullable[float]] $MarginBottom
        #[ValidateScript( { & $Script:PDFPageSizeValidation } )][string] $PageSize
    )

    [PSCustomObject] @{
        Type     = 'Options'
        Settings = @{
            Margins = @{
                MarginLeft   = $MarginLeft
                MarginRight  = $MarginRight
                MarginTop    = $MarginTop
                MarginBottom = $MarginBottom
            }
            #PageSize = $PageSize
        }
    }
}

Register-ArgumentCompleter -CommandName New-PDFOptions -ParameterName PageSize -ScriptBlock $Script:PDFPageSize
function New-PDFPage {
    [CmdletBinding()]
    param(
        [ScriptBlock] $PageContent,
        [nullable[float]] $MarginLeft,
        [nullable[float]] $MarginRight,
        [nullable[float]] $MarginTop,
        [nullable[float]] $MarginBottom,
        [ValidateScript( { & $Script:PDFPageSizeValidation } )][string] $PageSize,
        [switch] $Rotate
    )
    if ($null -ne $Script:PDFStart -and $Script:PDFStart['Start']) {
        $Page = [PSCustomObject] @{
            Type     = 'Page'
            Settings = @{
                Margins     = @{
                    MarginLeft   = $MarginLeft
                    MarginRight  = $MarginRight
                    MarginTop    = $MarginTop
                    MarginBottom = $MarginBottom
                }
                PageSize    = $PageSize
                Rotate      = $Rotate.IsPresent
                PageContent = if ($PageContent) { & $PageContent } else { $null }
            }
        }
        $Page
    } else {
        # New-InternalPDFPage -PageSize $PageSize -Rotate:$Rotate.IsPresent
    }
}

Register-ArgumentCompleter -CommandName New-PDFPage -ParameterName PageSize -ScriptBlock $Script:PDFPageSize
function New-PDFTable {
    [CmdletBinding()]
    param(
        [Array] $DataTable
    )
    if ($null -ne $Script:PDFStart -and $Script:PDFStart['Start']) {
        $Settings = [PSCustomObject] @{
            Type     = 'Table'
            Settings = @{
                DataTable = $DataTable
            }
        }
        $Settings
    } else {
        New-InteralPDFTable -DataTable $DataTable
    }
}
function New-PDFText {
    [CmdletBinding()]
    param(
        [string[]] $Text,
        [ValidateScript( { & $Script:PDFFontValidationList } )][string[]] $Font,
        [ValidateScript( { & $Script:PDFColorValidation } )][string[]] $FontColor,
        [nullable[bool][]] $FontBold
    )
    $Splat = @{ }
    if ($Text) {
        $Splat['Text'] = $Text
    }
    if ($Font) {
        $Splat['Font'] = $Font
    }
    if ($FontColor) {
        $Splat['FontColor'] = $FontColor
    }
    if ($FontBold) {
        $Splat['FontBold'] = $FontBold
    }

    if ($null -ne $Script:PDFStart -and $Script:PDFStart['Start']) {
        $Settings = [PSCustomObject] @{
            Type     = 'Text'
            Settings = $Splat
        }
        $Settings
    } else {
        New-InternalPDFText @Splat
    }
}

Register-ArgumentCompleter -CommandName New-PDFText -ParameterName Font -ScriptBlock $Script:PDFFontList
Register-ArgumentCompleter -CommandName New-PDFText -ParameterName FontColor -ScriptBlock $Script:PDFColor
function Register-PDFFont {
    [cmdletBinding()]
    param(
        [Parameter(Mandatory)][string] $FontName,
        [Parameter(Mandatory)][string] $FontPath,
        [ValidateScript( { & $Script:PDFFontEncodingValidation } )][string] $Encoding,
        [iText.Kernel.Font.PdfFontFactory+EmbeddingStrategy] $EmbeddingStrategy = [iText.Kernel.Font.PdfFontFactory+EmbeddingStrategy]::PREFER_EMBEDDED,
        [switch] $Cached,
        [switch] $Default
    )
    if (Test-Path -LiteralPath $FontPath) {
        try {
            if ($FontPath -and $Encoding) {
                $Script:Fonts[$FontName] = [iText.Kernel.Font.PdfFontFactory]::CreateFont($FontPath, [iText.IO.Font.PdfEncodings]::$Encoding, $EmbeddingStrategy, $Cached.IsPresent)
            } elseif ($FontPath) {
                $Script:Fonts[$FontName] = [iText.Kernel.Font.PdfFontFactory]::CreateFont($FontPath, $EmbeddingStrategy)
            }
        } catch {
            if ($PSBoundParameters.ErrorAction -eq 'Stop') {
                throw
            } else {
                Write-Warning "Register-PDFFont - Font registration failed. Error: $($_.Exception.Message)"
                return
            }
        }
        if (($Default -or $Script:Fonts.Count -eq 0) -and $Script:Fonts[$FontName]) {
            $Script:DefaultFont = $Script:Fonts[$FontName]
        }
    } else {
        if ($PSBoundParameters.ErrorAction -eq 'Stop') {
            throw "Font path '$FontPath' does not exist."
        } else {
            Write-Warning "Register-PDFFont - Font path does not exist. Path: $FontPath"
        }
    }
}

$Script:Fonts = [ordered] @{}
# Validation for Fonts Encoding
$Script:PDFFontEncoding = {
    ([iText.IO.Font.PdfEncodings] | Get-Member -Static -MemberType Property).Name
}
$Script:PDFFontEncodingValidation = {
    $Array = @(
        (& $Script:PDFFontEncoding)
        ''
    )
    $_ -in $Array
}
Register-ArgumentCompleter -CommandName Register-PDFFont -ParameterName Encoding -ScriptBlock $Script:PDFFontEncoding




# Export functions and aliases as required
Export-ModuleMember -Function @('Close-PDF', 'Convert-HTMLToPDF', 'Convert-PDFToText', 'Get-PDF', 'Get-PDFConstantAction', 'Get-PDFConstantColor', 'Get-PDFConstantFont', 'Get-PDFConstantPageSize', 'Get-PDFConstantVersion', 'Get-PDFDetails', 'Get-PDFFormField', 'Merge-PDF', 'New-PDF', 'New-PDFArea', 'New-PDFDocument', 'New-PDFImage', 'New-PDFInfo', 'New-PDFList', 'New-PDFListItem', 'New-PDFOptions', 'New-PDFPage', 'New-PDFTable', 'New-PDFText', 'Register-PDFFont', 'Set-PDFForm', 'Split-PDF') -Alias @()
# SIG # Begin signature block
# MIInPgYJKoZIhvcNAQcCoIInLzCCJysCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDcVrje5VkrLjVt
# Zl/0nba3ZaBISEafNtqdqbYDSV2beKCCITcwggO3MIICn6ADAgECAhAM5+DlF9hG
# /o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa
# Fw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD
# ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwmlIiq9M71IDkoWGAM+IDaqRWVMmE8
# tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf
# 4rHZ/hhk0hJbX/lYGDW8R82hNvlrf9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1
# lhb+WZyLdm3X8aJLDSv/C3LanmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqi
# uhOCEe05F52ZOnKh5vqk2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplaz
# vbKX7aqn8LfFqD+VFtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGG
# MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgP
# MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUA
# A4IBAQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS
# TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLil4Qf
# 6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXBzLZ/wvFv
# hsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW2168RJGYIPXJwS+
# S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdhAbHSoyahEHGdreLD
# +cOZUbcrBwjOLuZQsqf6CkUvovDyMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1
# b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
# aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE
# aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgx
# MDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLX
# cep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSR
# I5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXi
# TWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5
# Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8
# vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYD
# VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB
# BQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4
# oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv
# b3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCow
# KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZI
# AYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaA
# FEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPz
# ItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRu
# pY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKN
# JK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmif
# z0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN
# 3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKy
# ZqHnGKSaZFHvMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkqhkiG
# 9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy
# IEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoXDTIz
# MDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tpZTER
# MA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlzIEVW
# T1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqDBqln
# r3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfFjVye
# 3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub+3ti
# i0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf3tZZ
# zO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6Ea41
# zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQABo4IB
# xTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE
# FBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3
# BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
# Y29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25p
# bmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1sz4ls
# LARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsRXPHU
# F/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHINrTC
# vPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8Rj9y
# G4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6o6ES
# Jre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNpezQu
# g9ufqExx6lHYDjCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZI
# hvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz
# dXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVow
# YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290
# IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjww
# IjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J5
# 8soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMH
# hOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6
# Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQ
# ecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4b
# A3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9
# WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCU
# tNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvo
# ZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/J
# vNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCP
# orF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMB
# Af8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXr
# oq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRt
# MGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEF
# BQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgw
# BgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cH
# vZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8
# UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTn
# f+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxU
# jG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8j
# LfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBq4w
# ggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4X
# DTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAV
# BgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVk
# IEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5M
# om2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE
# 2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWN
# lCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFo
# bjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhN
# ef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3Vu
# JyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtz
# Q87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4O
# uGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5
# sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm
# 4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIz
# tM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6
# FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYB
# BQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w
# QQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZ
# MBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmO
# wJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H
# 6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/
# R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzv
# qLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/ae
# sXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdm
# kfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3
# EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh
# 3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA
# 3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8
# BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsf
# gPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggbAMIIEqKADAgECAhAMTWly
# S5T6PCpKPSkHgD1aMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYD
# VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH
# NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwOTIxMDAwMDAw
# WhcNMzMxMTIxMjM1OTU5WjBGMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNl
# cnQxJDAiBgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM/spSY6xqnya7uNwQ2a26HoFIV0Mxom
# rNAcVR4eNm28klUMYfSdCXc9FZYIL2tkpP0GgxbXkZI4HDEClvtysZc6Va8z7GGK
# 6aYo25BjXL2JU+A6LYyHQq4mpOS7eHi5ehbhVsbAumRTuyoW51BIu4hpDIjG8b7g
# L307scpTjUCDHufLckkoHkyAHoVW54Xt8mG8qjoHffarbuVm3eJc9S/tjdRNlYRo
# 44DLannR0hCRRinrPibytIzNTLlmyLuqUDgN5YyUXRlav/V7QG5vFqianJVHhoV5
# PgxeZowaCiS+nKrSnLb3T254xCg/oxwPUAY3ugjZNaa1Htp4WB056PhMkRCWfk3h
# 3cKtpX74LRsf7CtGGKMZ9jn39cFPcS6JAxGiS7uYv/pP5Hs27wZE5FX/NurlfDHn
# 88JSxOYWe1p+pSVz28BqmSEtY+VZ9U0vkB8nt9KrFOU4ZodRCGv7U0M50GT6Vs/g
# 9ArmFG1keLuY/ZTDcyHzL8IuINeBrNPxB9ThvdldS24xlCmL5kGkZZTAWOXlLimQ
# prdhZPrZIGwYUWC6poEPCSVT8b876asHDmoHOWIZydaFfxPZjXnPYsXs4Xu5zGcT
# B5rBeO3GiMiwbjJ5xwtZg43G7vUsfHuOy2SJ8bHEuOdTXl9V0n0ZKVkDTvpd6kVz
# HIR+187i1Dp3AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/
# BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w
# HQYDVR0OBBYEFGKK3tBh/I8xFO2XC809KpQU31KcMFoGA1UdHwRTMFEwT6BNoEuG
# SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw
# OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG
# TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT
# QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB
# AFWqKhrzRvN4Vzcw/HXjT9aFI/H8+ZU5myXm93KKmMN31GT8Ffs2wklRLHiIY1UJ
# RjkA/GnUypsp+6M/wMkAmxMdsJiJ3HjyzXyFzVOdr2LiYWajFCpFh0qYQitQ/Bu1
# nggwCfrkLdcJiXn5CeaIzn0buGqim8FTYAnoo7id160fHLjsmEHw9g6A++T/350Q
# p+sAul9Kjxo6UrTqvwlJFTU2WZoPVNKyG39+XgmtdlSKdG3K0gVnK3br/5iyJpU4
# GYhEFOUKWaJr5yI+RCHSPxzAm+18SLLYkgyRTzxmlK9dAlPrnuKe5NMfhgFknADC
# 6Vp0dQ094XmIvxwBl8kZI4DXNlpflhaxYwzGRkA7zl011Fk+Q5oYrsPJy8P7mxNf
# arXH4PMFw1nfJ2Ir3kHJU7n/NBBn9iYymHv+XEKUgZSCnawKi8ZLFUrTmJBFYDOA
# 4CPe+AOk9kVH5c64A0JH6EE2cXet/aLol3ROLtoeHYxayB6a1cLwxiKoT5u92Bya
# UcQvmvZfpyeXupYuhVfAYOd4Vn9q78KVmksRAsiCnMkaBXy6cbVOepls9Oie1FqY
# yJ+/jbsYXEP10Cro4mLueATbvdH7WwqocH7wl4R44wgDXUcsY6glOJcB0j862uXl
# 9uab3H4szP8XTE0AotjWAQ64i+7m4HJViSwnGWH2dwGMMYIFXTCCBVkCAQEwgYYw
# cjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVk
# IElEIENvZGUgU2lnbmluZyBDQQIQBNXcH0jqydhSALrNmpsqpzANBglghkgBZQME
# AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCBWUsNVsIHNVPcZJ28W69cIjKaaqfWLNnKqPwthDQC3PDANBgkq
# hkiG9w0BAQEFAASCAQB3wGKGCapGnHl5+ud2eWvS2nQThlqIf3jOyaunwNb4JBcv
# YgXKEDeEbiiwQc/QQOBEvQzhvYgjsHfAW1Xc5MO/39xNJOfZZtrM+qZPQrRKYpPg
# P9nsK+RwETffQavjL4JDHRPQWjVtsdhhAniiF4Ixxu8cfhNgFhwy6Xbr1D3X3Syb
# 1bN00gCZVEvtL9M1sLQF9MLagbWMQZMr60OWUgj+z1xc9oXzzUNHUtWX+QzxlOu8
# bGKEbWKxWfAYzrqm5yM0XsIsxIxQzXNrIeukqILg3KsSd6k+KdlJlAh2Z7+VIYlF
# rEzkrlNcPSK4xrecoJO+aEUiJLeabd6a+rv7TJI/oYIDIDCCAxwGCSqGSIb3DQEJ
# BjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hB
# MjU2IFRpbWVTdGFtcGluZyBDQQIQDE1pckuU+jwqSj0pB4A9WjANBglghkgBZQME
# AgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
# DTIyMTAwMjE3MjQyOFowLwYJKoZIhvcNAQkEMSIEIEiFzK3Wy58FVTTKCNNCdQgy
# g8cSSL8kfl7qBMxjBAhjMA0GCSqGSIb3DQEBAQUABIICAKtGVOkQfzfR4As3GERK
# xErsHplKsIUyrThD5hPbUV7FjBtGx0UYEhjsgjJdxQWKm0vOieKYeDhz0WdtT2AN
# 5mVSI6jpfovGGpMPLX8EQnCzvUcDOJBPNEh/ZQhZ8weM091I4k2jaZa3vk9Tbn+e
# uk5vvJ0EJwbzVm+Db1O+GPbcSGvbffLRsj/ueXCqmD8jVBacW/xUdwIsxb2GaLDU
# r0D2ShSKrhboRfGVV3IIY80DSD7LibkSjoRdTy6wiqhd+JndlaDWMtXxytVv+Niw
# s43skfvqhzQtuknpshgeGOm1hCxKyNB60JquAKCTrS5WHyq3QU+nwOrgOLd6TgsQ
# yw8rR3GzouiSe3Aktn+nRTkjmGPog9uBTgUgRXEIGwJ/S+Sg5Yas8oMK+7lg8Xdn
# QRpR5iPLLLthn7obbxtQjl/gzsyiry5GfLN+8gIiwd0CqL9PV7eiA8XmFsbNI0nA
# nYswvI7oH67PLO6ybe/X0g9kjlAn2/qdojdZ4rV4MJHJdX9xPvUlYn1CXRZXYnia
# +I4QoSVkQpJt+CtmrqMcrc+jaFXgqUE0AikHsumYV3ye0RZhToxG7M5KOqKPziFx
# Ru/PB1q7eR9VTAIRQDOfUWkiJ5sIwagGtWqyk2N2CZWgVNBN3WAfJY4yGIoiULK3
# /sSUWZbLZnnhr8C++ZNOLMB3
# SIG # End signature block