Src/Plugins/Word/Word.ps1

function ConvertTo-WordColor
{
<#
    .SYNOPSIS
        Converts an HTML color to RRGGBB value as Word does not support short Html color codes
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.String] $Color
    )
    process
    {
        $Color = $Color.TrimStart('#')
        if ($Color.Length -eq 3)
        {
            $Color = '{0}{0}{1}{1}{2}{2}' -f $Color[0], $Color[1], $Color[2]
        }

        return $Color.ToUpper()
    }
}

function Get-WordDocument
{
<#
    .SYNOPSIS
        Outputs Office Open XML document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param
    (
        # The PScribo document object to convert to a Word xml document
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Document
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $xmlnswpdrawing = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
        $xmlnsdrawing = 'http://schemas.openxmlformats.org/drawingml/2006/main'
        $xmlnspicture = 'http://schemas.openxmlformats.org/drawingml/2006/picture'
        $xmlnsrelationships = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
        $xmlnsofficeword14 = 'http://schemas.microsoft.com/office/drawing/2010/main'
        $xmlnsmath = 'http://schemas.openxmlformats.org/officeDocument/2006/math'
        $xmlnsmc = 'http://schemas.openxmlformats.org/markup-compatibility/2006' # required for custom number lists
        $xmlnsw14 = 'http://schemas.microsoft.com/office/word/2010/wordml' # required for custom number lists
        $xmlDocument = New-Object -TypeName 'System.Xml.XmlDocument'
        [ref] $null = $xmlDocument.AppendChild($xmlDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))
        $documentXml = $xmlDocument.AppendChild($xmlDocument.CreateElement('w', 'document', $xmlns))
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:xml', 'http://www.w3.org/XML/1998/namespace')
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:pic', $xmlnspicture)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:wp', $xmlnswpdrawing)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:a', $xmlnsdrawing)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:r', $xmlnsrelationships)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:m', $xmlnsmath)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:a14', $xmlnsofficeword14)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:mc', $xmlnsmc)
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:w14', $xmlnsw14)
        $body = $documentXml.AppendChild($xmlDocument.CreateElement('w', 'body', $xmlns))
        $script:pscriboIsFirstSection = $false

        foreach ($subSection in $Document.Sections.GetEnumerator())
        {
            $currentIndentationLevel = 1
            if ($null -ne $subSection.PSObject.Properties['Level'])
            {
                $currentIndentationLevel = $subSection.Level + 1
            }
            Write-PScriboProcessSectionId -SectionId $subSection.Id -SectionType $subSection.Type -Indent $currentIndentationLevel

            switch ($subSection.Type)
            {
                'PScribo.Section'
                {
                    Out-WordSection -Section $subSection -Element $body -XmlDocument $xmlDocument
                }
                'PScribo.Paragraph'
                {
                    [ref] $null = $body.AppendChild((Out-WordParagraph -Paragraph $subSection -XmlDocument $xmlDocument))
                }
                'PScribo.Image'
                {
                    $Images += @($subSection)
                    [ref] $null = $body.AppendChild((Out-WordImage -Image $subSection -XmlDocument $xmlDocument))
                }
                'PScribo.PageBreak'
                {
                    [ref] $null = $body.AppendChild((Out-WordPageBreak -PageBreak $subSection -XmlDocument $xmlDocument))
                }
                'PScribo.LineBreak'
                {
                    [ref] $null = $body.AppendChild((Out-WordLineBreak -LineBreak $subSection -XmlDocument $xmlDocument))
                }
                'PScribo.Table'
                {
                    Out-WordTable -Table $subSection -XmlDocument $xmlDocument -Element $body
                }
                'PScribo.TOC'
                {
                    [ref] $null = $body.AppendChild((Out-WordTOC -TOC $subSection -XmlDocument $xmlDocument))
                }
                'PScribo.BlankLine'
                {
                    Out-WordBlankLine -BlankLine $subSection -XmlDocument $xmlDocument -Element $body
                }
                'PScribo.ListReference'
                {
                    Out-WordList -List $Document.Lists[$subSection.Number -1] -Element $body -XmlDocument $xmlDocument -NumberId $subSection.Number
                }
                Default
                {
                    Write-PScriboMessage -Message ($localized.PluginUnsupportedSection -f $subSection.Type) -IsWarning
                }
            }
        }

        ## Last section's properties are a child element of body element
        $lastSectionOrientation = $Document.Sections |
            Where-Object { $_.Type -in 'PScribo.Section','PScribo.Paragraph' } |
                Select-Object -Last 1 -ExpandProperty Orientation
        if ($null -eq $lastSectionOrientation)
        {
            $lastSectionOrientation = $Document.Options['PageOrientation']
        }

        $sectionPrParams = @{
            PageHeight       = $Document.Options['PageHeight']
            PageWidth        = $Document.Options['PageWidth']
            PageMarginTop    = $Document.Options['MarginTop']
            PageMarginBottom = $Document.Options['MarginBottom']
            PageMarginLeft   = $Document.Options['MarginLeft']
            PageMarginRight  = $Document.Options['MarginRight']
            Orientation      = $lastSectionOrientation
        }

        $wordSectionPr = Get-WordSectionPr @sectionPrParams -XmlDocument $xmlDocument
        [ref] $null = $body.AppendChild($wordSectionPr)
        return $xmlDocument
    }
}

function Get-WordHeaderFooterDocument
{
<#
    .SYNOPSIS
        Outputs Office Open XML footer document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $HeaderFooter,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Header')]
        [System.Management.Automation.SwitchParameter] $IsHeader,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Footer')]
        [System.Management.Automation.SwitchParameter] $IsFooter
    )
    process
    {
        ## Create the Style.xml document
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $headerFooterDocument = New-Object -TypeName 'System.Xml.XmlDocument'
        [ref] $null = $headerFooterDocument.AppendChild($headerFooterDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))

        if ($IsHeader -eq $true)
        {
            $elementName = 'hdr'
        }
        elseif ($IsFooter -eq $true)
        {
            $elementName = 'ftr'
        }
        $element = $headerFooterDocument.CreateElement('w', $elementName, $xmlns)

        foreach ($subSection in $HeaderFooter.Sections)
        {
            switch ($subSection.Type)
            {
                'PScribo.Paragraph'
                {
                    [ref] $null = $element.AppendChild((Out-WordParagraph -Paragraph $subSection -XmlDocument $headerFooterDocument))
                }
                'PScribo.Table'
                {
                    Out-WordTable -Table $subSection -XmlDocument $headerFooterDocument -Element $element
                }
                'PScribo.BlankLine'
                {
                    Out-WordBlankLine -BlankLine $subSection -XmlDocument $headerFooterDocument -Element $element
                }
                'PScribo.LineBreak'
                {
                    [ref] $null = $element.AppendChild((Out-WordLineBreak -LineBreak $subSection -XmlDocument $headerFooterDocument))
                }
            }
        }

        [ref] $null = $headerFooterDocument.AppendChild($element)
        return $headerFooterDocument
    }
}

function Get-WordListLevel
{
<#
    .SYNOPSIS
        Process (nested) lists and build index of number/bullet styles.
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $List,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Collections.Hashtable] $Levels = @{ }
    )
    process
    {
        foreach ($item in $List.Items)
        {
            if ($item.Type -eq 'PScribo.Item')
            {
                $level = $item.Level -1
                if (-not $Levels.ContainsKey($level))
                {
                    $Levels[$level] = @{
                        IsNumbered  = $List.IsNumbered
                        NumberStyle = $List.NumberStyle
                        BulletStyle = $List.BulletStyle
                    }
                }
            }
            elseif ($item.Type -eq 'PScribo.List')
            {
                $Levels = Get-WordListLevel -List $item -Levels $Levels
            }
        }
        return $Levels
    }
}

function Get-WordNumberingDocument
{
<#
    .SYNOPSIS
        Outputs Office Open XML numbering document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param
    (
        ## PScribo document styles
        [Parameter(Mandatory, ValueFromPipeline)]
        [AllowEmptyCollection()]
        [System.Collections.ArrayList] $Lists
    )
    process
    {
        ## Create the numbering.xml document
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $xmlDocument = New-Object -TypeName 'System.Xml.XmlDocument'
        [ref] $null = $xmlDocument.AppendChild($XmlDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))
        $numbering = $xmlDocument.AppendChild($xmlDocument.CreateElement('w', 'numbering', $xmlns))
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006')
        [ref] $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:w14', 'http://schemas.microsoft.com/office/word/2010/wordml')

        foreach ($list in $Lists.GetEnumerator())
        {
            $abstractNum = Get-WordNumberStyle -List $list -XmlDocument $xmlDocument
            [ref] $null = $numbering.AppendChild($abstractNum)
        }

        foreach ($list in $Lists.GetEnumerator())
        {
            $num = $numbering.AppendChild($xmlDocument.CreateElement('w', 'num', $xmlns))
            [ref] $null = $num.SetAttribute('numId', $xmlns, $list.Number)
            $abstractNumId = $num.AppendChild($xmlDocument.CreateElement('w', 'abstractNumId', $xmlns))
            [ref] $null = $abstractNumId.SetAttribute('val', $xmlns, $list.Number -1)
        }

        return $xmlDocument
    }
}

function Get-WordNumberStyle
{
<#
    .SYNOPSIS
        Outputs Office Open XML numbering document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        ## PScribo document styles
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $List,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    begin
    {
        $bulletMatrix = @{
            Disc   = [PSCustomObject] @{ Text = '?'; Font = 'Symbol'; }
            Circle = [PSCustomObject] @{ Text = 'o'; Font = 'Courier New'; }
            Square = [PSCustomObject] @{ Text = '?'; Font = 'Wingdings'; }
            Dash   = [PSCustomObject] @{ Text = '-'; Font = 'Courier New' }
        }
    }
    process
    {
        ## Create the Numbering.xml document
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $xmlnsmc = 'http://schemas.openxmlformats.org/markup-compatibility/2006'

        $abstractNum = $xmlDocument.CreateElement('w', 'abstractNum', $xmlns)
        [ref] $null = $abstractNum.SetAttribute('abstractNumId', $xmlns, $list.Number -1)
        $multiLevelType = $abstractNum.AppendChild($xmlDocument.CreateElement('w', 'multiLevelType', $xmlns))
        [ref] $null = $multiLevelType.SetAttribute('val', $xmlns, 'hybridMultilevel')

        $listLevels = Get-WordListLevel -List $List
        foreach ($level in ($listLevels.Keys | Sort-Object))
        {
            $listLevel = $listLevels[$level]
            if ($listLevel.IsNumbered)
            {
                $numberStyle = $Document.NumberStyles[$listLevel.NumberStyle]
            }

            $lvl = $abstractNum.AppendChild($xmlDocument.CreateElement('w', 'lvl', $xmlns))
            [ref] $null = $lvl.SetAttribute('ilvl', $xmlns, $level)
            $start = $lvl.AppendChild($xmlDocument.CreateElement('w', 'start', $xmlns))
            [ref] $null = $start.SetAttribute('val', $xmlns, 1)

            if ($listLevel.IsNumbered)
            {
                switch ($numberStyle.Format)
                {
                    Number
                    {
                        $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                        $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                        [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'decimal')
                        [ref] $null = $lvlText.SetAttribute('val', $xmlns, ('%{0}{1}' -f ($level +1), $numberStyle.Suffix))
                    }
                    Letter
                    {
                        $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                        $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                        if ($numberStyle.Uppercase)
                        {
                            [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'upperLetter')
                        }
                        else
                        {
                            [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'lowerLetter')
                        }
                        [ref] $null = $lvlText.SetAttribute('val', $xmlns, ('%{0}{1}' -f ($level +1), $numberStyle.Suffix))
                    }
                    Roman
                    {
                        $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                        $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                        if ($numberStyle.Uppercase)
                        {
                            [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'upperRoman')
                        }
                        else
                        {
                            [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'lowerRoman')
                        }
                        [ref] $null = $lvlText.SetAttribute('val', $xmlns, ('%{0}{1}' -f ($level +1), $numberStyle.Suffix))
                    }
                    Custom
                    {
                        $regexMatch = [Regex]::Match($numberStyle.Custom, '%+')
                        if ($regexMatch.Success -eq $true)
                        {
                            $numberString = $regexMatch.Value
                            if ($numberString.Length -eq 1)
                            {
                                $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                                $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                                [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'decimal')
                            }
                            elseif ($numberString.Length -eq 2)
                            {
                                $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                                $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                                [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'decimalZero')
                            }
                            else
                            {
                                $AlternateContent = $lvl.AppendChild($xmlDocument.CreateElement('mc', 'AlternateContent', $xmlnsmc))
                                $Choice = $AlternateContent.AppendChild($xmlDocument.CreateElement('mc', 'Choice', $xmlnsmc))
                                [ref] $null = $Choice.SetAttribute('Requires', 'w14')
                                $numFmtC = $Choice.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                                [ref] $null = $numFmtC.SetAttribute('val', $xmlns, 'custom')

                                if ($numberString.Length -eq 3)
                                {
                                    [ref] $null = $numFmtC.SetAttribute('format', $xmlns, '001, 002, 003, ...')
                                }
                                elseif ($numberString.Length -eq 4)
                                {
                                    [ref] $null = $numFmtC.SetAttribute('format', $xmlns, '0001, 0002, 0003, ...')
                                }
                                elseif ($numberString.Length -ge 5)
                                {
                                    [ref] $null = $numFmtC.SetAttribute('format', $xmlns, '00001, 00002, 00003, ...')
                                }

                                $Fallback = $AlternateContent.AppendChild($xmlDocument.CreateElement('mc', 'Fallback', $xmlnsmc))
                                $numFmtF = $Fallback.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                                [ref] $null = $numFmtF.SetAttribute('val', $xmlns, 'decimal')

                                $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                            }
                        }
                        else
                        {
                            Write-PScriboMessage 'Invalid custom number format' -IsWarning
                            $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                            [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'none')
                        }
                        $replacementString = '%{0}' -f ($level +1)
                        $wordNumberString = $numberStyle.Custom -replace '%+', $replacementString
                        [ref] $null = $lvlText.SetAttribute('val', $xmlns, $wordNumberString)
                    }
                }
            }
            else
            {
                $numFmt = $lvl.AppendChild($xmlDocument.CreateElement('w', 'numFmt', $xmlns))
                [ref] $null = $numFmt.SetAttribute('val', $xmlns, 'bullet')
                $lvlText = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlText', $xmlns))
                [ref] $null = $lvlText.SetAttribute('val', $xmlns, $bulletMatrix[$listLevel.BulletStyle].Text)
                $rPr = $lvl.AppendChild($xmlDocument.CreateElement('w', 'rPr', $xmlns))
                $rFonts = $rPr.AppendChild($xmlDocument.CreateElement('w', 'rFonts', $xmlns))
                [ref] $null = $rFonts.SetAttribute('ascii', $xmlns, $bulletMatrix[$listLevel.BulletStyle].Font)
                [ref] $null = $rFonts.SetAttribute('hAnsi', $xmlns, $bulletMatrix[$listLevel.BulletStyle].Font)
                [ref] $null = $rFonts.SetAttribute('hint', $xmlns, 'default')
            }

            $lvlJc = $lvl.AppendChild($xmlDocument.CreateElement('w', 'lvlJc', $xmlns))

            if ($listLevel.IsNumbered)
            {
                $indent = $numberStyle.Indent
                $hanging = $numberStyle.Hanging

                if ($numberStyle.Align -eq 'Left')
                {
                    [ref] $null = $lvlJc.SetAttribute('val', $xmlns,'start')
                    if ($indent -eq 0)
                    {
                        $indent = ($level + 1) * 680
                    }
                    if ($hanging -eq 0)
                    {
                        $hanging = 400
                    }
                }
                elseif ($numberStyle.Align -eq 'Right')
                {
                    [ref] $null = $lvlJc.SetAttribute('val', $xmlns, 'end')
                    if ($indent -eq 0)
                    {
                        $indent = ($level + 1) * 680
                    }
                    if ($hanging -eq 0)
                    {
                        $hanging = 120
                    }
                }
            }
            else
            {
                [ref] $null = $lvlJc.SetAttribute('val', $xmlns, 'Right')
                $indent = ($level + 1) * 640
                $hanging = 280
            }

            $pPr = $lvl.AppendChild($xmlDocument.CreateElement('w', 'pPr', $xmlns))
            $ind = $pPr.AppendChild($xmlDocument.CreateElement('w', 'ind', $xmlns))

            [ref] $null = $ind.SetAttribute('left', $xmlns, $indent)
            [ref] $null = $ind.SetAttribute('hanging', $xmlns, $hanging)
        }

        return $abstractNum
    }
}

function Get-WordParagraphRun
{
<#
    .SYNOPSIS
        Returns an array of strings, split on tokens (PageNumber/TotalPages).
#>

    [CmdletBinding()]
    [OutputType([System.String[]])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [AllowEmptyString()]
        [System.String] $Text,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $NoSpace
    )
    process
    {
        $pageNumberMatch = '<!#\s*PageNumber\s*#!>'
        $totalPagesMatch = '<!#\s*TotalPages\s*#!>'
        $runs = New-Object -TypeName 'System.Collections.ArrayList'

        if (-not $NoSpace)
        {
            $Text = '{0} ' -f $Text
        }

        $pageNumbers = $Text -isplit $pageNumberMatch
        for ($pn = 0; $pn -lt $pageNumbers.Count; $pn++)
        {
            $totalPages = $pageNumbers[$pn] -isplit $totalPagesMatch
            for ($tp = 0; $tp -lt $totalPages.Count; $tp++)
            {
                if (-not [System.String]::IsNullOrWhitespace($totalPages[$tp]))
                {
                    $null = $runs.Add($totalPages[$tp])
                }
                if ($tp -lt ($totalPages.Count -1))
                {
                    $null = $runs.Add('<!#TOTALPAGES#!>')
                }
            }

            if ($pn -lt ($pageNumbers.Count -1))
            {
                $null = $runs.Add('<!#PAGENUMBER#!>')
            }
        }

        return $runs.ToArray()
    }
}

function Get-WordParagraphRunPr
{
<#
    .SYNOPSIS
        Outputs paragraph text/run (rPr) properties.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [System.Management.Automation.PSObject] $ParagraphRun,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $rPr = $XmlDocument.CreateElement('w', 'rPr', $xmlns)

        if ($ParagraphRun.HasStyle -eq $true)
        {
            $rStyle = $rPr.AppendChild($XmlDocument.CreateElement('w', 'rStyle', $xmlns))
            $characterStyle = '{0}Char' -f $ParagraphRun.Style
            [ref] $null = $rStyle.SetAttribute('val', $xmlns, $characterStyle)
        }
        if ($ParagraphRun.HasInlineStyle -eq $true)
        {
            if ($null -ne $ParagraphRun.Font)
            {
                $rFonts = $rPr.AppendChild($XmlDocument.CreateElement('w', 'rFonts', $xmlns))
                [ref] $null = $rFonts.SetAttribute('ascii', $xmlns, $ParagraphRun.Font[0])
                [ref] $null = $rFonts.SetAttribute('hAnsi', $xmlns, $ParagraphRun.Font[0])
            }

            if ($ParagraphRun.Bold -eq $true)
            {
                [ref] $null = $rPr.AppendChild($XmlDocument.CreateElement('w', 'b', $xmlns))
            }

            if ($ParagraphRun.Underline -eq $true)
            {
                $u = $rPr.AppendChild($XmlDocument.CreateElement('w', 'u', $xmlns))
                [ref] $null = $u.SetAttribute('val', $xmlns, 'single')
            }

            if ($ParagraphRun.Italic -eq $true)
            {
                [ref] $null = $rPr.AppendChild($XmlDocument.CreateElement('w', 'i', $xmlns))
            }

            if (-not [System.String]::IsNullOrEmpty($ParagraphRun.Color))
            {
                $wordColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $ParagraphRun.Color)
                $color = $rPr.AppendChild($XmlDocument.CreateElement('w', 'color', $xmlns))
                [ref] $null = $color.SetAttribute('val', $xmlns, $wordColor)
            }

            if (($null -ne $ParagraphRun.Size) -and ($ParagraphRun.Size -gt 0))
            {
                $sz = $rPr.AppendChild($XmlDocument.CreateElement('w', 'sz', $xmlns))
                [ref] $null = $sz.SetAttribute('val', $xmlns, $ParagraphRun.Size * 2)
            }
        }

        return $rPr
    }
}

function Get-WordSectionPr
{
<#
    .SYNOPSIS
        Outputs Office Open XML section element to set page size and margins.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory)]
        [System.Single] $PageWidth,

        [Parameter(Mandatory)]
        [System.Single] $PageHeight,

        [Parameter(Mandatory)]
        [System.Single] $PageMarginTop,

        [Parameter(Mandatory)]
        [System.Single] $PageMarginLeft,

        [Parameter(Mandatory)]
        [System.Single] $PageMarginBottom,

        [Parameter(Mandatory)]
        [System.Single] $PageMarginRight,

        [Parameter(Mandatory)]
        [System.String] $Orientation,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        if ($Orientation -eq 'Portrait')
        {
            $alignedPageHeight = $PageHeight
            $alignedPageWidth = $PageWidth
        }
        elseif ($Orientation -eq 'Landscape')
        {
            $alignedPageHeight = $PageWidth
            $alignedPageWidth = $PageHeight
        }

        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'

        $sectPr = $XmlDocument.CreateElement('w', 'sectPr', $xmlns)

        $pgSz = $sectPr.AppendChild($XmlDocument.CreateElement('w', 'pgSz', $xmlns))
        [ref] $null = $pgSz.SetAttribute('w', $xmlns, (ConvertTo-Twips -Millimeter $alignedPageWidth))
        [ref] $null = $pgSz.SetAttribute('h', $xmlns, (ConvertTo-Twips -Millimeter $alignedPageHeight))
        [ref] $null = $pgSz.SetAttribute('orient', $xmlns, $Orientation.ToLower())

        $pgMar = $sectPr.AppendChild($XmlDocument.CreateElement('w', 'pgMar', $xmlns))
        [ref] $null = $pgMar.SetAttribute('top', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginTop))
        [ref] $null = $pgMar.SetAttribute('header', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginTop))
        [ref] $null = $pgMar.SetAttribute('bottom', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginBottom))
        [ref] $null = $pgMar.SetAttribute('footer', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginBottom))
        [ref] $null = $pgMar.SetAttribute('left', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginLeft))
        [ref] $null = $pgMar.SetAttribute('right', $xmlns, (ConvertTo-Twips -Millimeter $PageMarginRight))

        if ($Document.Header.HasFirstPageHeader)
        {
            $headerReference = $sectPr.AppendChild($xmlDocument.CreateElement('w', 'headerReference', $xmlns))
            [ref] $null = $headerReference.SetAttribute('type', $xmlns, 'first')
            [ref] $null = $headerReference.SetAttribute('id', $xmlnsrelationships, 'rId3')
        }

        if ($Document.Header.HasDefaultHeader)
        {
            $headerReference = $sectPr.AppendChild($xmlDocument.CreateElement('w', 'headerReference', $xmlns))
            [ref] $null = $headerReference.SetAttribute('type', $xmlns, 'default')
            [ref] $null = $headerReference.SetAttribute('id', $xmlnsrelationships, 'rId4')
        }

        if ($Document.Footer.HasFirstPageFooter)
        {
            $footerReference = $sectPr.AppendChild($xmlDocument.CreateElement('w', 'footerReference', $xmlns))
            [ref] $null = $footerReference.SetAttribute('type', $xmlns, 'first')
            [ref] $null = $footerReference.SetAttribute('id', $xmlnsrelationships, 'rId5')
        }

        if ($Document.Footer.HasDefaultFooter)
        {
            $footerReference = $sectPr.AppendChild($xmlDocument.CreateElement('w', 'footerReference', $xmlns))
            [ref] $null = $footerReference.SetAttribute('type', $xmlns, 'default')
            [ref] $null = $footerReference.SetAttribute('id', $xmlnsrelationships, 'rId6')
        }

        if (-not $script:pscriboIsFirstSection)
        {
            [ref] $null = $sectPr.AppendChild($xmlDocument.CreateElement('w', 'titlePg', $xmlns))
            $script:pscriboIsFirstSection = $true
        }

        return $sectPr
    }
}

function Get-WordSettingsDocument
{
<#
    .SYNOPSIS
        Outputs Office Open XML settings document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param
    (
        [Parameter()]
        [System.Management.Automation.SwitchParameter] $UpdateFields
    )
    process
    {
        ## Create the Style.xml document
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $settingsDocument = New-Object -TypeName 'System.Xml.XmlDocument'
        [ref] $null = $settingsDocument.AppendChild($settingsDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))
        $settings = $settingsDocument.AppendChild($settingsDocument.CreateElement('w', 'settings', $xmlns))

        ## Set compatibility mode to Word 2013
        $compat = $settings.AppendChild($settingsDocument.CreateElement('w', 'compat', $xmlns))
        $compatSetting = $compat.AppendChild($settingsDocument.CreateElement('w', 'compatSetting', $xmlns))
        [ref] $null = $compatSetting.SetAttribute('name', $xmlns, 'compatibilityMode')
        [ref] $null = $compatSetting.SetAttribute('uri', $xmlns, 'http://schemas.microsoft.com/office/word')
        [ref] $null = $compatSetting.SetAttribute('val', $xmlns, 15)

        if ($UpdateFields)
        {
            $wupdateFields = $settings.AppendChild($settingsDocument.CreateElement('w', 'updateFields', $xmlns))
            [ref] $null = $wupdateFields.SetAttribute('val', $xmlns, 'true')
        }

        return $settingsDocument
    }
}

function Get-WordStyle
{
<#
    .SYNOPSIS
        Generates Word Xml style element from a PScribo document style.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        ## PScribo document style
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Style,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument,

        [Parameter(Mandatory)]
        [ValidateSet('Paragraph', 'Character')]
        [System.String] $Type
    )
    begin
    {
        ## Semi hide styles behind table styles (except default style!)
        $hiddenStyleIds = $Document.TableStyles.Values |
            ForEach-Object -Process { $_.HeaderStyle; $_.RowStyle; $_.AlternateRowStyle }
    }
    process
    {
        if ($Type -eq 'Paragraph')
        {
            $styleId = $Style.Id
            $styleName = $Style.Name
            $linkId = '{0}Char' -f $Style.Id
        }
        else
        {
            $styleId = '{0}Char' -f $Style.Id
            $styleName = '{0} Char' -f $Style.Name
            $linkId = $Style.Id
        }

        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $documentStyle = $XmlDocument.CreateElement('w', 'style', $xmlns)
        [ref] $null = $documentStyle.SetAttribute('type', $xmlns, $Type.ToLower())
        [ref] $null = $documentStyle.SetAttribute('styleId', $xmlns, $styleId)

        if ($Style.Id -eq $Document.DefaultStyle)
        {
            ## Set as default style
            [ref] $null = $documentStyle.SetAttribute('default', $xmlns, 1)
            $uiPriority = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'uiPriority', $xmlns))
            [ref] $null = $uiPriority.SetAttribute('val', $xmlns, 1)
        }
        elseif ($Style.Hidden -eq $true)
        {
            ## Semi hide style (headers and footers etc)
            [ref] $null = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'semiHidden', $xmlns))
        }
        elseif ($hiddenStyleIds -contains $Style.Id)
        {
            [ref] $null = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'semiHidden', $xmlns))
        }

        $documentStyleName = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'name', $xmlns))
        [ref] $null = $documentStyleName.SetAttribute('val', $xmlns, $styleName)

        $basedOn = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'basedOn', $xmlns))
        [ref] $null = $basedOn.SetAttribute('val', $xmlns, 'Normal')

        $link = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'link', $xmlns))
        [ref] $null = $link.SetAttribute('val', $xmlns, $linkId)

        $next = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'next', $xmlns))
        [ref] $null = $next.SetAttribute('val', $xmlns, 'Normal')

        [ref] $null = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'qFormat', $xmlns))

        $pPr = $documentStyle.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        [ref] $null = $pPr.AppendChild($XmlDocument.CreateElement('w', 'keepLines', $xmlns))

        $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlns))
        [ref] $null = $spacing.SetAttribute('before', $xmlns, 0)
        [ref] $null = $spacing.SetAttribute('after', $xmlns, 0)

        $jc = $pPr.AppendChild($XmlDocument.CreateElement('w', 'jc', $xmlns))
        if ($Style.Align.ToLower() -eq 'justify')
        {
            [ref] $null = $jc.SetAttribute('val', $xmlns, 'distribute')
        }
        else
        {
            [ref] $null = $jc.SetAttribute('val', $xmlns, $Style.Align.ToLower())
        }

        if ($Style.BackgroundColor)
        {
            $backgroundColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $Style.BackgroundColor)
            $shd = $pPr.AppendChild($XmlDocument.CreateElement('w', 'shd', $xmlns))
            [ref] $null = $shd.SetAttribute('val', $xmlns, 'clear')
            [ref] $null = $shd.SetAttribute('color', $xmlns, 'auto')
            [ref] $null = $shd.SetAttribute('fill', $xmlns, $backgroundColor)
        }

        $rPr = Get-WordStyleRunPr -Style $Style -XmlDocument $XmlDocument
        [ref] $null = $documentStyle.AppendChild($rPr)

        return $documentStyle
    }
}

function Get-WordStyleRunPr
{
<#
    .SYNOPSIS
        Generates Word run (rPr) formatting properties
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory)]
        [System.Management.Automation.PSObject] $Style,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'

        $rPr = $XmlDocument.CreateElement('w', 'rPr', $xmlns)

        $rFonts = $rPr.AppendChild($XmlDocument.CreateElement('w', 'rFonts', $xmlns))
        [ref] $null = $rFonts.SetAttribute('ascii', $xmlns, $Style.Font[0])
        [ref] $null = $rFonts.SetAttribute('hAnsi', $xmlns, $Style.Font[0])

        if ($Style.Bold)
        {
            [ref] $null = $rPr.AppendChild($XmlDocument.CreateElement('w', 'b', $xmlns))
        }

        if ($Style.Underline)
        {
            [ref] $null = $rPr.AppendChild($XmlDocument.CreateElement('w', 'u', $xmlns))
        }

        if ($Style.Italic)
        {
            [ref] $null = $rPr.AppendChild($XmlDocument.CreateElement('w', 'i', $xmlns))
        }

        $wordColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $Style.Color)
        $color = $rPr.AppendChild($XmlDocument.CreateElement('w', 'color', $xmlns))
        [ref] $null = $color.SetAttribute('val', $xmlns, $wordColor)

        $sz = $rPr.AppendChild($XmlDocument.CreateElement('w', 'sz', $xmlns))
        [ref] $null = $sz.SetAttribute('val', $xmlns, $Style.Size * 2)

        return $rPr
    }
}

function Get-WordStylesDocument
{
<#
    .SYNOPSIS
        Outputs Office Open XML style document
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    param
    (
        ## PScribo document styles
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Collections.Hashtable] $Styles,

        ## PScribo document tables styles
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Collections.Hashtable] $TableStyles
    )
    process
    {
        ## Create the Style.xml document
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $xmlDocument = New-Object -TypeName 'System.Xml.XmlDocument'
        [ref] $null = $xmlDocument.AppendChild($XmlDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes'))
        $documentStyles = $xmlDocument.AppendChild($xmlDocument.CreateElement('w', 'styles', $xmlns))

        ## Create the document default style
        $defaultStyle = $Styles[$Document.DefaultStyle]
        $docDefaults = $documentStyles.AppendChild($xmlDocument.CreateElement('w', 'docDefaults', $xmlns))
        $rPrDefault = $docDefaults.AppendChild($xmlDocument.CreateElement('w', 'rPrDefault', $xmlns))
        $rPr = Get-WordStyleRunPr -Style $defaultStyle -XmlDocument $XmlDocument
        [ref] $null = $rPrDefault.AppendChild($rPr)
        $pPrDefault = $docDefaults.AppendChild($xmlDocument.CreateElement('w', 'pPrDefault', $xmlns))
        $pPr = $pPrDefault.AppendChild($xmlDocument.CreateElement('w', 'pPr', $xmlns))
        $spacing = $pPr.AppendChild($xmlDocument.CreateElement('w', 'spacing', $xmlns))
        [ref] $null = $spacing.SetAttribute('after', $xmlns, '0')

        ## Create default style (will inherit from the document default style)
        $documentStyle = $documentStyles.AppendChild($xmlDocument.CreateElement('w', 'style', $xmlns))
        [ref] $null = $documentStyle.SetAttribute('type', $xmlns, 'paragraph')
        [ref] $null = $documentStyle.SetAttribute('default', $xmlns, '1')
        [ref] $null = $documentStyle.SetAttribute('styleId', $xmlns, $defaultStyle.Id)
        $documentStyleName = $documentStyle.AppendChild($xmlDocument.CreateElement('w', 'name', $xmlns))
        [ref] $null = $documentStyleName.SetAttribute('val', $xmlns, $defaultStyle.Id)
        [ref] $null = $documentStyle.AppendChild($xmlDocument.CreateElement('w', 'qFormat', $xmlns))

        ## Create default character style (will inherit from the document default style)
        $documentCharacterStyleId = '{0}Char' -f $defaultStyle.Id
        $documentCharacterStyle = $documentStyles.AppendChild($xmlDocument.CreateElement('w', 'style', $xmlns))
        [ref] $null = $documentCharacterStyle.SetAttribute('type', $xmlns, 'character')
        [ref] $null = $documentCharacterStyle.SetAttribute('default', $xmlns, '1')
        [ref] $null = $documentCharacterStyle.SetAttribute('styleId', $xmlns, 'name')
        $documentCharacterStyleName = $documentCharacterStyle.AppendChild($xmlDocument.CreateElement('w', 'name', $xmlns))
        [ref] $null = $documentCharacterStyleName.SetAttribute('val', $xmlns, $documentCharacterStyleId)

        $nonDefaultStyles = $Styles.Values | Where-Object { $_.Id -ne $defaultStyle.Id }
        foreach ($Style in $nonDefaultStyles)
        {
            $documentParagraphStyle = Get-WordStyle -Style $Style -XmlDocument $xmlDocument -Type Paragraph
            [ref] $null = $documentStyles.AppendChild($documentParagraphStyle)
            $documentCharacterStyle = Get-WordStyle -Style $Style -XmlDocument $xmlDocument -Type Character
            [ref] $null = $documentStyles.AppendChild($documentCharacterStyle)
        }

        foreach ($tableStyle in $TableStyles.Values)
        {
            $documentTableStyle = Get-WordTableStyle -TableStyle $tableStyle -XmlDocument $XmlDocument
            [ref] $null = $documentStyles.AppendChild($documentTableStyle)
        }

        return $xmlDocument
    }
}

function Get-WordTableCaption
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNull()]
        [System.Management.Automation.PSObject] $Table,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $tableStyle = Get-PScriboDocumentStyle -TableStyle $Table.Style
        $caption = ' {0}' -f $Table.Caption

        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $p = $XmlDocument.CreateElement('w', 'p', $xmlns)
        $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        $pStyle = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlns))
        [ref] $null = $pStyle.SetAttribute('val', $xmlns, $tableStyle.CaptionStyle)

        $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $t = $r.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
        [ref] $null = $t.SetAttribute('space', 'http://www.w3.org/XML/1998/namespace', 'preserve')
        $paddedTableCaption = '{0} ' -f $tableStyle.CaptionPrefix
        [ref] $null = $t.AppendChild($XmlDocument.CreateTextNode($paddedTableCaption))

        $fldSimple = $p.AppendChild($XmlDocument.CreateElement('w', 'fldSimple', $xmlns))
        [ref] $null = $fldSimple.SetAttribute('instr', $xmlns, ' SEQ Table \* ARABIC ')
        $r2 = $fldSimple.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $rPr2 = $r2.AppendChild($XmlDocument.CreateElement('w', 'rPr', $xmlns))
        [ref] $null = $rPr2.AppendChild($XmlDocument.CreateElement('w', 'noProof', $xmlns))
        $t2 = $r2.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
        [ref] $null = $t2.AppendChild($XmlDocument.CreateTextNode($Table.CaptionNumber))

        $r3 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $rPr3 = $r3.AppendChild($XmlDocument.CreateElement('w', 'rPr', $xmlns))
        [ref] $null = $rPr3.AppendChild($XmlDocument.CreateElement('w', 'noProof', $xmlns))
        $t3 = $r3.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
        [ref] $null = $t3.SetAttribute('space', 'http://www.w3.org/XML/1998/namespace', 'preserve')
        [ref] $null = $t3.AppendChild($XmlDocument.CreateTextNode($caption))

        return $p
    }
}

function Get-WordTableConditionalFormattingValue
{
<#
    .SYNOPSIS
        Generates legacy table conditioning formatting value (for LibreOffice).
#>

    [CmdletBinding()]
    [OutputType([System.Int32])]
    param
    (
        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $HasFirstRow,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $HasLastRow,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $HasFirstColumn,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $HasLastColumn,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $NoHorizontalBand,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $NoVerticalBand
    )
    process
    {
        $val = 0
        if ($HasFirstRow)
        {
            $val = $val -bor 0x20
        }
        if ($HasLastRow)
        {
            $val = $val -bor 0x40
        }
        if ($HasFirstColumn)
        {
            $val = $val -bor 0x80
        }
        if ($HasLastColumn)
        {
            $val = $val -bor 0x100
        }
        if ($NoHorizontalBand)
        {
            $val = $val -bor 0x200
        }
        if ($NoVerticalBand)
        {
            $val = $val -bor 0x400
        }
        return $val
    }
}

function Get-WordTablePr
{
<#
    .SYNOPSIS
        Creates a scaffold Word <w:tblPr> element
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNull()]
        [System.Management.Automation.PSObject] $Table,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $tableStyle = $Document.TableStyles[$Table.Style]
        $tblPr = $XmlDocument.CreateElement('w', 'tblPr', $xmlns)

        $tblStyle = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblStyle', $xmlns))
        [ref] $null = $tblStyle.SetAttribute('val', $xmlns, $tableStyle.Id)

        $tblInd = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblInd', $xmlns))
        [ref] $null = $tblInd.SetAttribute('w', $xmlns, (720 * $Table.Tabs))
        [ref] $null = $tblInd.SetAttribute('type', $xmlns, 'dxa')

        $getWordTableRenderWidthMmParams = @{
            TableWidth  = $Table.Width
            Tabs        = $Table.Tabs
            Orientation = $Table.Orientation
        }
        $tableRenderWidthMm = Get-WordTableRenderWidthMm @getWordTableRenderWidthMmParams
        $tableRenderWidthTwips = ConvertTo-Twips -Millimeter $tableRenderWidthMm

        $tblLayout = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblLayout', $xmlns))
        if ($Table.ColumnWidths -or ($Table.Width -gt 0 -and $Table.Width -le 100))
        {
            [ref] $null = $tblLayout.SetAttribute('type', $xmlns, 'fixed')
        }
        else
        {
            [ref] $null = $tblLayout.SetAttribute('type', $xmlns, 'autofit')
        }

        $tableAlignment = @{ Left = 'start'; Center = 'center'; Right = 'end'; }
        $jc =  $tblPr.AppendChild($XmlDocument.CreateElement('w', 'jc', $xmlns))
        [ref] $null = $jc.SetAttribute('val', $xmlns, $tableAlignment[$tableStyle.Align])

        if ($Table.Width -gt 0)
        {
            $tblW = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblW', $xmlns))
            [ref] $null = $tblW.SetAttribute('w', $xmlns, $tableRenderWidthTwips)
            [ref] $null = $tblW.SetAttribute('type', $xmlns, 'dxa')
        }

        $tblLook = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblLook', $xmlns))
        $isFirstRow = ($Table.IsKeyedList -eq $true -or $Table.IsList -eq $false)
        $isFirstColumn = ($Table.IsKeyedList -eq $true -or $Table.IsList -eq $true)
        ## LibreOffice requires legacy conditional formatting value (#99)
        $val = Get-WordTableConditionalFormattingValue -HasFirstRow:$isFirstRow -HasFirstColumn:$isFirstColumn -NoVerticalBand
        [ref] $null = $tblLook.SetAttribute('val', $xmlns, ('{0:x4}' -f $val))
        [ref] $null = $tblLook.SetAttribute('firstRow', $xmlns, ($isFirstRow -as [System.Int32]))
        [ref] $null = $tblLook.SetAttribute('lastRow', $xmlns, '0')
        [ref] $null = $tblLook.SetAttribute('firstColumn', $xmlns, ($isFirstColumn -as [System.Int32]))
        [ref] $null = $tblLook.SetAttribute('lastColumn', $xmlns, '0')
        [ref] $null = $tblLook.SetAttribute('noHBand', $xmlns, '0')
        [ref] $null = $tblLook.SetAttribute('noVBand', $xmlns, '1')

        if ($tableStyle.BorderWidth -gt 0)
        {
            $tblBorders = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblBorders', $xmlns))
            foreach ($border in @('top', 'bottom', 'start', 'end', 'insideH', 'insideV'))
            {
                $borderType = $tblBorders.AppendChild($XmlDocument.CreateElement('w', $border, $xmlns))
                [ref] $null = $borderType.SetAttribute('sz', $xmlns, (ConvertTo-Octips $tableStyle.BorderWidth))
                [ref] $null = $borderType.SetAttribute('val', $xmlns, 'single')
                [ref] $null = $borderType.SetAttribute('color', $xmlns, (ConvertTo-WordColor -Color $tableStyle.BorderColor))
            }
        }

        $tblCellMar = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblCellMar', $xmlns))
        $top = $tblCellMar.AppendChild($XmlDocument.CreateElement('w', 'top', $xmlns))
        [ref] $null = $top.SetAttribute('w', $xmlns, (ConvertTo-Twips $tableStyle.PaddingTop))
        [ref] $null = $top.SetAttribute('type', $xmlns, 'dxa')
        $start = $tblCellMar.AppendChild($XmlDocument.CreateElement('w', 'start', $xmlns))
        [ref] $null = $start.SetAttribute('w', $xmlns, (ConvertTo-Twips $tableStyle.PaddingLeft))
        [ref] $null = $start.SetAttribute('type', $xmlns, 'dxa')
        $bottom = $tblCellMar.AppendChild($XmlDocument.CreateElement('w', 'bottom', $xmlns))
        [ref] $null = $bottom.SetAttribute('w', $xmlns, (ConvertTo-Twips $tableStyle.PaddingBottom))
        [ref] $null = $bottom.SetAttribute('type', $xmlns, 'dxa')
        $end = $tblCellMar.AppendChild($XmlDocument.CreateElement('w', 'end', $xmlns))
        [ref] $null = $end.SetAttribute('w', $xmlns, (ConvertTo-Twips $tableStyle.PaddingRight))
        [ref] $null = $end.SetAttribute('type', $xmlns, 'dxa')

        $spacing = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlns))
        [ref] $null = $spacing.SetAttribute('before', $xmlns, 72)
        [ref] $null = $spacing.SetAttribute('after', $xmlns, 72)

        return $tblPr
    }
}

function Get-WordTableRenderWidthMm
{
<#
    .SYNOPSIS
        Calcualtes a table's (maximum) rendering size in millimetres.
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateRange(0, 100)]
        [System.UInt16] $TableWidth,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ValidateRange(0, 10)]
        [System.UInt16] $Tabs,

        [Parameter(Mandatory, ValueFromPipeline)]
        [System.String] $Orientation
    )
    process
    {
        if ($TableWidth -eq 0)
        {
            ## Word will autofit contents as necessary, but LibreOffice won't
            ## so we just have assume that we're using all available width
            $TableWidth = 100
        }
        if ($Orientation -eq 'Portrait')
        {
            $pageWidthMm = $Document.Options['PageWidth'] - ($Document.Options['MarginLeft'] + $Document.Options['MarginRight'])
        }
        elseif ($Orientation -eq 'Landscape')
        {
            $pageWidthMm = $Document.Options['PageHeight'] - ($Document.Options['MarginLeft'] + $Document.Options['MarginRight'])
        }
        $indentWidthMm = ConvertTo-Mm -Point ($Tabs * 36)
        $tableWidthRenderMm = (($pageWidthMm / 100) * $TableWidth) + $indentWidthMm
        if ($tableWidthRenderMm -gt $pageWidthMm)
        {
            ## We now need to deal with tables being pushed outside the page margin so just return the maximum permitted
            $tableWidthRenderMm = $pageWidthMm - $indentWidthMm
            Write-PScriboMessage -Message ($localized.TableWidthOverflowWarning -f $tableWidthRenderMm) -IsWarning
        }
        return $tableWidthRenderMm
    }
}

function Get-WordTableStyle
{
<#
    .SYNOPSIS
        Generates Word Xml table style element from a PScribo document table style.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        ## PScribo document table style
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $TableStyle,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'

        $style = $XmlDocument.CreateElement('w', 'style', $xmlns)
        [ref] $null = $style.SetAttribute('type', $xmlns, 'table')
        [ref] $null = $style.SetAttribute('customStyle', $xmlns, '1')
        [ref] $null = $style.SetAttribute('styleId', $xmlns, $tableStyle.Id)

        $name = $style.AppendChild($XmlDocument.CreateElement('w', 'name', $xmlns))
        [ref] $null = $name.SetAttribute('val', $xmlns, $TableStyle.Id)

        $basedOn = $style.AppendChild($XmlDocument.CreateElement('w', 'basedOn', $xmlns))
        [ref] $null = $basedOn.SetAttribute('val', $xmlns, 'TableNormal')

        $tblPr = $style.AppendChild($XmlDocument.CreateElement('w', 'tblPr', $xmlns))
        $tblStyleRowBandSize = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblStyleRowBandSize', $xmlns))
        [ref] $null = $tblStyleRowBandSize.SetAttribute('val', $xmlns, 1)

        if ($TableStyle.BorderWidth -gt 0)
        {
            $tblBorders = $tblPr.AppendChild($XmlDocument.CreateElement('w', 'tblBorders', $xmlns))
            foreach ($border in @('top', 'bottom', 'start', 'end', 'insideH', 'insideV'))
            {
                $borderType = $tblBorders.AppendChild($XmlDocument.CreateElement('w', $border, $xmlns))
                [ref] $null = $borderType.SetAttribute('sz', $xmlns, (ConvertTo-Octips $tableStyle.BorderWidth))
                [ref] $null = $borderType.SetAttribute('val', $xmlns, 'single')
                $borderColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $tableStyle.BorderColor)
                [ref] $null = $borderType.SetAttribute('color', $xmlns, (ConvertTo-WordColor -Color $borderColor))
            }
        }

        [ref] $null = $Style.AppendChild((Get-WordTableStylePr -Style $Document.Styles[$TableStyle.HeaderStyle] -Type HeaderRow -XmlDocument $XmlDocument))
        [ref] $null = $Style.AppendChild((Get-WordTableStylePr -Style $Document.Styles[$TableStyle.HeaderStyle] -Type HeaderColumn -XmlDocument $XmlDocument))
        [ref] $null = $Style.AppendChild((Get-WordTableStylePr -Style $Document.Styles[$TableStyle.RowStyle] -Type Row -XmlDocument $XmlDocument))
        [ref] $null = $Style.AppendChild((Get-WordTableStylePr -Style $Document.Styles[$TableStyle.AlternateRowStyle] -Type AlternateRow -XmlDocument $XmlDocument))

        return $style
    }
}

function Get-WordTableStylePr
{
<#
    .SYNOPSIS
        Generates Word table style (tblStylePr) formatting properties for specified table style type
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory)]
        [System.Management.Automation.PSObject] $Style,

        [Parameter(Mandatory)]
        [ValidateSet('HeaderRow', 'HeaderColumn', 'Row', 'AlternateRow')]
        [System.String] $Type,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        if ($Type -eq 'HeaderRow')
        {
            $tblStylePrType = 'firstRow'
        }
        elseif ($Type -eq 'HeaderColumn')
        {
            $tblStylePrType = 'firstCol'
        }
        elseif ($Type -eq 'Row')
        {
            $tblStylePrType = 'band1Horz'
        }
        elseif ($Type -eq 'AlternateRow')
        {
            $tblStylePrType = 'band2Horz'
        }

        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $tblStylePr = $XmlDocument.CreateElement('w', 'tblStylePr', $xmlns)
        [ref] $null = $tblStylePr.SetAttribute('type', $xmlns, $tblStylePrType)

        $rPr = Get-WordStyleRunPr -Style $Style -XmlDocument $XmlDocument
        [ref] $null = $tblStylePr.AppendChild($rPr)

        $null = $tblStylePr.AppendChild($XmlDocument.CreateElement('w', 'tblPr', $xmlns))
        $tcPr = $tblStylePr.AppendChild($XmlDocument.CreateElement('w', 'tcPr', $xmlns))
        if (-not [System.String]::IsNullOrEmpty($Style.BackgroundColor))
        {
            $shd = $tcPr.AppendChild($XmlDocument.CreateElement('w', 'shd', $xmlns))
            [ref] $null = $shd.SetAttribute('val', $xmlns, 'clear')
            [ref] $null = $shd.SetAttribute('color', $xmlns, 'auto')
            $backgroundColor = ConvertTo-WordColor -Color $Style.BackgroundColor
            [ref] $null = $shd.SetAttribute('fill', $xmlns, $backgroundColor)
        }

        $pPr = $tblStylePr.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        $jc = $pPr.AppendChild($XmlDocument.CreateElement('w', 'jc', $xmlns))
        if ($Style.Align.ToLower() -eq 'justify')
        {
            [ref] $null = $jc.SetAttribute('val', $xmlns, 'distribute')
        }
        else
        {
            [ref] $null = $jc.SetAttribute('val', $xmlns, $Style.Align.ToLower())
        }

        return $tblStylePr
    }
}

function Out-WordBlankLine
{
<#
    .SYNOPSIS
        Output formatted Word xml blank line (empty paragraph).
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $BlankLine,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument,

        [Parameter(Mandatory)]
        [System.Xml.XmlElement] $Element
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        for ($i = 0; $i -lt $BlankLine.LineCount; $i++) {
            [ref] $null = $Element.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
        }
    }
}

function Out-WordDocument
{
<#
    .SYNOPSIS
        Microsoft Word output plugin for PScribo.

    .DESCRIPTION
        Outputs a Word document representation of a PScribo document object.
  #>

    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'pluginName')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter','Options')]
    [OutputType([System.IO.FileInfo])]
    param
    (
        ## ThePScribo document object to convert to a text document
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Document,

        ## Output directory path for the .txt file
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ValidateNotNull()]
        [System.String] $Path,

        ### Hashtable of all plugin supported options
        [Parameter()]
        [AllowNull()]
        [System.Collections.Hashtable] $Options
    )
    process
    {
        $pluginName = 'Word'
        $stopwatch = [Diagnostics.Stopwatch]::StartNew()
        Write-PScriboMessage -Message ($localized.DocumentProcessingStarted -f $Document.Name)

        ## Generate the Word 'document.xml' document part
        $documentXml = Get-WordDocument -Document $Document

        ## Generate the Word 'styles.xml' document part
        $stylesXml = Get-WordStylesDocument -Styles $Document.Styles -TableStyles $Document.TableStyles

        ## Generate the Word 'settings.xml' document part
        $updateFields = (($Document.Properties['TOCs']) -and ($Document.Properties['TOCs'] -gt 0))
        $settingsXml = Get-WordSettingsDocument -UpdateFields:$updateFields

        #Convert relative or PSDrive based path to the absolute filesystem path
        $absolutePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
        $destinationPath = Join-Path -Path $absolutePath ('{0}.docx' -f $Document.Name)
        if ($PSVersionTable['PSEdition'] -ne 'Core')
        {
            ## "Unable to determine the identity of the domain" fix (https://github.com/AsBuiltReport/AsBuiltReport.Core/issues/17)
            $currentAppDomain = [System.Threading.Thread]::GetDomain()
            $securityIdentityField = $currentAppDomain.GetType().GetField("_SecurityIdentity", ([System.Reflection.BindingFlags]::Instance -bOr [System.Reflection.BindingFlags]::NonPublic))
            $replacementEvidence = New-Object -TypeName 'System.Security.Policy.Evidence'
            $securityZoneMyComputer = New-Object -TypeName 'System.Security.Policy.Zone' -ArgumentList @([System.Security.SecurityZone]::MyComputer)
            $replacementEvidence.AddHost($securityZoneMyComputer)
            $securityIdentityField.SetValue($currentAppDomain, $replacementEvidence)
            ## WindowsBase.dll is not included in Core PowerShell
            Add-Type -AssemblyName WindowsBase
        }
        try
        {
            $package = [System.IO.Packaging.Package]::Open($destinationPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite)
        }
        catch
        {
            Write-PScriboMessage -Message ($localized.OpenPackageError -f $destinationPath) -IsWarning
            throw $_
        }

        ## Create document.xml part
        $documentUri = New-Object -TypeName System.Uri -ArgumentList ('/word/document.xml', [System.UriKind]::Relative)
        Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $documentUri)
        $documentPart = $package.CreatePart($documentUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml')
        $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($documentPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
        $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
        Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $documentUri)
        $documentXml.Save($xmlWriter)
        $xmlWriter.Dispose()
        $streamWriter.Close()

        ## Create styles.xml part
        $stylesUri = New-Object -TypeName System.Uri -ArgumentList ('/word/styles.xml', [System.UriKind]::Relative)
        Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $stylesUri)
        $stylesPart = $package.CreatePart($stylesUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml')
        $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($stylesPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
        $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
        Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $stylesUri)
        $stylesXml.Save($xmlWriter)
        $xmlWriter.Dispose()
        $streamWriter.Close()

        ## Create settings.xml part
        $settingsUri = New-Object -TypeName System.Uri -ArgumentList ('/word/settings.xml', [System.UriKind]::Relative)
        Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $settingsUri)
        $settingsPart = $package.CreatePart($settingsUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml')
        $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($settingsPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
        $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
        Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $settingsUri)
        $settingsXml.Save($xmlWriter)
        $xmlWriter.Dispose()
        $streamWriter.Close()

        Out-WordHeaderFooterDocument -Document $Document -Package $package

        ## Create the Package relationships
        Write-PScriboMessage -Message $localized.GeneratingPackageRelationships
        $officeDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument'
        $stylesDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles'
        $settingsDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings'

        [ref] $null = $package.CreateRelationship($documentUri, [System.IO.Packaging.TargetMode]::Internal, $officeDocumentUri, 'rId1')
        [ref] $null = $documentPart.CreateRelationship($stylesUri, [System.IO.Packaging.TargetMode]::Internal, $stylesDocumentUri, 'rId1')
        [ref] $null = $documentPart.CreateRelationship($settingsUri, [System.IO.Packaging.TargetMode]::Internal, $settingsDocumentUri, 'rId2')

        $headerDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/header'
        if ($Document.Header.HasFirstPageHeader)
        {
            $firstPageHeaderUri = New-Object -TypeName System.Uri -ArgumentList ('/word/firstPageHeader.xml', [System.UriKind]::Relative)
            [ref] $null = $documentPart.CreateRelationship($firstPageHeaderUri, [System.IO.Packaging.TargetMode]::Internal, $headerDocumentUri, 'rId3')
        }
        if ($Document.Header.HasDefaultHeader)
        {
            $defaultHeaderUri = New-Object -TypeName System.Uri -ArgumentList ('/word/defaultHeader.xml', [System.UriKind]::Relative)
            [ref] $null = $documentPart.CreateRelationship($defaultHeaderUri, [System.IO.Packaging.TargetMode]::Internal, $headerDocumentUri, 'rId4')
        }

        $footerDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer'
        if ($Document.Footer.HasFirstPageFooter)
        {
            $firstPageFooterUri = New-Object -TypeName System.Uri -ArgumentList ('/word/firstPageFooter.xml', [System.UriKind]::Relative)
            [ref] $null = $documentPart.CreateRelationship($firstPageFooterUri, [System.IO.Packaging.TargetMode]::Internal, $footerDocumentUri, 'rId5')
        }
        if ($Document.Footer.HasDefaultFooter)
        {
            $defaultFooterUri = New-Object -TypeName System.Uri -ArgumentList ('/word/defaultFooter.xml', [System.UriKind]::Relative)
            [ref] $null = $documentPart.CreateRelationship($defaultFooterUri, [System.IO.Packaging.TargetMode]::Internal, $footerDocumentUri, 'rId6')
        }

        ## Create numbering.xml part
        $numberingUri = New-Object -TypeName System.Uri -ArgumentList ('/word/numbering.xml', [System.UriKind]::Relative)
        Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $numberingUri)
        $numberingPart = $package.CreatePart($numberingUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml')
        $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($numberingPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
        $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
        Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $numberingUri)
        $numberingXml = Get-WordNumberingDocument -Lists $Document.Lists
        $numberingXml.Save($xmlWriter)
        $xmlWriter.Dispose()
        $streamWriter.Close()

        $numberingDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering'
        [ref] $null = $documentPart.CreateRelationship($numberingUri, [System.IO.Packaging.TargetMode]::Internal, $numberingDocumentUri, 'rId7')

        ## Process images (assuming we have a section, e.g. example03.ps1)
        if ($Document.Sections.Count -gt 0)
        {
            $imageDocumentUri = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
            foreach ($image in (Get-PScriboImage -Section $Document.Sections))
            {
                try
                {
                    $uri = ('/word/media/{0}' -f $image.Name)
                    $partName = New-Object -TypeName 'System.Uri' -ArgumentList ($uri, [System.UriKind]'Relative')
                    $part = $package.CreatePart($partName, $image.MimeType)
                    $stream = $part.GetStream()
                    $stream.Write($image.Bytes, 0, $image.Bytes.Length)
                    $stream.Close()
                    [ref] $null = $documentPart.CreateRelationship($partName, [System.IO.Packaging.TargetMode]::Internal, $imageDocumentUri, $image.Name)
                }
                catch
                {
                    throw $_
                }
                finally
                {
                    if ($null -ne $stream) { $stream.Close() }
                }
            }
        }

        $package.Flush()
        $package.Close()
        $stopwatch.Stop()
        Write-PScriboMessage -Message ($localized.DocumentProcessingCompleted -f $Document.Name)

        if ($stopwatch.Elapsed.TotalSeconds -gt 90)
        {
            Write-PScriboMessage -Message ($localized.TotalProcessingTimeMinutes -f $stopwatch.Elapsed.TotalMinutes)
        }
        else
        {
            Write-PScriboMessage -Message ($localized.TotalProcessingTimeSeconds -f $stopwatch.Elapsed.TotalSeconds)
        }

        Write-Output -InputObject (Get-Item -Path $destinationPath)
    }
}

function Out-WordHeaderFooterDocument
{
    [CmdletBinding()]
    param
    (
        ## ThePScribo document object to convert to a text document
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Document,

        [Parameter(Mandatory)]
        [System.IO.Packaging.Package] $Package
    )
    process
    {
        ## Create headers
        if ($Document.Header.HasFirstPageHeader)
        {
            $firstPageHeaderUri = New-Object -TypeName System.Uri -ArgumentList ('/word/firstPageHeader.xml', [System.UriKind]::Relative)
            $firstPageHeaderXml = Get-WordHeaderFooterDocument -HeaderFooter $Document.Header.FirstPageHeader -IsHeader
            Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $firstPageHeaderUri)
            $headerPart = $Package.CreatePart($firstPageHeaderUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml')
            $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($headerPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
            $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
            Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $firstPageHeaderUri)
            $firstPageHeaderXml.Save($xmlWriter)
            $xmlWriter.Dispose()
            $streamWriter.Close()
        }

        if ($Document.Header.HasDefaultHeader)
        {
            $defaultHeaderUri = New-Object -TypeName System.Uri -ArgumentList ('/word/defaultHeader.xml', [System.UriKind]::Relative)
            $defaultHeaderXml = Get-WordHeaderFooterDocument -HeaderFooter $Document.Header.DefaultHeader -IsHeader
            Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $defaultHeaderUri)
            $headerPart = $Package.CreatePart($defaultHeaderUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml')
            $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($headerPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
            $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
            Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $defaultHeaderUri)
            $defaultHeaderXml.Save($xmlWriter)
            $xmlWriter.Dispose()
            $streamWriter.Close()
        }

        ## Create footers
        if ($Document.Footer.HasFirstPageFooter)
        {
            $firstPageFooterUri = New-Object -TypeName System.Uri -ArgumentList ('/word/firstPageFooter.xml', [System.UriKind]::Relative)
            $firstPageFooterXml = Get-WordHeaderFooterDocument -HeaderFooter $Document.Footer.FirstPageFooter -IsFooter
            Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $firstPageFooterUri)
            $footerPart = $Package.CreatePart($firstPageFooterUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml')
            $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($footerPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
            $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
            Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $firstPageFooterUri)
            $firstPageFooterXml.Save($xmlWriter)
            $xmlWriter.Dispose()
            $streamWriter.Close()
        }

        if ($Document.Footer.HasDefaultFooter)
        {
            $defaultFooterUri = New-Object -TypeName System.Uri -ArgumentList ('/word/defaultFooter.xml', [System.UriKind]::Relative)
            $defaultFooterXml = Get-WordHeaderFooterDocument -HeaderFooter $Document.Footer.DefaultFooter -IsFooter
            Write-PScriboMessage -Message ($localized.ProcessingDocumentPart -f $defaultFooterUri)
            $footerPart = $Package.CreatePart($defaultFooterUri, 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml')
            $streamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($footerPart.GetStream([System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite))
            $xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
            Write-PScriboMessage -Message ($localized.WritingDocumentPart -f $defaultFooterUri)
            $defaultFooterXml.Save($xmlWriter)
            $xmlWriter.Dispose()
            $streamWriter.Close()
        }
    }
}

function Out-WordImage
{
<#
    .SYNOPSIS
        Output Image to Word.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Image,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlnsMain = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $xmlnswpDrawingWordProcessing = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
        $xmlnsDrawingMain = 'http://schemas.openxmlformats.org/drawingml/2006/main'
        $xmlnsDrawingPicture = 'http://schemas.openxmlformats.org/drawingml/2006/picture'
        $xmlnsRelationships = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'

        $p = $XmlDocument.CreateElement('w', 'p', $xmlnsMain)
        $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlnsMain))
        $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlnsMain))
        [ref] $null = $spacing.SetAttribute('before', $xmlnsMain, 0)
        [ref] $null = $spacing.SetAttribute('after', $xmlnsMain, 0)

        $jc = $pPr.AppendChild($XmlDocument.CreateElement('w', 'jc', $xmlnsMain))
        [ref] $null = $jc.SetAttribute('val', $xmlnsMain, $Image.Align.ToLower())

        $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlnsMain))
        [ref] $null = $r.AppendChild($XmlDocument.CreateElement('w', 'rPr', $xmlnsMain))
        $drawing = $r.AppendChild($XmlDocument.CreateElement('w', 'drawing', $xmlnsMain))
        $inline = $drawing.AppendChild($XmlDocument.CreateElement('wp', 'inline', $xmlnswpDrawingWordProcessing))
        [ref] $null = $inline.SetAttribute('distT', '0')
        [ref] $null = $inline.SetAttribute('distB', '0')
        [ref] $null = $inline.SetAttribute('distL', '0')
        [ref] $null = $inline.SetAttribute('distR', '0')

        $extent = $inline.AppendChild($XmlDocument.CreateElement('wp', 'extent', $xmlnswpDrawingWordProcessing))
        [ref] $null = $extent.SetAttribute('cx', $Image.WidthEm)
        [ref] $null = $extent.SetAttribute('cy', $Image.HeightEm)

        $effectExtent = $inline.AppendChild($XmlDocument.CreateElement('wp', 'effectExtent', $xmlnswpDrawingWordProcessing))
        [ref] $null = $effectExtent.SetAttribute('l', '0')
        [ref] $null = $effectExtent.SetAttribute('t', '0')
        [ref] $null = $effectExtent.SetAttribute('r', '0')
        [ref] $null = $effectExtent.SetAttribute('b', '0')

        $docPr = $inline.AppendChild($XmlDocument.CreateElement('wp', 'docPr', $xmlnswpDrawingWordProcessing))
        [ref] $null = $docPr.SetAttribute('id', $Image.ImageNumber)
        [ref] $null = $docPr.SetAttribute('name', $Image.Name)
        [ref] $null = $docPr.SetAttribute('descr', $Image.Name)

        $cNvGraphicFramePr = $inline.AppendChild($XmlDocument.CreateElement('wp', 'cNvGraphicFramePr', $xmlnswpDrawingWordProcessing))
        $graphicFrameLocks = $cNvGraphicFramePr.AppendChild($XmlDocument.CreateElement('a', 'graphicFrameLocks', $xmlnsDrawingMain))
        [ref] $null = $graphicFrameLocks.SetAttribute('noChangeAspect', '1')

        $graphic = $inline.AppendChild($XmlDocument.CreateElement('a', 'graphic', $xmlnsDrawingMain))
        $graphicData = $graphic.AppendChild($XmlDocument.CreateElement('a', 'graphicData', $xmlnsDrawingMain))
        [ref] $null = $graphicData.SetAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/picture')

        $pic = $graphicData.AppendChild($XmlDocument.CreateElement('pic', 'pic', $xmlnsDrawingPicture))
        $nvPicPr = $pic.AppendChild($XmlDocument.CreateElement('pic', 'nvPicPr', $xmlnsDrawingPicture))
        $cNvPr = $nvPicPr.AppendChild($XmlDocument.CreateElement('pic', 'cNvPr', $xmlnsDrawingPicture))
        [ref] $null = $cNvPr.SetAttribute('id', $Image.ImageNumber)
        [ref] $null = $cNvPr.SetAttribute('name', $Image.Name)
        [ref] $null = $cNvPr.SetAttribute('descr', $Image.Name)
        $cNvPicPr = $nvPicPr.AppendChild($XmlDocument.CreateElement('pic', 'cNvPicPr', $xmlnsDrawingPicture))
        $picLocks = $cNvPicPr.AppendChild($XmlDocument.CreateElement('a', 'picLocks', $xmlnsDrawingMain))
        [ref] $null = $picLocks.SetAttribute('noChangeAspect', '1')
        [ref] $null = $picLocks.SetAttribute('noChangeArrowheads', '1')

        $blipFill = $pic.AppendChild($XmlDocument.CreateElement('pic', 'blipFill', $xmlnsDrawingPicture))
        $blip = $blipFill.AppendChild($XmlDocument.CreateElement('a', 'blip', $xmlnsDrawingMain))
        [ref] $null = $blip.SetAttribute('embed', $xmlnsRelationships, $Image.Name)
        [ref] $null = $blip.SetAttribute('cstate', 'print')
        $extlst = $blip.AppendChild($XmlDocument.CreateElement('a', 'extlst', $xmlnsDrawingMain))
        $ext = $extlst.AppendChild($XmlDocument.CreateElement('a', 'ext', $xmlnsDrawingMain))
        [ref] $null = $ext.SetAttribute('uri', '')
        [ref] $null = $blipFill.AppendChild($XmlDocument.CreateElement('a', 'srcRect', $xmlnsDrawingMain))
        $stretch = $blipFill.AppendChild($XmlDocument.CreateElement('a', 'stretch', $xmlnsDrawingMain))
        [ref] $null = $stretch.AppendChild($XmlDocument.CreateElement('a', 'fillRect', $xmlnsDrawingMain))

        $spPr = $pic.AppendChild($XmlDocument.CreateElement('pic', 'spPr', $xmlnsDrawingPicture))
        [ref] $null = $spPr.SetAttribute('bwMode', 'auto')
        $xfrm = $spPr.AppendChild($XmlDocument.CreateElement('a', 'xfrm', $xmlnsDrawingMain))
        $off = $xfrm.AppendChild($XmlDocument.CreateElement('a', 'off', $xmlnsDrawingMain))
        [ref] $null = $off.SetAttribute('x', '0')
        [ref] $null = $off.SetAttribute('y', '0')
        $ext = $xfrm.AppendChild($XmlDocument.CreateElement('a', 'ext', $xmlnsDrawingMain))
        [ref] $null = $ext.SetAttribute('cx', $Image.WidthEm)
        [ref] $null = $ext.SetAttribute('cy', $Image.HeightEm)

        $prstGeom = $spPr.AppendChild($XmlDocument.CreateElement('a', 'prstGeom', $xmlnsDrawingMain))
        [ref] $null = $prstGeom.SetAttribute('prst', 'rect')
        [ref] $null = $prstGeom.AppendChild($XmlDocument.CreateElement('a', 'avLst', $xmlnsDrawingMain))

        [ref] $null = $spPr.AppendChild($XmlDocument.CreateElement('a', 'noFill', $xmlnsDrawingMain))

        $ln = $spPr.AppendChild($XmlDocument.CreateElement('a', 'ln', $xmlnsDrawingMain))
        [ref] $null = $ln.AppendChild($XmlDocument.CreateElement('a', 'noFill', $xmlnsDrawingMain))

        return $p
    }
}

function Out-WordLineBreak
{
<#
    .SYNOPSIS
        Output formatted Word line break.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter','LineBreak')]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $LineBreak,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $p = $XmlDocument.CreateElement('w', 'p', $xmlns)
        $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        $pBdr = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pBdr', $xmlns))
        $bottom = $pBdr.AppendChild($XmlDocument.CreateElement('w', 'bottom', $xmlns))
        [ref] $null = $bottom.SetAttribute('val', $xmlns, 'single')
        [ref] $null = $bottom.SetAttribute('sz', $xmlns, 6)
        [ref] $null = $bottom.SetAttribute('space', $xmlns, 1)
        [ref] $null = $bottom.SetAttribute('color', $xmlns, 'auto')

        return $p
    }
}

function Out-WordList
{
<#
    .SYNOPSIS
        Output formatted Word list.
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $List,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Xml.XmlElement] $Element,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Xml.XmlDocument] $XmlDocument,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Int32] $NumberId,

        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $NotRoot
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'

        foreach ($item in $List.Items)
        {
            if ($item.Type -eq 'PScribo.Item')
            {
                $p = $Element.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
                $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))

                if ($List.HasStyle)
                {
                    $pStyle = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlns))
                    [ref] $null = $pStyle.SetAttribute('val', $xmlns, $List.Style)
                }

                $numPr = $pPr.AppendChild($XmlDocument.CreateElement('w', 'numPr', $xmlns))
                $ilvl = $numPr.AppendChild($XmlDocument.CreateElement('w', 'ilvl', $xmlns))
                [ref] $null = $ilvl.SetAttribute('val', $xmlns, $item.Level -1)
                $numId = $numPr.AppendChild($XmlDocument.CreateElement('w', 'numId', $xmlns))
                [ref] $null = $numId.SetAttribute('val', $xmlns, $NumberId)

                $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                $rPr = Get-WordParagraphRunPr -ParagraphRun $item -XmlDocument $XmlDocument
                [ref] $null = $r.AppendChild($rPr)

                $t = $r.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
                [ref] $null = $t.AppendChild($XmlDocument.CreateTextNode($item.Text))
            }
            elseif ($item.Type -eq 'PScribo.List')
            {
                Out-WordList -List $item -Element $Element -XmlDocument $XmlDocument -NumberId $NumberId -NotRoot
            }
        }

        ## Append a blank line after each list
        if (-not $NotRoot)
        {
            $p = $Element.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
        }
    }
}

function Out-WordPageBreak
{
<#
    .SYNOPSIS
        Output formatted Word page break.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter','PageBreak')]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $PageBreak,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $p = $XmlDocument.CreateElement('w', 'p', $xmlns)
        $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $br = $r.AppendChild($XmlDocument.CreateElement('w', 'br', $xmlns))
        [ref] $null = $br.SetAttribute('type', $xmlns, 'page')

        return $p
    }
}

function Out-WordParagraph
{
<#
    .SYNOPSIS
        Output formatted Word paragraph and run(s).
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Paragraph,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $p = $XmlDocument.CreateElement('w', 'p', $xmlns);
        $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns));

        if ($Paragraph.Tabs -gt 0)
        {
            $ind = $pPr.AppendChild($XmlDocument.CreateElement('w', 'ind', $xmlns))
            [ref] $null = $ind.SetAttribute('left', $xmlns, (720 * $Paragraph.Tabs))
        }
        if (-not [System.String]::IsNullOrEmpty($Paragraph.Style))
        {
            $pStyle = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlns))
            [ref] $null = $pStyle.SetAttribute('val', $xmlns, $Paragraph.Style)
        }

        $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlns))
        [ref] $null = $spacing.SetAttribute('before', $xmlns, 0)
        [ref] $null = $spacing.SetAttribute('after', $xmlns, 0)

        if ($Paragraph.IsSectionBreakEnd)
        {
            $paragraphPrParams = @{
                PageHeight       = $Document.Options['PageHeight']
                PageWidth        = $Document.Options['PageWidth']
                PageMarginTop    = $Document.Options['MarginTop'];
                PageMarginBottom = $Document.Options['MarginBottom'];
                PageMarginLeft   = $Document.Options['MarginLeft'];
                PageMarginRight  = $Document.Options['MarginRight'];
                Orientation      = $Paragraph.Orientation;
            }
            [ref] $null = $pPr.AppendChild((Get-WordSectionPr @paragraphPrParams -XmlDocument $xmlDocument))
        }

        foreach ($paragraphRun in $Paragraph.Sections)
        {
            $rPr = Get-WordParagraphRunPr -ParagraphRun $paragraphRun -XmlDocument $XmlDocument
            $noSpace = ($paragraphRun.IsParagraphRunEnd -eq $true) -or ($paragraphRun.NoSpace -eq $true)
            $runs = Get-WordParagraphRun -Text $paragraphRun.Text -NoSpace:$noSpace

            foreach ($run in $runs)
            {
                if (-not [System.String]::IsNullOrEmpty($run))
                {
                    if ($run -imatch '<!#(TOTALPAGES|PAGENUMBER)#!>')
                    {
                        $r1 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        $fldChar1 = $r1.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
                        [ref] $null = $fldChar1.SetAttribute('fldCharType', $xmlns, 'begin')

                        $r2 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        [ref] $null = $r2.AppendChild($rPr)
                        $instrText = $r2.AppendChild($XmlDocument.CreateElement('w', 'instrText', $xmlns))
                        [ref] $null = $instrText.SetAttribute('space', 'http://www.w3.org/XML/1998/namespace', 'preserve')

                        if ($run -match '<!#PAGENUMBER#!>')
                        {
                            [ref] $null = $instrText.AppendChild($XmlDocument.CreateTextNode(' PAGE \* MERGEFORMAT '))
                        }
                        elseif ($run -match '<!#TOTALPAGES#!>')
                        {
                            [ref] $null = $instrText.AppendChild($XmlDocument.CreateTextNode(' NUMPAGES \* MERGEFORMAT '))
                        }

                        $r3 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        $fldChar2 = $r3.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
                        [ref] $null = $fldChar2.SetAttribute('fldCharType', $xmlns, 'separate')

                        $r4 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        [ref] $null = $r4.AppendChild($rPr)
                        $t2 = $r4.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
                        [ref] $null = $t2.AppendChild($XmlDocument.CreateTextNode('1'))

                        $r5 = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        $fldChar3 = $r5.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
                        [ref] $null = $fldChar3.SetAttribute('fldCharType', $xmlns, 'end')
                    }
                    else
                    {
                        $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
                        [ref] $null = $r.AppendChild($rPr)

                        ## Create a separate text block for each line/break
                        $lines = $run -split '\r\n?|\n'
                        for ($l = 0; $l -lt $lines.Count; $l++)
                        {
                            $line = $lines[$l]
                            $t = $r.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
                            if ($line -ne $line.Trim())
                            {
                                ## Only preserve space if there is a preceeding or trailing space
                                [ref] $null = $t.SetAttribute('space', 'http://www.w3.org/XML/1998/namespace', 'preserve')
                            }
                            [ref] $null = $t.AppendChild($XmlDocument.CreateTextNode($line))

                            if ($l -lt ($lines.Count - 1))
                            {
                                ## Don't add a line break to the last line/break
                                [ref] $null = $r.AppendChild($XmlDocument.CreateElement('w', 'br', $xmlns))
                            }
                        }
                    }
                }
            }
        }

        return $p
    }
}

function Out-WordSection
{
<#
    .SYNOPSIS
        Output formatted Word section (paragraph).
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $Section,

        [Parameter(Mandatory)]
        [System.Xml.XmlElement] $Element,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'

        $p = $Element.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns));
        $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns));

        if (-not [System.String]::IsNullOrEmpty($Section.Style))
        {
            $pStyle = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlns))
            [ref] $null = $pStyle.SetAttribute('val', $xmlns, $Section.Style)
        }

        if ($Section.Tabs -gt 0)
        {
            $ind = $pPr.AppendChild($XmlDocument.CreateElement('w', 'ind', $xmlns));
            [ref] $null = $ind.SetAttribute('left', $xmlns, (720 * $Section.Tabs));
        }

        $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlns));
        ## Increment heading spacing by 2pt for each section level, starting at 8pt for level 0, 10pt for level 1 etc
        $spacingPt = (($Section.Level * 2) + 8) * 20
        [ref] $null = $spacing.SetAttribute('before', $xmlns, $spacingPt)
        [ref] $null = $spacing.SetAttribute('after', $xmlns, $spacingPt)

        if ($Section.IsSectionBreakEnd)
        {
            $sectionPrParams = @{
                PageHeight       = $Document.Options['PageHeight']
                PageWidth        = $Document.Options['PageWidth']
                PageMarginTop    = $Document.Options['MarginTop']
                PageMarginBottom = $Document.Options['MarginBottom']
                PageMarginLeft   = $Document.Options['MarginLeft']
                PageMarginRight  = $Document.Options['MarginRight']
                Orientation      = $Section.Orientation;
            }
            [ref] $null = $pPr.AppendChild((Get-WordSectionPr @sectionPrParams -XmlDocument $xmlDocument))
        }

        $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $t = $r.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))

        if ($Document.Options['EnableSectionNumbering'])
        {
            [System.String] $sectionName = '{0} {1}' -f $Section.Number, $Section.Name
        }
        else
        {
            [System.String] $sectionName = '{0}' -f $Section.Name
        }
        [ref] $null = $t.AppendChild($XmlDocument.CreateTextNode($sectionName))

        foreach ($subSection in $Section.Sections.GetEnumerator())
        {
            $currentIndentationLevel = 1
            if ($null -ne $subSection.PSObject.Properties['Level'])
            {
                $currentIndentationLevel = $subSection.Level + 1
            }
            Write-PScriboProcessSectionId -SectionId $subSection.Id -SectionType $subSection.Type -Indent $currentIndentationLevel

            switch ($subSection.Type)
            {
                'PScribo.Section'
                {
                    Out-WordSection -Section $subSection -Element $Element -XmlDocument $XmlDocument
                }
                'PScribo.Paragraph'
                {
                    [ref] $null = $Element.AppendChild((Out-WordParagraph -Paragraph $subSection -XmlDocument $XmlDocument))
                }
                'PScribo.PageBreak'
                {
                    [ref] $null = $Element.AppendChild((Out-WordPageBreak -PageBreak $subSection -XmlDocument $XmlDocument))
                }
                'PScribo.LineBreak'
                {
                    [ref] $null = $Element.AppendChild((Out-WordLineBreak -LineBreak $subSection -XmlDocument $XmlDocument))
                }
                'PScribo.Table'
                {
                    Out-WordTable -Table $subSection -XmlDocument $XmlDocument -Element $Element
                }
                'PScribo.BlankLine'
                {
                    Out-WordBlankLine -BlankLine $subSection -XmlDocument $XmlDocument -Element $Element
                }
                'PScribo.Image'
                {
                    [ref] $null = $Element.AppendChild((Out-WordImage -Image $subSection -XmlDocument $XmlDocument))
                }
                'PScribo.ListReference'
                {
                    Out-WordList -List $Document.Lists[$subSection.Number -1] -Element $Element -XmlDocument $xmlDocument -NumberId $subSection.Number
                }
                Default
                {
                    Write-PScriboMessage -Message ($localized.PluginUnsupportedSection -f $subSection.Type) -IsWarning
                }
            }
        }
    }
}

function Out-WordTable
{
<#
    .SYNOPSIS
        Output one (or more listed) formatted Word tables.

    .NOTES
        Specifies that the current row should be repeated at the top each new page on which the table is displayed. E.g, <w:tblHeader />.
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNull()]
        [System.Management.Automation.PSObject] $Table,

        ## Root element to append the table(s) to. List view will create multiple tables
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [System.Xml.XmlElement] $Element,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    begin
    {
        $formattedTables = @(ConvertTo-PScriboPreformattedTable -Table $Table)
    }
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $tableStyle = Get-PScriboDocumentStyle -TableStyle $Table.Style

        for ($tableNumber = 0; $tableNumber -lt $formattedTables.Count; $tableNumber++)
        {
            $formattedTable = $formattedTables[$tableNumber]
            if ($Table.HasCaption -and ($tableStyle.CaptionLocation -eq 'Above'))
            {
                $tableCaption = (Get-WordTableCaption -Table $Table -XmlDocument $XmlDocument)
                [ref] $null = $Element.AppendChild($tableCaption)
            }

            $tbl = $Element.AppendChild($XmlDocument.CreateElement('w', 'tbl', $xmlns))
            [ref] $null = $tbl.AppendChild((Get-WordTablePr -Table $Table -XmlDocument $XmlDocument))

            ## LibreOffice requires column widths to be specified so we must calculate rough approximations (#99).
            $getWordTableRenderWidthMmParams = @{
                TableWidth  = $Table.Width
                Tabs        = $Table.Tabs
                Orientation = $Table.Orientation
            }
            $tableRenderWidthMm = Get-WordTableRenderWidthMm @getWordTableRenderWidthMmParams
            $tableRenderWidthTwips = ConvertTo-Twips -Millimeter $tableRenderWidthMm
            $tblGrid = $tbl.AppendChild($XmlDocument.CreateElement('w', 'tblGrid', $xmlns))

            $tableColumnCount = $Table.Columns.Count
            if ($Table.IsList -and (-not $Table.IsKeyedList))
            {
                $tableColumnCount = 2
            }
            for ($i = 0; $i -lt $tableColumnCount; $i++)
            {
                $gridCol = $tblGrid.AppendChild($XmlDocument.CreateElement('w', 'gridCol', $xmlns))
                $gridColPct = (100 / $Table.Columns.Count) -as [System.Int32]
                if (($null -ne $Table.ColumnWidths) -and ($null -ne $Table.ColumnWidths[$i]))
                {
                    $gridColPct = $Table.ColumnWidths[$i]
                }
                $gridColWidthTwips = (($tableRenderWidthTwips/100) * $gridColPct) -as [System.Int32]
                [ref] $null = $gridCol.SetAttribute('w', $xmlns, $gridColWidthTwips)
            }

            for ($r = 0; $r -lt $formattedTable.Rows.Count; $r++)
            {
                $row = $formattedTable.Rows[$r]
                $isRowStyleInherited = $row.IsStyleInherited
                $rowStyle = $null
                if (-not $isRowStyleInherited) {
                    $rowStyle = Get-PScriboDocumentStyle -Style $row.Style
                }

                $tr = $tbl.AppendChild($XmlDocument.CreateElement('w', 'tr', $xmlns))

                if (($r -eq 0) -and ($formattedTable.HasHeaderRow))
                {
                    $trPr = $tr.AppendChild($XmlDocument.CreateElement('w', 'trPr', $xmlns))
                    [ref] $null = $trPr.AppendChild($XmlDocument.CreateElement('w', 'tblHeader', $xmlns))
                    $cnfStyle = $trPr.AppendChild($XmlDocument.CreateElement('w', 'cnfStyle', $xmlns))
                    # [ref] $null = $cnfStyle.SetAttribute('val', $xmlns, '100000000000')
                    [ref] $null = $cnfStyle.SetAttribute('firstRow', $xmlns, '1')
                }

                for ($c = 0; $c -lt $row.Cells.Count; $c++)
                {
                    $cell = $row.Cells[$c]
                    $isCellStyleInherited = $cell.IsStyleInherited
                    $cellStyle = $null
                    if (-not $isCellStyleInherited)
                    {
                        $cellStyle = Get-PScriboDocumentStyle -Style $cell.Style
                    }

                    $tc = $tr.AppendChild($XmlDocument.CreateElement('w', 'tc', $xmlns))
                    $tcPr = $tc.AppendChild($XmlDocument.CreateElement('w', 'tcPr', $xmlns))

                    if ((-not $isCellStyleInherited) -and (-not [System.String]::IsNullOrEmpty($cellStyle.BackgroundColor)))
                    {
                        $shd = $tcPr.AppendChild($XmlDocument.CreateElement('w', 'shd', $xmlns))
                        [ref] $null = $shd.SetAttribute('val', $xmlns, 'clear')
                        [ref] $null = $shd.SetAttribute('color', $xmlns, 'auto')
                        $backgroundColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $cellStyle.BackgroundColor)
                        [ref] $null = $shd.SetAttribute('fill', $xmlns, $backgroundColor)
                    }
                    elseif ((-not $isRowStyleInherited) -and (-not [System.String]::IsNullOrEmpty($rowStyle.BackgroundColor)))
                    {
                        $shd = $tcPr.AppendChild($XmlDocument.CreateElement('w', 'shd', $xmlns))
                        [ref] $null = $shd.SetAttribute('val', $xmlns, 'clear')
                        [ref] $null = $shd.SetAttribute('color', $xmlns, 'auto')
                        $backgroundColor = ConvertTo-WordColor -Color (Resolve-PScriboStyleColor -Color $rowStyle.BackgroundColor)
                        [ref] $null = $shd.SetAttribute('fill', $xmlns, $backgroundColor)
                    }

                    if (($Table.IsList) -and ($c -eq 0) -and ($r -ne 0))
                    {
                        $cnfStyle = $tcPr.AppendChild($XmlDocument.CreateElement('w', 'cnfStyle', $xmlns))
                        [ref] $null = $cnfStyle.SetAttribute('firstColumn', $xmlns, '1')
                    }

                    $tcW = $tcPr.AppendChild($XmlDocument.CreateElement('w', 'tcW', $xmlns))
                    if (($null -ne $Table.ColumnWidths) -and ($null -ne $Table.ColumnWidths[$c]))
                    {
                        [ref] $null = $tcW.SetAttribute('w', $xmlns, ($Table.ColumnWidths[$c] * 50))
                        [ref] $null = $tcW.SetAttribute('type', $xmlns, 'pct')
                    }
                    else
                    {
                        [ref] $null = $tcW.SetAttribute('w', $xmlns, 0)
                        [ref] $null = $tcW.SetAttribute('type', $xmlns, 'auto')
                    }

                    ## Scaffold paragraph and paragraph run for cell content
                    $newPScriboParagraphParams = @{
                        NoIncrementCounter = $true
                    }
                    if (-not $isCellStyleInherited)
                    {
                        $newPScriboParagraphParams['Style'] = $cellStyle.Id
                    }
                    elseif (-not $isRowStyleInherited)
                    {
                        $newPScriboParagraphParams['Style'] = $rowStyle.Id
                    }
                    $paragraph = New-PScriboParagraph @newPScriboParagraphParams

                    if (-not [System.String]::IsNullOrEmpty($cell.Content))
                    {
                        $paragraphRun = New-PScriboParagraphRun -Text $cell.Content
                    }
                    else
                    {
                        $paragraphRun = New-PScriboParagraphRun -Text ''
                    }
                    $paragraphRun.IsParagraphRunEnd = $true
                    [ref] $null = $paragraph.Sections.Add($paragraphRun)
                    $p = Out-WordParagraph -Paragraph $paragraph -XmlDocument $XmlDocument
                    [ref] $null = $tc.AppendChild($p)
                }
            }

            if ($Table.HasCaption -and ($tableStyle.CaptionLocation -eq 'Below'))
            {
                $tableCaption = Get-WordTableCaption -Table $Table -XmlDocument $XmlDocument
                [ref] $null = $Element.AppendChild($tableCaption)
            }

            ## Output empty line after (each) table
            $p = $Element.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
            ## Only apply section break to the last table
            if (($tableNumber -eq ($formattedTables.Count -1)) -and ($Table.IsSectionBreakEnd))
            #if ($Table.IsSectionBreakEnd)
            {
                $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns));
                $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlns))
                [ref] $null = $spacing.SetAttribute('before', $xmlns, 0)
                [ref] $null = $spacing.SetAttribute('after', $xmlns, 0)

                $paragraphPrParams = @{
                    PageHeight       = $Document.Options['PageHeight']
                    PageWidth        = $Document.Options['PageWidth']
                    PageMarginTop    = $Document.Options['MarginTop']
                    PageMarginBottom = $Document.Options['MarginBottom']
                    PageMarginLeft   = $Document.Options['MarginLeft']
                    PageMarginRight  = $Document.Options['MarginRight']
                    Orientation      = $Table.Orientation
                }
                $sectPr = Get-WordSectionPr @paragraphPrParams -XmlDocument $xmlDocument
                [ref] $null = $pPr.AppendChild($sectPr)
            }
        }
    }
}

function Out-WordTOC
{
<#
    .SYNOPSIS
        Output formatted Word table of contents.
#>

    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSObject] $TOC,

        [Parameter(Mandatory)]
        [System.Xml.XmlDocument] $XmlDocument
    )
    process
    {
        $xmlns = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
        $sdt = $XmlDocument.CreateElement('w', 'sdt', $xmlns)
        $sdtPr = $sdt.AppendChild($XmlDocument.CreateElement('w', 'sdtPr', $xmlns))
        $docPartObj = $sdtPr.AppendChild($XmlDocument.CreateElement('w', 'docPartObj', $xmlns))
        $docObjectGallery = $docPartObj.AppendChild($XmlDocument.CreateElement('w', 'docPartGallery', $xmlns))
        [ref] $null = $docObjectGallery.SetAttribute('val', $xmlns, 'Table of Contents')
        [ref] $null = $docPartObj.AppendChild($XmlDocument.CreateElement('w', 'docPartUnique', $xmlns))
        [ref] $null = $sdt.AppendChild($XmlDocument.CreateElement('w', 'stdEndPr', $xmlns))

        $sdtContent = $sdt.AppendChild($XmlDocument.CreateElement('w', 'stdContent', $xmlns))
        $p1 = $sdtContent.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
        $pPr1 = $p1.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        $pStyle1 = $pPr1.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlns))
        [ref] $null = $pStyle1.SetAttribute('val', $xmlns, 'TOC')
        $r1 = $p1.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $t1 = $r1.AppendChild($XmlDocument.CreateElement('w', 't', $xmlns))
        [ref] $null = $t1.AppendChild($XmlDocument.CreateTextNode($TOC.Name))

        $p2 = $sdtContent.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
        $pPr2 = $p2.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlns))
        $tabs2 = $pPr2.AppendChild($XmlDocument.CreateElement('w', 'tabs', $xmlns))
        $tab2 = $tabs2.AppendChild($XmlDocument.CreateElement('w', 'tab', $xmlns))
        [ref] $null = $tab2.SetAttribute('val', $xmlns, 'right')
        [ref] $null = $tab2.SetAttribute('leader', $xmlns, 'dot')
        [ref] $null = $tab2.SetAttribute('pos', $xmlns, '9016')

        $r2 = $p2.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $fldChar1 = $r2.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
        [ref] $null = $fldChar1.SetAttribute('fldCharType', $xmlns, 'begin')

        $r3 = $p2.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $instrText = $r3.AppendChild($XmlDocument.CreateElement('w', 'instrText', $xmlns))
        [ref] $null = $instrText.SetAttribute('space', 'http://www.w3.org/XML/1998/namespace', 'preserve')
        [ref] $null = $instrText.AppendChild($XmlDocument.CreateTextNode(' TOC \h \z \u '))

        $r4 = $p2.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $fldChar2 = $r4.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
        [ref] $null = $fldChar2.SetAttribute('fldCharType', $xmlns, 'separate')

        $p3 = $sdtContent.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlns))
        $r5 = $p3.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlns))
        $fldChar3 = $r5.AppendChild($XmlDocument.CreateElement('w', 'fldChar', $xmlns))
        [ref] $null = $fldChar3.SetAttribute('fldCharType', $xmlns, 'end')

        return $sdt
    }
}


# SIG # Begin signature block
# MIIuugYJKoZIhvcNAQcCoIIuqzCCLqcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCrjJx3nTlsYwQ/
# BQqqedLto4ONehocVm2MA0lrsJWsKKCCE6QwggWQMIIDeKADAgECAhAFmxtXno4h
# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
# eE4wggdYMIIFQKADAgECAhAIfHT3o/FeY5ksO94AUhTmMA0GCSqGSIb3DQEBCwUA
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwHhcNMjMxMDE4MDAwMDAwWhcNMjYxMjE2MjM1OTU5WjBgMQsw
# CQYDVQQGEwJHQjEPMA0GA1UEBxMGTG9uZG9uMR8wHQYDVQQKExZWaXJ0dWFsIEVu
# Z2luZSBMaW1pdGVkMR8wHQYDVQQDExZWaXJ0dWFsIEVuZ2luZSBMaW1pdGVkMIIC
# IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtyhrsCMi6pgLcX5sWY7I09dO
# WKweRHfDwW5AN6ffgLCYO9dqWWxvqu95FqnNVRyt1VNzEl3TevKVhRE0GGdirei3
# VqnFFjLDwD2jHhGY8qoSYyfffj/WYq2DkvNI62C3gUwSeP3FeqKRalc2c3V2v4jh
# yEYhrgG3nfnWQ/Oq2xzuiCqHy1E4U+IKKDtrXls4JX2Z4J/uAHZIAyKfrcTRQOhZ
# R4ZS1cQkeSBU9Urx578rOmxL0si0GAoaYQC49W7OimRelbahxZw/R+f5ch+C1ycU
# CpeXLg+bFhpa0+EXnkGidlILZbJiZJn7qvMQTZgipQKZ8nhX3rtJLqTeodPWzcCk
# tXQUy0q5fxhR3e6Ls7XQesq/G2yMcCMTCd6eltze0OgabvL6Xkhir5lATHaJtnmw
# FlcKzRr1YXK1k1D84hWfKSAdUg8T1O72ztimbqFLg6WoC8M2qqsHcm2DOc9hM3i2
# CWRpegikitRvZ9i1wkA9arGh7+a7UD+nLh2hnGmO06wONLNqABOEn4JOVnNrQ1gY
# eDeH9FDx7IYuAvMsfXG9Bo+I97TR2VfwDAx+ccR+UQLON3aQyFZ3BefYnvUu0gUR
# ikEAnAS4Jnc3BHizgb0voz0iWRDjFoTTmCmrInCVDGc+5KMy0xyoUwdQvYvRGAWB
# 61OCWnXBXbAEPniTZ80CAwEAAaOCAgMwggH/MB8GA1UdIwQYMBaAFGg34Ou2O/hf
# EYb7/mF7CIhl9E5CMB0GA1UdDgQWBBRuAv58K4EDYLmb7WNcxt5+r4NfnzA+BgNV
# HSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2lj
# ZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMD
# MIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEu
# Y3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDCBlAYIKwYB
# BQUHAQEEgYcwgYQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv
# bTBcBggrBgEFBQcwAoZQaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD
# ZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcnQw
# CQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAgEAnXMg6efkBrwLIvd1Xmuh0dam
# 9FhUtDEj+P5SIqdP/U4veOv66NEQhBHLbW2Dvrdm6ec0HMj9b4e8pt4ylKFzHIPj
# fpuRffHVR9JQSx8qpryN6pP49DfCkAYeZGqjY3pGRzd/xQ0cfwcuYbUF+vwVk7tj
# q8c93VHCM0rb5M4N2hD1Ze1pvZxtaf9QnFKFzgXZjr02K6bswQc2+n5jFCp7zV1f
# KTstyb68rhSJBWKK1tMeFk6a6HXr5buTD3skluC0oyPmD7yAd97r2owjDMEveEso
# kADP/z7XQk7wqbwbpi4W6Uju2qHK/9UUsVRF5KTVEAIzVw2V1Aq/Jh3JuSV7b7C1
# 4CghNekltBb+w7YVp8/IFcj7axqnpNQ/+f7RVc3A5hyjV+MkoSwn8Sg7a7hn6SzX
# jec/TfRVvWCmG94MQHko+6206uIXrZnmQ6UQYFyOHRlyKDEozzkZhIcVlsZloUjL
# 3FZ5V/l8TIIzbc3bkEnu4iByksNvRxI6c5264OLauYlWv50ZUPwXmZ9gX8bs3BqZ
# avbGUrOW2PIjtWhtvs4zHhMBCoU1Z0OMvXcF9rUDqefmVCZK46xz3DGKVkDQnxY6
# UWQ3GL60/lEzju4YS99LJVQks2UGmP6LAzlEZ1dnGqi1aQ51OidCYEs39B75PsvO
# By2iAR8pBVi/byWBypExghpsMIIaaAIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYD
# VQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBH
# NCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTECEAh8dPej8V5j
# mSw73gBSFOYwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAA
# oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgfJZdjqiM3sSBkB4rC8EsQ104
# Is2IRt2dBu+BcdXYwPkwDQYJKoZIhvcNAQEBBQAEggIAmls7DXwRtBZYvT2lEo37
# iVuMhbUo31l7VrSVXrupKUqfQPLgGlDq9XmOmZdl11+gn/F40r7ZiNPZ6g0g+oXk
# 0gLApU/JwaTEtHfVk1MFDPyG1Wl8+aZD+RHpD1eP8nJrY/lX9OWJZO2E5vVar1nj
# ThKqAT3qrNonUj5/mvEduIn1aO3zwfkS7r/AygqT3amSJNH82L6Qh7dcO38vITe6
# +k+kTijYEX1ow4MCyjI4icDbTZBwU+H1cRXUUv2YWjM0TQsV6deCou+xndBAxMVJ
# 0iAxC7+GXXujzmKRpxCH1VBRpvCaSNEgF6ms5BjaCHrXs8ND4p8joVIIN4EpGfsQ
# cBGtQ41nYcghxQNRHRH+ynb7g521tqgNEvT75ihpE9/ra+tM0ccQaQ6NzBEoeR7N
# +RjTFvZP5OHyFpGauLmuh5QRp27R/hEaIt2XEgyW02lDyRS6guM9o5DjfKgBP3nR
# bFYnoXugQVujCVcT2xbVoOuPMwnHZIPHmTMtU1ZK57i6QcrxX90+xzQFDxiBSDPp
# JFSxN/U71DoQ9xdyBe6HoX5NPctfU6MP0cwk5ALkdxEhRcacabX6JWtVA0Hw36y4
# tgGE38Wg++o8k6UnPjAdgiddViAHw9NnMdKO7LhRzA7N2c9d5u3JLh1j8dP5DRUc
# 8kJcXEjb3o4el+qDIu3dn8+hghc5MIIXNQYKKwYBBAGCNwMDATGCFyUwghchBgkq
# hkiG9w0BBwKgghcSMIIXDgIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqGSIb3DQEJ
# EAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQgJFMLk4BJ
# /ywYt+/j7+qyze0RrDo0wQRwKsVJxby3YJACEELqsMtKmag/NbKRcyEHT64YDzIw
# MjUwMzA3MDg1NTA4WqCCEwMwgga8MIIEpKADAgECAhALrma8Wrp/lYfG+ekE4zME
# MA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy
# dCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNI
# QTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjQwOTI2MDAwMDAwWhcNMzUxMTI1MjM1
# OTU5WjBCMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxIDAeBgNVBAMT
# F0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEAvmpzn/aVIauWMLpbbeZZo7Xo/ZEfGMSIO2qZ46XB/QowIEMSvgjE
# dEZ3v4vrrTHleW1JWGErrjOL0J4L0HqVR1czSzvUQ5xF7z4IQmn7dHY7yijvoQ7u
# jm0u6yXF2v1CrzZopykD07/9fpAT4BxpT9vJoJqAsP8YuhRvflJ9YeHjes4fduks
# THulntq9WelRWY++TFPxzZrbILRYynyEy7rS1lHQKFpXvo2GePfsMRhNf1F41nyE
# g5h7iOXv+vjX0K8RhUisfqw3TTLHj1uhS66YX2LZPxS4oaf33rp9HlfqSBePejlY
# eEdU740GKQM7SaVSH3TbBL8R6HwX9QVpGnXPlKdE4fBIn5BBFnV+KwPxRNUNK6lY
# k2y1WSKour4hJN0SMkoaNV8hyyADiX1xuTxKaXN12HgR+8WulU2d6zhzXomJ2Ple
# I9V2yfmfXSPGYanGgxzqI+ShoOGLomMd3mJt92nm7Mheng/TBeSA2z4I78JpwGpT
# RHiT7yHqBiV2ngUIyCtd0pZ8zg3S7bk4QC4RrcnKJ3FbjyPAGogmoiZ33c1HG93V
# p6lJ415ERcC7bFQMRbxqrMVANiav1k425zYyFMyLNyE1QulQSgDpW9rtvVcIH7Wv
# G9sqYup9j8z9J1XqbBZPJ5XLln8mS8wWmdDLnBHXgYly/p1DhoQo5fkCAwEAAaOC
# AYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
# MAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAf
# BgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUn1csA3cO
# KBWQZqVjXu5Pkh92oFswWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFt
# cGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6
# Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVT
# dGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAPa0eH3aZW+M4hBJH2UOR
# 9hHbm04IHdEoT8/T3HuBSyZeq3jSi5GXeWP7xCKhVireKCnCs+8GZl2uVYFvQe+p
# PTScVJeCZSsMo1JCoZN2mMew/L4tpqVNbSpWO9QGFwfMEy60HofN6V51sMLMXNTL
# fhVqs+e8haupWiArSozyAmGH/6oMQAh078qRh6wvJNU6gnh5OruCP1QUAvVSu4kq
# VOcJVozZR5RRb/zPd++PGE3qF1P3xWvYViUJLsxtvge/mzA75oBfFZSbdakHJe2B
# VDGIGVNVjOp8sNt70+kEoMF+T6tptMUNlehSR7vM+C13v9+9ZOUKzfRUAYSyyEmY
# tsnpltD/GWX8eM70ls1V6QG/ZOB6b6Yum1HvIiulqJ1Elesj5TMHq8CWT/xrW7tw
# ipXTJ5/i5pkU5E16RSBAdOp12aw8IQhhA/vEbFkEiF2abhuFixUDobZaA0VhqAsM
# HOmaT3XThZDNi5U2zHKhUs5uHHdG6BoQau75KiNbh0c+hatSF+02kULkftARjsyE
# pHKsF7u5zKRbt5oK5YGwFvgc4pEVUNytmB3BpIiowOIIuDgP5M9WArHYSAR16gc0
# dP2XdkMEP5eBsX7bf/MGN4K3HP50v/01ZHo/Z5lGLvNwQ7XHBx1yomzLP8lx4Q1z
# ZKDyHcp4VQJLu2kWTsKsOqQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5b
# MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5
# NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkG
# A1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3Rh
# bXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPB
# PXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/
# nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLc
# Z47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mf
# XazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3N
# Ng1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yem
# j052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g
# 3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD
# 4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDS
# LFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwM
# O1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU
# 7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/
# BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0j
# BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E
# PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw
# DQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPO
# vxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQ
# TGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWae
# LJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPBy
# oyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfB
# wWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8l
# Y5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/
# O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbb
# bxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3
# OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBl
# dkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt
# 1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0BAQwF
# ADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
# ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElE
# IFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYD
# VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln
# aWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKn
# JS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/W
# BTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHi
# LQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhm
# V1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHE
# tWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
# MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mX
# aXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZ
# xd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfh
# vbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvl
# EFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn1
# 5GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
# HQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SSy4Ix
# LVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAkBggr
# BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdo
# dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290
# Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRVHSAA
# MA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzs
# hV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre
# +i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo8L8v
# C6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++hUD38
# dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5xaiNr
# Iv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDdjCCA3ICAQEw
# dzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNV
# BAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1w
# aW5nIENBAhALrma8Wrp/lYfG+ekE4zMEMA0GCWCGSAFlAwQCAQUAoIHRMBoGCSqG
# SIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUwMzA3MDg1
# NTA4WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTb04XuYtvSPnvk9nFIUIck1YZb
# RTAvBgkqhkiG9w0BCQQxIgQgTaS9XXKJ9oC1LPtbrTQIik9IEjWtIfW8mjQXH0y6
# NGYwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgdnafqPJjLx9DCzojMK7WVnX+13Pb
# BdZluQWTmEOPmtswDQYJKoZIhvcNAQEBBQAEggIAdYzF4SMBuNj+Ha1uAl/xiyqj
# tynNRAMfdM/s57YJYZMlvqM9mqgsj9p7M5klj0N3/F5PigHIfvdE5yU/kjAvgBgt
# gOglIcf3P+L10Wq8MJIaexjmnB+B8mKFztySyO/AfkOsUgVv7Bc9esa90hWSRA5Z
# XEjUViWZTf9VLMGW5kKXeCwlkUYaOtM7Uf0Z1dcMdje6UPugpLysVY7s3O5WrCym
# IrjXkr+570Z54rkt5kH4RCEGlCRIjuwq4sUKQMPMai+37ZZ6jA9gCCE6ZxTCbCPW
# CyctncqhaFktkERIm0+4yrEdRJh4ty3AunHGm8kUdzbnwvK8eokswstaqm8ZR9vK
# lDauIeDOvti7HkVkJ0Pz1RZvq9CWhrGhuMJATX6BzUt8+7TDdy/vhd7TKidkPB+w
# YAlIse2PMsLOmsNkx64PSbVFfJxcU7PEa5uYHc2GMC1IAUKCGEicQYnG6by/eQ3p
# Vt3KNzTeX0U3kBSw+yNZTXbR6Jp6h7cyC4Cf6gM/Y/U2PLJzUf58NzvUYW0kTf6S
# Cc6v5+Ce6tNaHbnnig65CR+B9qC1zTCu4L7ZA808nHIJNI8B95Y6qOVaTQzriQAr
# s4eJ8Kg+60f6vi57jfem1oV/EkFal8iklCQnFFSIkfOFHhGgm1AQiVATwsj9Ehc/
# 1RTcoxohE/MIAFKmGSs=
# SIG # End signature block