PSWriteHTML.psm1

function Add-CustomFormatForDatetimeSorting {
    <#
    .SYNOPSIS
     
    .DESCRIPTION
        This function adds code to make the datatable columns sortable with different datetime formats.
        Formatting:
        Day (of Month)
        D - 1 2 ... 30 31
        Do - 1st 2nd ... 30th 31st
        DD - 01 02 ... 30 31
         
        Month
        M - 1 2 ... 11 12
        Mo - 1st 2nd ... 11th 12th
        MM - 01 02 ... 11 12
        MMM - Jan Feb ... Nov Dec
        MMMM - January February ... November December
 
        Year
        YY - 70 71 ... 29 30
        YYYY - 1970 1971 ... 2029 2030
 
        Hour
        H - 0 1 ... 22 23
        HH - 00 01 ... 22 23
        h - 1 2 ... 11 12
        hh - 01 02 ... 11 12
 
        Minute
        m - 0 1 ... 58 59
        mm - 00 01 ... 58 59
 
        Second
        s - 0 1 ... 58 59
        ss - 00 01 ... 58 59
 
        More formats
        http://momentjs.com/docs/#/displaying/
 
    .PARAMETER CustomDateTimeFormat
        Array with strings of custom datetime format.
        The string is build from two parts. Format and locale. Locale is optional.
        format explanation: http://momentjs.com/docs/#/displaying/
        locale explanation: http://momentjs.com/docs/#/i18n/
 
 
    .LINK
        format explanation: http://momentjs.com/docs/#/displaying/
        locale explanation: http://momentjs.com/docs/#/i18n/
    .Example
        Add-CustomFormatForDatetimeSorting -CustomDateFormat 'dddd, MMMM Do, YYYY','HH:mm MMM D, YY'
    .Example
        Add-CustomFormatForDatetimeSorting -CustomDateFormat 'DD.MM.YYYY HH:mm:ss'
    #>

    [CmdletBinding()]
    param([array]$DateTimeSortingFormat)
    if ($Script:Output) { Remove-Variable Output -Scope Script }
    if ($DateTimeSortingFormat) { [array]$Script:Output = foreach ($format in $DateTimeSortingFormat) { "$.fn.dataTable.moment( '$format' );" } }
    else { $Script:Output = "$.fn.dataTable.moment( 'L' );" }
    return $Script:Output
}
function Add-TableFiltering {
    [CmdletBinding()]
    param([bool] $Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom')
    $Output = @{ }
    if ($Filtering) {
        if ($FilteringLocation -eq 'Bottom') {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each footer cell
                `$('#$DataTableName tfoot th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for footer cells
                table.columns().every(function () {
                    var that = this;
 
                    `$('input', this.footer()).on('keyup change', function () {
                        if (that.search() !== this.value) {
                            that.search(this.value).draw();
                        }
                    });
                });
"@

        } elseif ($FilteringLocation -eq 'Both') {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each header cell
                `$('#$DataTableName thead th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
                // Setup - add a text input to each footer cell
                `$('#$DataTableName tfoot th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for header cells
                table.columns().eq(0).each(function (colIdx) {
                    `$('input', table.column(colIdx).header()).on('keyup change', function () {
                        table
                            .column(colIdx)
                            .search(this.value)
                            .draw();
                    });
 
                    `$('input', table.column(colIdx).header()).on('click', function (e) {
                        e.stopPropagation();
                    });
                });
                // Apply the search for footer cells
                table.columns().every(function () {
                    var that = this;
 
                    `$('input', this.footer()).on('keyup change', function () {
                        if (that.search() !== this.value) {
                            that.search(this.value).draw();
                        }
                    });
                });
"@

        } else {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each header cell
                `$('#$DataTableName thead th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for header cells
                table.columns().eq(0).each(function (colIdx) {
                    `$('input', table.column(colIdx).header()).on('keyup change', function () {
                        table
                            .column(colIdx)
                            .search(this.value)
                            .draw();
                    });
 
                    `$('input', table.column(colIdx).header()).on('click', function (e) {
                        e.stopPropagation();
                    });
                });
"@

        }
    } else { $Output.FilteringTopCode = $Output.FilteringBottomCode = '' }
    return $Output
}
function Add-TableHeader {
    [CmdletBinding()]
    param([System.Collections.Generic.List[PSCustomObject]] $HeaderRows,
        [System.Collections.Generic.List[PSCUstomObject]] $HeaderStyle,
        [System.Collections.Generic.List[PSCUstomObject]] $HeaderTop,
        [string[]] $HeaderNames)
    if ($HeaderRows.Count -eq 0 -and $HeaderStyle.Count -eq 0 -and $HeaderTop.Count -eq 0) { return }
    [Array] $MergeColumns = foreach ($Row in $HeaderRows) {
        $Index = foreach ($R in $Row.Names) { [array]::indexof($HeaderNames.ToUpper(), $R.ToUpper()) }
        if ($Index -contains -1) { Write-Warning -Message "Table Header can't be processed properly. Names on the list to merge were not found in Table Header." } else {
            @{Index   = $Index
                Title = $Row.Title
                Count = $Index.Count
                Style = $Row.Style
                Used  = $false
            }
        }
    }
    $Styles = @{ }
    foreach ($Row in $HeaderStyle) {
        foreach ($_ in $Row.Names) {
            $Index = [array]::indexof($HeaderNames.ToUpper(), $_.ToUpper())
            $Styles[$Index] = @{Index = $Index
                Title                 = $Row.Title
                Count                 = $Index.Count
                Style                 = $Row.Style
                Used                  = $false
            }
        }
    }
    if ($HeaderTop.Count -gt 0) {
        $UsedColumns = 0
        $ColumnsTotal = $HeaderNames.Count
        $TopHeader = New-HTMLTag -Tag 'tr' { foreach ($_ in $HeaderTop) {
                if ($_.ColumnCount -eq 0) {
                    $UsedColumns = $ColumnsTotal - $UsedColumns
                    New-HTMLTag -Tag 'th' -Attributes @{colspan = $UsedColumns; style = ($_.Style) } -Value { $_.Title }
                } else {
                    if ($_.ColumnCount -le $ColumnsTotal) { $UsedColumns = $UsedColumns + $_.ColumnCount } else { $UsedColumns = - ($ColumnsTotal - $_.ColumnCount) }
                    New-HTMLTag -Tag 'th' -Attributes @{colspan = $_.ColumnCount; style = ($_.Style) } -Value { $_.Title }
                }
            } }
    }
    $AddedHeader = @($NewHeader = [System.Collections.Generic.List[string]]::new()
        $TopHeader
        New-HTMLTag -Tag 'tr' { for ($i = 0; $i -lt $HeaderNames.Count; $i++) {
                $Found = $false
                foreach ($_ in $MergeColumns) {
                    if ($_.Index -contains $i) {
                        if ($_.Used -eq $false) { New-HTMLTag -Tag 'th' -Attributes @{colspan = $_.Count; style = ($_.Style) } -Value { $_.Title }
                            $_.Used = $true
                            $Found = $true
                        } else { $Found = $true }
                    }
                }
                if (-not $Found) { if ($MergeColumns.Count -eq 0) { New-HTMLTag -Tag 'th' { $HeaderNames[$i] } -Attributes @{style = $Styles[$i].Style } } else { New-HTMLTag -Tag 'th' { $HeaderNames[$i] } -Attributes @{rowspan = 2; style = $Styles[$i].Style }
                    }
                } else { $Head = New-HTMLTag -Tag 'th' { $HeaderNames[$i] } -Attributes @{style = $Styles[$i].Style }
                    $NewHeader.Add($Head)
                }
            } }
        if ($NewHeader.Count) { New-HTMLTag -Tag 'tr' { $NewHeader } })
    return $AddedHeader
}
function Add-TableState {
    [CmdletBinding()]
    param([bool] $Filtering,
        [bool] $SavedState,
        [string] $DataTableName,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom')
    if ($Filtering -and $SavedState) {
        if ($FilteringLocation -eq 'Top') {
            $Output = @"
                // Setup - Looading text input from SavedState
                `$('#$DataTableName').on('stateLoaded.dt', function(e, settings, data) {
                    settings.aoPreSearchCols.forEach(function(col, index) {
                        if (col.sSearch) setTimeout(function() {
                            `$('#$DataTableName thead th:eq('+index+') input').val(col.sSearch)
                        }, 50)
                    })
                });
"@

        } elseif ($FilteringLocation -eq 'Both') {
            $Output = @"
                // Setup - Looading text input from SavedState
                `$('#$DataTableName').on('stateLoaded.dt', function(e, settings, data) {
                    settings.aoPreSearchCols.forEach(function(col, index) {
                        if (col.sSearch) setTimeout(function() {
                            `$('#$DataTableName thead th:eq('+index+') input').val(col.sSearch)
                        }, 50)
                    })
                });
                // Setup - Looading text input from SavedState
                `$('#$DataTableName').on('stateLoaded.dt', function(e, settings, data) {
                    settings.aoPreSearchCols.forEach(function(col, index) {
                        if (col.sSearch) setTimeout(function() {
                            `$('#$DataTableName tfoot th:eq('+index+') input').val(col.sSearch)
                        }, 50)
                    })
                });
"@

        } else {
            $Output = @"
                // Setup - Looading text input from SavedState
                `$('#$DataTableName').on('stateLoaded.dt', function(e, settings, data) {
                    settings.aoPreSearchCols.forEach(function(col, index) {
                        if (col.sSearch) setTimeout(function() {
                            `$('#$DataTableName tfoot th:eq('+index+') input').val(col.sSearch)
                        }, 50)
                    })
                })
"@

        }
    } else { $Output = '' }
    return $Output
}
function Convert-ImagesToBinary {
    [CmdLetBinding()]
    param([string[]] $Content,
        [string] $Search,
        [string] $ReplacePath)
    if ($Content -like "*$Search*") {
        $Replace = "data:image/$FileType;base64," + [Convert]::ToBase64String((Get-Content -LiteralPath $ReplacePath -Encoding Byte))
        $Content = $Content.Replace($Search, $Replace)
    }
    $Content
}
function Convert-StyleContent {
    [CmdLetBinding()]
    param([string[]] $CSS,
        [string] $ImagesPath,
        [string] $SearchPath)
    $ImageFiles = Get-ChildItem -Path (Join-Path $ImagesPath '\*') -Include *.jpg, *.png, *.bmp
    foreach ($Image in $ImageFiles) { $CSS = Convert-ImagesToBinary -Content $CSS -Search "$SearchPath$($Image.Name)" -ReplacePath $Image.FullName }
    return $CSS
}
function Convert-StyleContent1 {
    param([PSCustomObject] $Options)
    if ($null -ne $Options.StyleContent) {
        Write-Verbose "Logos: $($Options.Logos.Keys -join ',')"
        foreach ($Logo in $Options.Logos.Keys) {
            $Search = "../images/$Logo.png", "DataTables-1.10.18/images/$Logo.png"
            $Replace = $Options.Logos[$Logo]
            foreach ($S in $Search) {
                Write-Verbose "Logos - replacing $S with binary representation"
                $Options.StyleContent = ($Options.StyleContent).Replace($S, $Replace)
            }
        }
    }
}
function ConvertTo-HTMLStyle {
    [CmdletBinding()]
    param([nullable[RGBColors]] $Color,
        [nullable[RGBColors]] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $LineBreak)
    if ($FontSize -eq 0) { $Size = '' } else { $size = "$($FontSize)px" }
    $Style = @{'color'     = ConvertFrom-Color -Color $Color
        'background-color' = ConvertFrom-Color -Color $BackGroundColor
        'font-size'        = $Size
        'font-weight'      = $FontWeight
        'font-variant'     = $FontVariant
        'font-family'      = $FontFamily
        'font-style'       = $FontStyle
        'text-align'       = $Alignment
        'text-decoration'  = $TextDecoration
        'text-transform'   = $TextTransform
    }
    Remove-EmptyValues -Hashtable $Style
    return $Style
}
function Get-FeaturesInUse {
    <#
    .SYNOPSIS
    Short description
 
    .DESCRIPTION
    Long description
 
    .PARAMETER PriorityFeatures
    Define priority features - important for ordering when CSS or JS has to be processed in certain order
 
    .EXAMPLE
    Get-FeaturesInUse -PriorityFeatures 'Jquery', 'DataTables', 'Tabs', 'Test'
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string[]] $PriorityFeatures)
    [Array] $Features = foreach ($Key in $Script:HTMLSchema.Features.Keys) { if ($Script:HTMLSchema.Features[$Key]) { $Key } }
    [Array] $TopFeatures = foreach ($Feature in $PriorityFeatures) { if ($Features -contains $Feature) { $Feature } }
    [Array] $RemainingFeatures = foreach ($Feature in $Features) { if ($TopFeatures -notcontains $Feature) { $Feature } }
    [Array] $AllFeatures = $TopFeatures + $RemainingFeatures
    $AllFeatures
}
Function Get-HTMLLogos {
    <#
         .SYNOPSIS
            Get Base64 HTML
 
    #>

    [CmdletBinding()]
    param
    ([Parameter(Mandatory = $false)]
        [string]$LeftLogoName = "Sample",
        [string]$RightLogoName = "Alternate",
        [string]$LeftLogoString,
        [string]$RightLogoString)
    $LogoSources = @{ }
    $LogoPath = @()
    if ([String]::IsNullOrEmpty($RightLogoString) -eq $false -or [String]::IsNullOrEmpty($LeftLogoString) -eq $false) {
        if ([String]::IsNullOrEmpty($RightLogoString) -eq $false) { $LogoSources.Add($RightLogoName, $RightLogoString) }
        if ([String]::IsNullOrEmpty($LeftLogoString) -eq $false) { $LogoSources.Add($LeftLogoName, $LeftLogoString) }
    } else { $LogoPath += "$PSScriptRoot\Resources\Images\Other" }
    $LogoPath += "$PSScriptRoot\Resources\Images\DataTables"
    $ImageFiles = Get-ChildItem -Path (Join-Path $LogoPath '\*') -Include *.jpg, *.png, *.bmp -Recurse
    foreach ($ImageFile in $ImageFiles) {
        if ($ImageFile.Extension -eq '.jpg') { $FileType = 'jpeg' } else { $FileType = $ImageFile.Extension.Replace('.', '') }
        Write-Verbose "Converting $($ImageFile.FullName) to base64 ($FileType)"
        $LogoSources.Add($ImageFile.BaseName, "data:image/$FileType;base64," + [Convert]::ToBase64String((Get-Content $ImageFile.FullName -Encoding Byte)))
    }
    Write-Output $LogoSources
}
function Get-HTMLPartContent {
    param([Array] $Content,
        [string] $Start,
        [string] $End,
        [ValidateSet('Before', 'Between', 'After')] $Type = 'Between')
    $NrStart = $Content.IndexOf($Start)
    $NrEnd = $Content.IndexOf($End)
    if ($Type -eq 'Between') {
        if ($NrStart -eq -1) { return }
        $Content[$NrStart..$NrEnd]
    }
    if ($Type -eq 'After') {
        if ($NrStart -eq -1) { return $Content }
        $Content[($NrEnd + 1)..($Content.Count - 1)]
    }
    if ($Type -eq 'Before') {
        if ($NrStart -eq -1) { return }
        $Content[0..$NrStart]
    }
}
function Get-Resources {
    [CmdLetBinding()]
    param([switch] $UseCssLinks,
        [switch] $UseJavaScriptLinks,
        [switch] $NoScript,
        [ValidateSet('Header', 'Footer', 'HeaderAlways', 'FooterAlways')][string] $Location)
    DynamicParam {
        $Names = $Script:Configuration.Features.Keys
        $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute
        $ParamAttrib.Mandatory = $true
        $ParamAttrib.ParameterSetName = '__AllParameterSets'
        $ReportAttrib = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $ReportAttrib.Add($ParamAttrib)
        $ReportAttrib.Add((New-Object System.Management.Automation.ValidateSetAttribute($Names)))
        $ReportRuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter('Features', [string[]], $ReportAttrib)
        $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        $RuntimeParamDic.Add('Features', $ReportRuntimeParam)
        return $RuntimeParamDic
    }
    Process {
        [string[]] $Features = $PSBoundParameters.Features
        foreach ($Feature in $Features) {
            Write-Verbose "Get-Resources - Location: $Location - Feature: $Feature UseCssLinks: $UseCssLinks UseJavaScriptLinks: $UseJavaScriptLinks"
            if ($UseCssLinks) { New-HTMLResourceCSS -Link $Script:Configuration.Features.$Feature.$Location.'CssLink' -ResourceComment $Script:Configuration.Features.$Feature.Comment } else {
                $CSSOutput = New-HTMLResourceCSS -FilePath $Script:Configuration.Features.$Feature.$Location.'Css' -ResourceComment $Script:Configuration.Features.$Feature.Comment -Replace $Script:Configuration.Features.$Feature.CustomActionsReplace
                Convert-StyleContent -CSS $CSSOutput -ImagesPath "$PSScriptRoot\Resources\Images\DataTables" -SearchPath "DataTables-1.10.18/images/"
            }
            if ($UseJavaScriptLinks) { New-HTMLResourceJS -Link $Script:Configuration.Features.$Feature.$Location.'JsLink' -ResourceComment $Script:Configuration.Features.$Feature.Comment } else { New-HTMLResourceJS -FilePath $Script:Configuration.Features.$Feature.$Location.'Js' -ResourceComment $Script:Configuration.Features.$Feature.Comment -ReplaceData $Script:Configuration.Features.$Feature.CustomActionsReplace }
            if ($NoScript) {
                [Array] $Output = @(if ($UseCssLinks) { New-HTMLResourceCSS -Link $Script:Configuration.Features.$Feature.$Location.'CssLinkNoScript' -ResourceComment $Script:Configuration.Features.$Feature.Comment } else {
                        $CSSOutput = New-HTMLResourceCSS -FilePath $Script:Configuration.Features.$Feature.$Location.'CssNoScript' -ResourceComment $Script:Configuration.Features.$Feature.Comment -ReplaceData $Script:Configuration.Features.$Feature.CustomActionsReplace
                        Convert-StyleContent -CSS $CSSOutput -ImagesPath "$PSScriptRoot\Resources\Images\DataTables" -SearchPath "DataTables-1.10.18/images/"
                    })
                if (($Output.Count -gt 0) -and ($null -ne $Output[0])) { New-HTMLTag -Tag 'noscript' { $Output } }
            }
        }
    }
}
function New-ApexChart {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('default', 'central')][string] $Positioning = 'default')
    $Script:HTMLSchema.Features.ChartsApex = $true
    [string] $ID = "ChartID-" + (Get-RandomStringName -Size 8)
    if ($Positioning -eq 'default') { $Class = '' } else { $Class = $Positioning }
    $Div = New-HTMLTag -Tag 'div' -Attributes @{id = $ID; class = $Class }
    $Script = New-HTMLTag -Tag 'script' -Value { $JSON = $Options | ConvertTo-Json -Depth 5 | ForEach-Object { [System.Text.RegularExpressions.Regex]::Unescape($_) }
        "var options = $JSON"
        ""
        "var chart = new ApexCharts(document.querySelector('#$ID'),
            options
        );"

        "chart.render();" }
    $Div
    $Script:HTMLSchema.Charts.Add($Script)
}
function New-ChartAxisX {
    [alias('ChartCategory', 'ChartAxisX', 'New-ChartCategory')]
    [CmdletBinding()]
    param([alias('Name')][Array] $Names,
        [alias('Title')][string] $TitleText,
        [ValidateSet('datetime', 'category', 'numeric')][string] $Type = 'category',
        [int] $MinValue,
        [int] $MaxValue)
    [PSCustomObject] @{ObjectType = 'ChartAxisX'
        ChartAxisX                = @{Names = $Names
            Type                            = $Type
            TitleText                       = $TitleText
            Min                             = $MinValue
            Max                             = $MaxValue
        }
    }
}
function New-ChartAxisY {
    [alias('ChartAxisY')]
    [CmdletBinding()]
    param([switch] $Show,
        [switch] $ShowAlways,
        [string] $TitleText,
        [ValidateSet('90', '270')][string] $TitleRotate = '90',
        [int] $TitleOffsetX = 0,
        [int] $TitleOffsetY = 0,
        [RGBColors] $TitleStyleColor = [RGBColors]::None,
        [int] $TitleStyleFontSize = 12,
        [string] $TitleStylefontFamily = 'Helvetica, Arial, sans-serif',
        [int] $MinValue,
        [int] $MaxValue)
    [PSCustomObject] @{ObjectType = 'ChartAxisY'
        ChartAxisY                = @{Show = $Show.IsPresent
            ShowAlways                     = $ShowAlways.IsPresent
            TitleText                      = $TitleText
            TitleRotate                    = $TitleRotate
            TitleOffsetX                   = $TitleOffsetX
            TitleOffsetY                   = $TitleOffsetY
            TitleStyleColor                = $TitleStyleColor
            TitleStyleFontSize             = $TitleStyleFontSize
            TitleStylefontFamily           = $TitleStylefontFamily
            Min                            = $MinValue
            Max                            = $MaxValue
        }
    }
}
function New-ChartBar {
    [alias('ChartBar')]
    [CmdletBinding()]
    param([string] $Name,
        [object] $Value)
    [PSCustomObject] @{ObjectType = 'Bar'
        Name                      = $Name
        Value                     = $Value
    }
}
function New-ChartBarOptions {
    [alias('ChartBarOptions')]
    [CmdletBinding()]
    param([ValidateSet('bar', 'barStacked', 'barStacked100Percent')] $Type = 'bar',
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [nullable[RGBColors]] $DataLabelsColor,
        [alias('PatternedColors')][switch] $Patterned,
        [switch] $Distributed,
        [switch] $Vertical)
    [PSCustomObject] @{ObjectType = 'BarOptions'
        Type                      = $Type
        Title                     = $Title
        TitleAlignment            = $TitleAlignment
        Horizontal                = -not $Vertical.IsPresent
        DataLabelsEnabled         = $DataLabelsEnabled
        DataLabelsOffsetX         = $DataLabelsOffsetX
        DataLabelsFontSize        = $DataLabelsFontSize
        DataLabelsColor           = $DataLabelsColor
        PatternedColors           = $Patterned.IsPresent
        Distributed               = $Distributed.IsPresent
    }
}
function New-ChartGrid {
    [alias('ChartGrid')]
    [CmdletBinding()]
    param([switch] $Show,
        [RGBColors] $BorderColor = [RGBColors]::None,
        [int] $StrokeDash,
        [ValidateSet('front', 'back', 'default')][string] $Position = 'default',
        [switch] $xAxisLinesShow,
        [switch] $yAxisLinesShow,
        [RGBColors[]] $RowColors,
        [double] $RowOpacity = 0.5,
        [RGBColors[]] $ColumnColors,
        [double] $ColumnOpacity = 0.5,
        [int] $PaddingTop,
        [int] $PaddingRight,
        [int] $PaddingBottom,
        [int] $PaddingLeft)
    [PSCustomObject] @{ObjectType = 'ChartGrid'
        Grid                      = @{Show = $Show.IsPresent
            BorderColor                    = $BorderColor
            StrokeDash                     = $StrokeDash
            Position                       = $Position
            xAxisLinesShow                 = $xAxisLinesShow.IsPresent
            yAxisLinesShow                 = $yAxisLinesShow.IsPresent
            RowColors                      = $RowColors
            RowOpacity                     = $RowOpacity
            ColumnColors                   = $ColumnColors
            ColumnOpacity                  = $ColumnOpacity
            PaddingTop                     = $PaddingTop
            PaddingRight                   = $PaddingRight
            PaddingBottom                  = $PaddingBottom
            PaddingLeft                    = $PaddingLeft
        }
    }
}
function New-ChartInternalArea {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category')
    $Options.chart = @{type = 'area' }
    $Options.series = @(New-ChartInternalDataSet -Data $Data -DataNames $DataNames)
    $Options.xaxis = [ordered] @{ }
    if ($DataCategoriesType -ne '') { $Options.xaxis.type = $DataCategoriesType }
    if ($DataCategories.Count -gt 0) { $Options.xaxis.categories = $DataCategories }
}
function New-ChartInternalAxisX {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [string] $TitleText,
        [int] $Min,
        [int] $Max,
        [ValidateSet('datetime', 'category', 'numeric')][string] $Type = 'category',
        [Array] $Names)
    if (-not $Options.Contains('xaxis')) { $Options.xaxis = @{ }
    }
    if ($TitleText -ne '') { $Options.xaxis.title = @{ }
        $Options.xaxis.title.text = $TitleText
    }
    if ($MinValue -gt 0) { $Options.xaxis.min = $Min }
    if ($MinValue -gt 0) { $Options.xaxis.max = $Max }
    if ($Type -ne '') { $Options.xaxis.type = $Type }
    if ($Names.Count -gt 0) { $Options.xaxis.categories = $Names }
}
function New-ChartInternalAxisY {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [string] $TitleText,
        [int] $Min,
        [int] $Max,
        [bool] $Show,
        [bool] $ShowAlways,
        [ValidateSet('90', '270')][string] $TitleRotate = '90',
        [int] $TitleOffsetX = 0,
        [int] $TitleOffsetY = 0,
        [RGBColors] $TitleStyleColor = [RGBColors]::None,
        [int] $TitleStyleFontSize = 12,
        [string] $TitleStylefontFamily = 'Helvetica, Arial, sans-serif')
    if (-not $Options.Contains('yaxis')) { $Options.yaxis = @{ }
    }
    $Options.yaxis.show = $Show
    $Options.yaxis.showAlways = $ShowAlways
    if ($TitleText -ne '') { $Options.yaxis.title = [ordered] @{ }
        $Options.yaxis.title.text = $TitleText
        $Options.yaxis.title.rotate = [int] $TitleRotate
        $Options.yaxis.title.offsetX = $TitleOffsetX
        $Options.yaxis.title.offsetY = $TitleOffsetY
        $Options.yaxis.title.style = [ordered] @{ }
        $Color = ConvertFrom-Color -Color $TitleStyleColor
        if ($null -ne $Color) { $Options.yaxis.title.style.color = $Coor }
        $Options.yaxis.title.style.fontSize = $TitleStyleFontSize
        $Options.yaxis.title.style.fontFamily = $TitleStylefontFamily
    }
    if ($Min -gt 0) { $Options.yaxis.min = $Min }
    if ($Min -gt 0) { $Options.yaxis.max = $Max }
}
Function New-ChartInternalBar {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [bool] $Horizontal = $true,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default',
        [string] $Formatter,
        [ValidateSet('bar', 'barStacked', 'barStacked100Percent')] $Type = 'bar',
        [switch] $PatternedColors,
        [switch] $Distributed,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend)
    if ($Type -eq 'bar') { $Options.chart = [ordered] @{type = 'bar' }
    } elseif ($Type -eq 'barStacked') {
        $Options.chart = [ordered] @{type = 'bar'
            stacked                       = $true
        }
    } else {
        $Options.chart = [ordered] @{type = 'bar'
            stacked                       = $true
            stackType                     = '100%'
        }
    }
    $Options.plotOptions = @{bar = @{horizontal = $Horizontal } }
    if ($Distributed) { $Options.plotOptions.bar.distributed = $Distributed.IsPresent }
    $Options.dataLabels = [ordered] @{enabled = $DataLabelsEnabled
        offsetX                               = $DataLabelsOffsetX
        style                                 = @{fontSize = $DataLabelsFontSize }
    }
    if ($null -ne $DataLabelsColor) {
        $RGBColorLabel = ConvertFrom-Color -Color $DataLabelsColor
        $Options.dataLabels.style.colors = @($RGBColorLabel)
    }
    $Options.series = @(New-ChartInternalDataSet -Data $Data -DataNames $DataLegend)
    $Options.xaxis = [ordered] @{ }
    if ($DataNames.Count -gt 0) { $Options.xaxis.categories = $DataNames }
    New-ChartInternalTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    if ($PatternedColors) {
        $Options.fill = @{type = 'pattern'
            opacity            = 1
            pattern            = @{style = @('circles', 'slantedLines', 'verticalLines', 'horizontalLines') }
        }
    }
}
function New-ChartInternalColors {
    param([System.Collections.IDictionary] $Options,
        [RGBColors[]]$Colors)
    if ($Colors.Count -gt 0) {
        $RGBColor = ConvertFrom-Color -Color $Colors
        $Options.colors = @($RGBColor)
    }
}
function New-ChartInternalDataLabels {
    param([System.Collections.IDictionary] $Options,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor)
    $Options.dataLabels = [ordered] @{enabled = $DataLabelsEnabled
        offsetX                               = $DataLabelsOffsetX
        style                                 = @{fontSize = $DataLabelsFontSize }
    }
    if ($DataLabelsColor.Count -gt 0) { $Options.dataLabels.style.colors = @(ConvertFrom-Color -Color $DataLabelsColor) }
}
function New-ChartInternalDataSet {
    [CmdletBinding()]
    param([Array] $Data,
        [Array] $DataNames)
    if ($null -ne $Data -and $null -ne $DataNames) {
        if ($Data[0] -is [System.Collections.ICollection]) {
            if ($Data[0].Count -eq $DataNames.Count) {
                for ($a = 0; $a -lt $Data.Count; $a++) {
                    [ordered] @{name = $DataNames[$a]
                        data         = $Data[$a]
                    }
                }
            } elseif ($Data.Count -eq $DataNames.Count) {
                for ($a = 0; $a -lt $Data.Count; $a++) {
                    [ordered] @{name = $DataNames[$a]
                        data         = $Data[$a]
                    }
                }
            } else { New-ChartInternalDataSet -Data $Data }
        } else {
            if ($null -ne $DataNames) {
                [ordered] @{name = $DataNames
                    data         = $Data
                }
            } else { [ordered] @{data = $Data }
            }
        }
    } elseif ($null -ne $Data) { if ($Data[0] -is [System.Collections.ICollection]) { foreach ($D in $Data) { [ordered] @{data = $D } } } else { [ordered] @{data = $Data }
        }
    } else {
        Write-Warning -Message "New-ChartInternalDataSet - No Data provided. Unabled to create dataset."
        return [ordered] @{ }
    }
}
function New-ChartInternalGrid {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [bool] $Show,
        [RGBColors] $BorderColor = [RGBColors]::None,
        [int] $StrokeDash,
        [ValidateSet('front', 'back', 'default')][string] $Position = 'default',
        [nullable[bool]] $xAxisLinesShow = $null,
        [nullable[bool]] $yAxisLinesShow = $null,
        [alias('GridColors')][RGBColors[]] $RowColors,
        [alias('GridOpacity')][double] $RowOpacity = 0.5,
        [RGBColors[]] $ColumnColors ,
        [double] $ColumnOpacity = 0.5,
        [int] $PaddingTop,
        [int] $PaddingRight,
        [int] $PaddingBottom,
        [int] $PaddingLeft)
    $Options.grid = [ordered] @{ }
    $Options.grid.Show = $Show
    if ($BorderColor -ne [RGBColors]::None) { $options.grid.borderColor = @(ConvertFrom-Color -Color $BorderColor) }
    if ($StrokeDash -gt 0) { $Options.grid.strokeDashArray = $StrokeDash }
    if ($Position -ne 'Default') { $Options.grid.position = $Position }
    if ($null -ne $xAxisLinesShow) { $Options.grid.xaxis = @{ }
        $Options.grid.xaxis.lines = @{ }
        $Options.grid.xaxis.lines.show = $xAxisLinesShow
    }
    if ($null -ne $yAxisLinesShow) { $Options.grid.yaxis = @{ }
        $Options.grid.yaxis.lines = @{ }
        $Options.grid.yaxis.lines.show = $yAxisLinesShow
    }
    if ($RowColors.Count -gt 0 -or $RowOpacity -ne 0) { $Options.grid.row = @{ }
        if ($RowColors.Count -gt 0) { $Options.grid.row.colors = @(ConvertFrom-Color -Color $RowColors) }
        if ($RowOpacity -ne 0) { $Options.grid.row.opacity = $RowOpacity }
    }
    if ($ColumnColors.Count -gt 0 -or $ColumnOpacity -ne 0) { $Options.grid.column = @{ }
        if ($ColumnColors.Count -gt 0) { $Options.grid.column.colors = @(ConvertFrom-Color -Color $ColumnColors) }
        if ($ColumnOpacity -ne 0) { $Options.grid.column.opacity = $ColumnOpacitys }
    }
    if ($PaddingTop -gt 0 -or $PaddingRight -gt 0 -or $PaddingBottom -gt 0 -or $PaddingLeft -gt 0) { $Options.grid.padding = @{ }
        if ($PaddingTop -gt 0) { $Options.grid.padding.PaddingTop = $PaddingTop }
        if ($PaddingRight -gt 0) { $Options.grid.padding.PaddingRight = $PaddingRight }
        if ($PaddingBottom -gt 0) { $Options.grid.padding.PaddingBottom = $PaddingBottom }
        if ($PaddingLeft -gt 0) { $Options.grid.padding.PaddingLeft = $PaddingLeft }
    }
}
function New-ChartInternalLegend {
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', 'default')][string] $LegendPosition = 'default')
    if ($LegendPosition -eq 'default' -or $LegendPosition -eq 'bottom') { } elseif ($LegendPosition -eq 'right') {
        $Options.legend = [ordered]@{position = 'right'
            offsetY                           = 100
            height                            = 230
        }
    } elseif ($LegendPosition -eq 'top') {
        $Options.legend = [ordered]@{position = 'top'
            horizontalAlign                   = 'left'
            offsetX                           = 40
        }
    } elseif ($LegendPosition -eq 'topRight') {
        $Options.legend = [ordered]@{position = 'top'
            horizontalAlign                   = 'right'
            floating                          = true
            offsetY                           = -25
            offsetX                           = -5
        }
    }
}
function New-ChartInternalLine {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Data,
        [Array] $DataNames,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category')
    $Options.chart = @{type = 'line' }
    $Options.series = @(New-ChartInternalDataSet -Data $Data -DataNames $DataNames)
    $Options.xaxis = [ordered] @{ }
    if ($DataCategoriesType -ne '') { $Options.xaxis.type = $DataCategoriesType }
    if ($DataCategories.Count -gt 0) { $Options.xaxis.categories = $DataCategories }
}
function New-ChartInternalMarker {
    param([System.Collections.IDictionary] $Options,
        [int] $MarkerSize)
    if ($MarkerSize -gt 0) { $Options.markers = @{size = $MarkerSize }
    }
}
function New-ChartInternalRadial {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names,
        $Type)
    $Options.chart = @{type = 'radialBar' }
    if ($Type -eq '1') { New-ChartInternalRadialType1 -Options $Options } elseif ($Type -eq '2') { New-ChartInternalRadialType2 -Options $Options }
    $Options.series = @($Values)
    $Options.labels = @($Names)
}
function New-ChartInternalRadialCircleType {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('FullCircleTop', 'FullCircleBottom', 'FullCircleBottomLeft', 'FullCircleLeft', 'Speedometer', 'SemiCircleGauge')] $CircleType)
    if ($CircleType -eq 'SemiCircleGauge') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -90
            endAngle                                            = 90
        }
    } elseif ($CircleType -eq 'FullCircleBottom') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -180
            endAngle                                            = 180
        }
    } elseif ($CircleType -eq 'FullCircleLeft') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -90
            endAngle                                            = 270
        }
    } elseif ($CircleType -eq 'FullCircleBottomLeft') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -135
            endAngle                                            = 225
        }
    } elseif ($CircleType -eq 'Speedometer') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -135
            endAngle                                            = 135
        }
    } else { }
}
function New-ChartInternalRadialDataLabels {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [string] $LabelAverage = 'Average')
    if ($LabelAverage -ne '') {
        $Options.plotOptions.radialBar.dataLabels = @{showOn = 'always'
            name                                             = @{ }
            value                                            = @{ }
            total                                            = @{show = $true
                label                                                 = $LabelAverage
            }
        }
    }
}
function New-ChartInternalRadialType1 {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names)
    $Options.plotOptions = @{radialBar = [ordered] @{hollow = [ordered] @{margin = 0
                size                                                             = '70%'
                background                                                       = '#fff'
                image                                                            = 'undefined'
                imageOffsetX                                                     = 0
                imageOffsetY                                                     = 0
                position                                                         = 'front'
                dropShadow                                                       = @{enabled = $true
                    top                                                                      = 3
                    left                                                                     = 0
                    blur                                                                     = 4
                    opacity                                                                  = 0.24
                }
            }
            track                                           = [ordered] @{background = '#fff'
                strokeWidth                                                          = '70%'
                margin                                                               = 0
                dropShadow                                                           = [ordered] @{enabled = $true
                    top                                          = -3
                    left                                         = 0
                    blur                                         = 4
                    opacity                                      = 0.35
                }
            }
        }
    }
    $Options.fill = [ordered] @{type = 'gradient'
        gradient                     = [ordered] @{shade = 'dark'
            type                                         = 'horizontal'
            shadeIntensity                               = 0.5
            gradientToColors                             = @('#ABE5A1')
            inverseColors                                = true
            opacityFrom                                  = 1
            opacityTo                                    = 1
            stops                                        = @(0, 100)
        }
    }
    $Options.stroke = [ordered] @{dashArray = 4 }
}
function New-ChartInternalRadialType2 {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names)
    $Options.plotOptions = @{radialBar = [ordered] @{hollow = [ordered] @{margin = 0
                size                                                             = '70%'
                background                                                       = '#fff'
                image                                                            = 'undefined'
                imageOffsetX                                                     = 0
                imageOffsetY                                                     = 0
                position                                                         = 'front'
                dropShadow                                                       = @{enabled = $true
                    top                                                                      = 3
                    left                                                                     = 0
                    blur                                                                     = 4
                    opacity                                                                  = 0.24
                }
            }
        }
    }
}
function New-ChartInternalSize {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [nullable[int]] $Height = 350,
        [nullable[int]] $Width)
    if ($null -ne $Height) { $Options.chart.height = $Height }
    if ($null -ne $Width) { $Options.chart.width = $Width }
}
function New-ChartInternalSpark {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [nullable[RGBColors]] $Color,
        [string] $Title,
        [string] $SubTitle,
        [int] $FontSizeTitle = 24,
        [int] $FontSizeSubtitle = 14,
        [Array] $Values)
    if ($Values.Count -eq 0) { Write-Warning 'Get-ChartSpark - Values Empty' }
    if ($null -ne $Color) {
        $ColorRGB = ConvertFrom-Color -Color $Color
        $Options.colors = @($ColorRGB)
    }
    $Options.chart = [ordered] @{type = 'area'
        sparkline                     = @{enabled = $true }
    }
    $Options.stroke = @{curve = 'straight' }
    $Options.title = [ordered] @{text = $Title
        offsetX                       = 0
        style                         = @{fontSize = "$($FontSizeTitle)px"
            cssClass                               = 'apexcharts-yaxis-title'
        }
    }
    $Options.subtitle = [ordered] @{text = $SubTitle
        offsetX                          = 0
        style                            = @{fontSize = "$($FontSizeSubtitle)px"
            cssClass                                  = 'apexcharts-yaxis-title'
        }
    }
    $Options.yaxis = @{min = 0 }
    $Options.fill = @{opacity = 0.3 }
    $Options.series = @(if ($Values[0] -is [Array]) { foreach ($Value in $Values) { @{data = @($Value) } }
        } else { @{data = @($Values) }
        })
}
function New-ChartInternalStrokeDefinition {
    param([System.Collections.IDictionary] $Options,
        [bool] $LineShow = $true,
        [ValidateSet('straight', 'smooth', 'stepline')][string[]] $LineCurve,
        [int[]] $LineWidth,
        [ValidateSet('butt', 'square', 'round')][string[]] $LineCap,
        [RGBColors[]] $LineColor,
        [int[]] $LineDash)
    $Options.stroke = [ordered] @{show = $LineShow }
    if ($LineCurve.Count -gt 0) { $Options.stroke.curve = $LineCurve }
    if ($LineWidth.Count -gt 0) { $Options.stroke.width = $LineWidth }
    if ($LineColor.Count -gt 0) { $Options.stroke.colors = @(ConvertFrom-Color -Color $LineColor) }
    if ($LineCap.Count -gt 0) { $Options.stroke.lineCap = $LineCap }
    if ($LineDash.Count -gt 0) { $Options.stroke.dashArray = $LineDash }
}
function New-ChartInternalTheme {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('light', 'dark')][string] $Mode,
        [ValidateSet('palette1',
            'palette2',
            'palette3',
            'palette4',
            'palette5',
            'palette6',
            'palette7',
            'palette8',
            'palette9',
            'palette10')
        ][string] $Palette = 'palette1',
        [switch] $Monochrome,
        [RGBColors] $Color = [RGBColors]::DodgerBlue,
        [ValidateSet('light', 'dark')][string] $ShadeTo = 'lightF',
        [double] $ShadeIntensity = 0.65)
    $Options.theme = [ordered] @{mode = $Mode
        palette                       = $Palette
        monochrome                    = [ordered] @{enabled = $Monochrome.IsPresent
            color                                           = $Color
            shadeTo                                         = $ShadeTo
            shadeIntensity                                  = $ShadeIntensity
        }
    }
}
function New-ChartInternalTitle {
    param([System.Collections.IDictionary] $Options,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default')
    $Options.title = [ordered] @{ }
    if ($TitleText -ne '') { $Options.title.text = $Title }
    if ($TitleAlignment -ne 'default') { $Options.title.align = $TitleAlignment }
}
function New-ChartInternalToolbar {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [bool] $Show = $false,
        [bool] $Download = $false,
        [bool] $Selection = $false,
        [bool] $Zoom = $false,
        [bool] $ZoomIn = $false,
        [bool] $ZoomOut = $false,
        [bool] $Pan = $false,
        [bool] $Reset = $false,
        [ValidateSet('zoom', 'selection', 'pan')][string] $AutoSelected = 'zoom')
    $Options.chart.toolbar = [ordered] @{show = $show
        tools                                 = [ordered] @{download = $Download
            selection                                                = $Selection
            zoom                                                     = $Zoom
            zoomin                                                   = $ZoomIn
            zoomout                                                  = $ZoomOut
            pan                                                      = $Pan
            reset                                                    = $Reset
        }
        autoSelected                          = $AutoSelected
    }
}
function New-ChartInternalZoom {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [switch] $Enabled)
    if ($Enabled) {
        $Options.chart.zoom = @{type = 'x'
            enabled                  = $Enabled.IsPresent
        }
    }
}
function New-ChartLegend {
    [alias('ChartLegend')]
    [CmdletBinding()]
    param([Array] $Names,
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', 'default')][string] $LegendPosition = 'default',
        [RGBColors[]] $Color)
    [PSCustomObject] @{ObjectType = 'Legend'
        Names                     = $Names
        LegendPosition            = $LegendPosition
        Color                     = $Color
    }
}
function New-ChartLine {
    [alias('ChartLine')]
    [CmdletBinding()]
    param([string] $Name,
        [object] $Value,
        [RGBColors] $Color,
        [ValidateSet('straight', 'smooth', 'stepline')] $Curve = 'straight',
        [int] $Width = 6,
        [ValidateSet('butt', 'square', 'round')][string] $Cap = 'butt',
        [int] $Dash = 0)
    [PSCustomObject] @{ObjectType = 'Line'
        Name                      = $Name
        Value                     = $Value
        LineColor                 = $Color
        LineCurve                 = $Curve
        LineWidth                 = $Width
        LineCap                   = $Cap
        LineDash                  = $Dash
    }
}
function New-ChartTheme {
    [alias('ChartTheme')]
    [CmdletBinding()]
    param([ValidateSet('light', 'dark')][string] $Mode,
        [ValidateSet('palette1',
            'palette2',
            'palette3',
            'palette4',
            'palette5',
            'palette6',
            'palette7',
            'palette8',
            'palette9',
            'palette10')
        ][string] $Palette = 'palette1',
        [switch] $Monochrome,
        [RGBColors] $Color = [RGBColors]::DodgerBlue,
        [ValidateSet('light', 'dark')][string] $ShadeTo = 'lightF',
        [double] $ShadeIntensity = 0.65)
    [PSCustomObject] @{ObjectType = 'Theme'
        Mode                      = $Mode
        Palette                   = $Palette
        Monochrome                = $Monochrome.IsPresent
        Color                     = $Color
        ShadeTo                   = $ShadeTo
        ShadeIntensity            = $ShadeIntensity
    }
}
function New-ChartToolbar {
    [alias('ChartToolbar')]
    [CmdletBinding()]
    param([switch] $Download,
        [switch] $Selection,
        [switch] $Zoom,
        [switch] $ZoomIn,
        [switch] $ZoomOut,
        [switch] $Pan,
        [switch] $Reset,
        [ValidateSet('zoom', 'selection', 'pan')][string] $AutoSelected = 'zoom')
    [PSCustomObject] @{ObjectType = 'Toolbar'
        Toolbar                   = @{download = $Download.IsPresent
            selection                          = $Selection.IsPresent
            zoom                               = $Zoom.IsPresent
            zoomin                             = $ZoomIn.IsPresent
            zoomout                            = $ZoomOut.IsPresent
            pan                                = $Pan.IsPresent
            reset                              = $Reset.IsPresent
            autoSelected                       = $AutoSelected
        }
    }
}
Function New-HTML {
    [CmdletBinding()]
    param([Parameter(Position = 0)][ValidateNotNull()][ScriptBlock] $HtmlData = $(Throw "Have you put the open curly brace on the next line?"),
        [switch] $UseCssLinks,
        [switch] $UseJavaScriptLinks,
        [alias('Name')][String] $TitleText,
        [string] $Author,
        [string] $DateFormat = 'yyyy-MM-dd HH:mm:ss',
        [int] $AutoRefresh,
        [Parameter(Mandatory = $false)][string]$FilePath,
        [alias('Show', 'Open')][Parameter(Mandatory = $false)][switch]$ShowHTML,
        [ValidateSet('Unknown', 'String', 'Unicode', 'Byte', 'BigEndianUnicode', 'UTF8', 'UTF7', 'UTF32', 'Ascii', 'Default', 'Oem', 'BigEndianUTF32')] $Encoding = 'UTF8')
    [string] $CurrentDate = (Get-Date).ToString($DateFormat)
    $Script:HTMLSchema = @{TabsHeaders = [System.Collections.Generic.List[HashTable]]::new()
        Features                       = @{ }
        Charts                         = [System.Collections.Generic.List[string]]::new()
        TabOptions                     = @{SlimTabs = $false }
    }
    $OutputHTML = Invoke-Command -ScriptBlock $HtmlData
    if ($null -ne $OutputHTML -and $OutputHTML.Count -gt 0) {
        $Logo = Get-HTMLPartContent -Content $OutputHTML -Start '<!-- START LOGO -->' -End '<!-- END LOGO -->' -Type Between
        $OutputHTML = Get-HTMLPartContent -Content $OutputHTML -Start '<!-- START LOGO -->' -End '<!-- END LOGO -->' -Type After
    }
    $Features = Get-FeaturesInUse -PriorityFeatures 'JQuery', 'DataTables', 'Tabs'
    $HTML = @('<!DOCTYPE html>'
        New-HTMLTag -Tag 'html' { '<!-- HEADER -->'
            New-HTMLTag -Tag 'head' { New-HTMLTag -Tag 'meta' -Attributes @{charset = "utf-8" } -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'viewport'; content = 'width=device-width, initial-scale=1' } -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'author'; content = $Author } -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'revised'; content = $CurrentDate } -SelfClosing
                New-HTMLTag -Tag 'title' { $TitleText }
                if ($Autorefresh -gt 0) { New-HTMLTag -Tag 'meta' -Attributes @{'http-equiv' = 'refresh'; content = $Autorefresh } -SelfClosing
                }
                Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'HeaderAlways' -Features Default, DefaultHeadings, Fonts, FontsAwesome
                Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'HeaderAlways' -Features Default, DefaultHeadings
                if ($null -ne $Features) {
                    Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'HeaderAlways' -Features $Features -NoScript
                    Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'HeaderAlways' -Features $Features -NoScript
                    Get-Resources -UseCssLinks:$UseCssLinks -UseJavaScriptLinks:$UseJavaScriptLinks -Location 'Header' -Features $Features
                } }
            '<!-- END HEADER -->'
            '<!-- BODY -->'
            New-HTMLTag -Tag 'body' { $Logo
                if ($Script:HTMLSchema.TabsHeaders) { New-HTMLTabHead }
                $OutputHTML
                foreach ($Chart in $Script:HTMLSchema.Charts) { $Chart } }
            '<!-- END BODY -->'
            '<!-- FOOTER -->'
            New-HTMLTag -Tag 'footer' { if ($null -ne $Features) {
                    Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'FooterAlways' -Features $Features
                    Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'FooterAlways' -Features $Features
                    Get-Resources -UseCssLinks:$UseCssLinks -UseJavaScriptLinks:$UseJavaScriptLinks -Location 'Footer' -Features $Features
                } }
            '<!-- END FOOTER -->' })
    if ($FilePath -ne '') { Save-HTML -HTML $HTML -FilePath $FilePath -ShowHTML:$ShowHTML -Encoding $Encoding } else { $HTML }
}
function New-HTMLAnchor {
    <#
    .SYNOPSIS
    Short description
     
    .DESCRIPTION
    Long description
     
    .PARAMETER Name
    Parameter description
     
    .PARAMETER Id
    Parameter description
     
    .PARAMETER Target
    Parameter description
     
    .PARAMETER Class
    Parameter description
     
    .PARAMETER HrefLink
    Parameter description
     
    .PARAMETER OnClick
    Parameter description
     
    .PARAMETER Style
    Parameter description
     
    .PARAMETER Text
    Parameter description
     
    .EXAMPLE
    New-HTMLAnchor -Target _parent
 
    New-HTMLAnchor -Id "show_$RandomNumber" -Href '#' -OnClick "show('$RandomNumber');" -Style "color: #ffffff; display:none;" -Text 'Show'
 
    Output:
    <a target = "_parent" />
     
    .NOTES
    General notes
    #>

    param([alias('AnchorName')][string] $Name,
        [string] $Id,
        [string] $Target,
        [string] $Class,
        [alias('Url', 'Link', 'UrlLink', 'Href')][string] $HrefLink,
        [string] $OnClick,
        [string] $Style,
        [alias('AnchorText', 'Value')][string] $Text)
    $Attributes = [ordered]@{'id' = $Id
        'name'                    = $Name
        'class'                   = $Class
        'target'                  = $Target
        'href'                    = $HrefLink
        'onclick'                 = $OnClick
        'style'                   = $Style
    }
    New-HTMLTag -Tag 'a' -Attributes $Attributes { $Text }
}
Function New-HTMLAnchorLink {
    <#
    .SYNOPSIS
    Creates Hyperlink for an Anchor
 
    .DESCRIPTION
    Long description
 
    .PARAMETER AnchorName
    The Actual name of the Anchor (Hidden)
 
    .PARAMETER AnchorText
    The HyperLink text. Will default to $AnchorNname if not specified
 
    .EXAMPLE
    Get-HTMLAnchorLink -AnchorName 'test'
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param
    ([Parameter(Mandatory = $true)][String] $AnchorName,
        [Parameter(Mandatory = $false)][String] $AnchorText)
    if ($AnchorText -eq $null -or $AnchorText -eq '') { $AnchorText = $AnchorName }
    New-HTMLAnchor -Name $AnchorName -HrefLink '#' -Class 'alink' -Text $AnchorText
}
Function New-HTMLAnchorName {
    <#
    .SYNOPSIS
    Creates an anchor
 
    .DESCRIPTION
    Long description
 
    .PARAMETER AnchorName
    Parameter description
 
    .EXAMPLE
    An example
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)][String] $AnchorName)
    New-HTMLAnchor -Name $AnchorName
}
function New-HTMLCanvas {
    [CmdletBinding()]
    param([alias('Value')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace with Content"),
        [string] $ID,
        [string] $Width,
        [string] $Height,
        [string] $Style)
    $Canvas = [Ordered] @{Tag = 'canvas'
        Attributes            = [ordered]@{'id' = $Id
            'width'                             = $Width
            'height'                            = $Height
            'style'                             = $Style
        }
        SelfClosing           = $false
        Value                 = Invoke-Command -ScriptBlock $Content
    }
    $HTML = Set-Tag -HtmlObject $Canvas
    return $HTML
}
function New-HTMLChart {
    [alias('Chart')]
    [CmdletBinding()]
    param([ScriptBlock] $ChartSettings,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default',
        [nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default')
    $DataSet = [System.Collections.Generic.List[object]]::new()
    $DataName = [System.Collections.Generic.List[object]]::new()
    $Colors = @()
    $LineColors = [System.Collections.Generic.List[RGBColors]]::new()
    $LineCurves = [System.Collections.Generic.List[string]]::new()
    $LineWidths = [System.Collections.Generic.List[int]]::new()
    $LineDashes = [System.Collections.Generic.List[int]]::new()
    $LineCaps = [System.Collections.Generic.List[string]]::new()
    [string] $BarType = 'bar'
    [bool] $BarHorizontal = $true
    [bool] $BarDataLabelsEnabled = $true
    [int] $BarDataLabelsOffsetX = -6
    [string] $BarDataLabelsFontSize = '12px'
    [bool] $BarPatternedColors = $false
    [bool] $BarDistributed = $false
    [string] $LegendPosition = 'default'
    [Array] $Settings = & $ChartSettings
    foreach ($Setting in $Settings) {
        if ($Setting.ObjectType -eq 'Bar') {
            $Type = 'Bar'
            $DataSet.Add($Setting.Value)
            $DataName.Add($Setting.Name)
        } elseif ($Setting.ObjectType -eq 'Legend') {
            $DataLegend = $Setting.Names
            $LegendPosition = $Setting.LegendPosition
            if ($null -ne $Setting.Color) { $Colors = $Setting.Color }
        } elseif ($Setting.ObjectType -eq 'BarOptions') {
            $BarType = $Setting.Type
            $BarHorizontal = $Setting.Horizontal
            $BarDataLabelsEnabled = $Setting.DataLabelsEnabled
            $BarDataLabelsOffsetX = $Setting.DataLabelsOffsetX
            $BarDataLabelsFontSize = $Setting.DataLabelsFontSize
            $BarDataLabelsColor = $Setting.DataLabelsColor
            $BarPatternedColors = $Setting.PatternedColors
            $BarDistributed = $Setting.Distributed
        } elseif ($Setting.ObjectType -eq 'Toolbar') { $Toolbar = $Setting.Toolbar } elseif ($Setting.ObjectType -eq 'Line') {
            $Type = 'Line'
            $DataSet.Add($Setting.Value)
            $DataName.Add($Setting.Name)
            if ($Setting.LineColor) { $LineColors.Add($Setting.LineColor) }
            if ($Setting.LineCurve) { $LineCurves.Add($Setting.LineCurve) }
            if ($Setting.LineWidth) { $LineWidths.Add($Setting.LineWidth) }
            if ($Setting.LineDash) { $LineDashes.Add($Setting.LineDash) }
            if ($Setting.LineCap) { $LineCaps.Add($Setting.LineCap) }
        } elseif ($Setting.ObjectType -eq 'ChartAxisX') { $ChartAxisX = $Setting.ChartAxisX } elseif ($Setting.ObjectType -eq 'ChartGrid') { $GridOptions = $Setting.Grid } elseif ($Setting.ObjectType -eq 'ChartAxisY') { $ChartAxisY = $Setting.ChartAxisY }
    }
    if ($Type -eq 'Bar') {
        if ($DataLegend.Count -lt $DataSet[0].Count) { Write-Warning -Message "Chart Legend count doesn't match values count. Skipping." }
        $HashTable = [ordered] @{ }
        $ArrayCount = $DataSet[0].Count
        if ($ArrayCount -eq 1) { $HashTable.1 = $DataSet } else {
            for ($i = 0; $i -lt $ArrayCount; $i++) { $HashTable.$i = [System.Collections.Generic.List[object]]::new() }
            foreach ($Value in $DataSet) { for ($h = 0; $h -lt $Value.Count; $h++) { $HashTable[$h].Add($Value[$h]) } }
        }
        New-HTMLChartBar -Data $($HashTable.Values) -DataNames $DataName -DataLegend $DataLegend -LegendPosition $LegendPosition -Type $BarType -Title $Title -TitleAlignment $TitleAlignment -Horizontal:$BarHorizontal -DataLabelsEnabled $BarDataLabelsEnabled -PatternedColors:$BarPatternedColors -DataLabelsOffsetX $BarDataLabelsOffsetX -DataLabelsFontSize $BarDataLabelsFontSize -Distributed:$BarDistributed -DataLabelsColor $BarDataLabelsColor -Height $Height -Width $Width -Colors $Colors -Toolbar $Toolbar -Positioning $Positioning
    } elseif ($Type -eq 'Line') {
        if (-not $ChartAxisX) {
            Write-Warning -Message 'Chart Category (Chart Axis X) is missing.'
            Exit
        }
        New-HTMLChartLine -Data $DataSet -DataNames $DataName -Title $Title -TitleAlignment $TitleAlignment -DataLabelsEnabled $BarDataLabelsEnabled -DataLabelsOffsetX $BarDataLabelsOffsetX -DataLabelsFontSize $BarDataLabelsFontSize -DataLabelsColor $BarDataLabelsColor -Height $Height -Width $Width -Positioning $Positioning -LineColor $LineColors -LineCurve $LineCurves -LineWidth $LineWidths -LineDash $LineDashes -LineCap $LineCaps -GridOptions $GridOptions -ChartAxisX $ChartAxisX -ChartAxisY $ChartAxisY
    }
}
function New-HTMLChartArea {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default',
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category',
        [ValidateSet('straight', 'smooth', 'stepline')] $LineCurve = 'straight',
        [int] $LineWidth,
        [RGBColors[]] $LineColor,
        [RGBColors[]] $GridColors,
        [double] $GridOpacity,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default',
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', 'default')][string] $LegendPosition = 'default',
        [string] $TitleX,
        [string] $TitleY,
        [int] $MarkerSize,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend,
        [switch] $Zoom)
    $Options = [ordered] @{ }
    New-ChartInternalArea -Options $Options -Data $Data -DataNames $DataNames
    New-ChartInternalStrokeDefinition -Options $Options -LineShow $true -LineCurve $LineCurve -LineWidth $LineWidth -LineColor $LineColor
    New-ChartInternalDataLabels -Options $Options -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor
    New-ChartInternalAxisX -Options $Options -Title $TitleX -DataCategoriesType $DataCategoriesType -DataCategories $DataLegend
    New-ChartInternalAxisY -Options $Options -Title $TitleY
    New-ChartInternalMarker -Options $Options -MarkerSize $MarkerSize
    New-ChartInternalTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    New-ChartInternalGrid -Options $Options -GridColors $GridColors -GridOpacity $GridOpacity
    New-ChartInternalLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartInternalSize -Options $Options -Height $Height -Width $Width
    New-ChartInternalZoom -Options $Options -Enabled:$Zoom
    New-ChartInternalToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartBar {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default',
        [ValidateSet('bar', 'barStacked', 'barStacked100Percent')] $Type = 'bar',
        [RGBColors[]] $Colors,
        [switch] $PatternedColors,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default',
        [bool] $Horizontal = $true,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [nullable[RGBColors]] $DataLabelsColor,
        [switch] $Distributed,
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', 'default')][string] $LegendPosition = 'default',
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend,
        [hashtable] $Toolbar)
    $Options = [ordered] @{ }
    New-ChartInternalBar -Options $Options -Horizontal $Horizontal -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor -Data $Data -DataNames $DataNames -DataLegend $DataLegend -Title $Title -TitleAlignment $TitleAlignment -Type $Type -PatternedColors:$PatternedColors -Distributed:$Distributed
    New-ChartInternalColors -Options $Options -Colors $Colors
    New-ChartInternalLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartInternalSize -Options $Options -Height $Height -Width $Width
    if ($Toolbar.Count -eq 0) { $Toolbar = @{Show = $false }
    } else { $Toolbar.Show = $true }
    New-ChartInternalToolbar -Options $Options @Toolbar
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartLine {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default',
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [ValidateSet('straight', 'smooth', 'stepline')][string[]] $LineCurve,
        [int[]] $LineWidth,
        [RGBColors[]] $LineColor,
        [int[]] $LineDash,
        [ValidateSet('butt', 'square', 'round')][string[]] $LineCap,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', 'default')][string] $TitleAlignment = 'default',
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', 'default')][string] $LegendPosition = 'default',
        [int] $MarkerSize,
        [Array] $Data,
        [Array] $DataNames,
        [System.Collections.IDictionary] $GridOptions,
        [System.Collections.IDictionary] $ChartAxisX,
        [System.Collections.IDictionary] $ChartAxisY)
    $Options = [ordered] @{ }
    New-ChartInternalLine -Options $Options -Data $Data -DataNames $DataNames
    if ($LineCurve.Count -eq 0 -or ($LineCurve.Count -ne $DataNames.Count)) { $LineCurve = for ($i = $LineCurve.Count; $i -le $DataNames.Count; $i++) { 'straight' } }
    if ($LineCap.Count -eq 0 -or ($LineCap.Count -ne $DataNames.Count)) { $LineCap = for ($i = $LineCap.Count; $i -le $DataNames.Count; $i++) { 'butt' } }
    if ($LineDash.Count -eq 0) { }
    New-ChartInternalStrokeDefinition -Options $Options -LineShow $true -LineCurve $LineCurve -LineWidth $LineWidth -LineColor $LineColor -LineCap $LineCap -LineDash $LineDash
    New-ChartInternalColors -Options $Options -Colors $LineColor
    New-ChartInternalDataLabels -Options $Options -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor
    if ($ChartAxisX) { New-ChartInternalAxisX -Options $Options @ChartAxisX } else { }
    if ($ChartAxisY) { New-ChartInternalAxisY -Options $Options @ChartAxisY } else { }
    New-ChartInternalMarker -Options $Options -MarkerSize $MarkerSize
    New-ChartInternalTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    if ($GridOptions) { New-ChartInternalGrid -Options $Options @GridOptions } else { New-ChartInternalGrid -Options $Options }
    New-ChartInternalLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartInternalSize -Options $Options -Height $Height -Width $Width
    New-ChartInternalToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartRadial {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default',
        [Array] $Names,
        [Array] $Values,
        $Type,
        [ValidateSet('FullCircleTop', 'FullCircleBottom', 'FullCircleBottomLeft', 'FullCircleLeft', 'Speedometer', 'SemiCircleGauge')] $CircleType = 'FullCircleTop',
        [string] $LabelAverage)
    $Options = [ordered] @{ }
    New-ChartInternalRadial -Options $Options -Names $Names -Values $Values -Type $Type
    New-ChartInternalRadialCircleType -Options $Options -CircleType $CircleType
    New-ChartInternalRadialDataLabels -Options $Options -Label $LabelAverage
    New-ChartInternalSize -Options $Options -Height $Height -Width $Width
    New-ChartInternalToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartSpark {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('default', 'central')][string] $Positioning = 'default',
        [Array] $Data,
        [string] $TitleText,
        [string] $SubTitleText,
        [int] $FontSizeTitle = 24,
        [int] $FontSizeSubtitle = 14,
        [nullable[RGBColors]] $Color)
    $Options = [ordered] @{ }
    New-ChartInternalSpark -Options $Options -Color $Color -Title $TitleText -SubTitle $SubTitleText -FontSizeTitle $FontSizeTitle -FontSizeSubtitle $FontSizeSubtitle -Values $Data
    New-ChartInternalSize -Options $Options -Height $Height -Width $Width
    New-ChartInternalToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
Function New-HTMLCodeBlock {
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)][String] $Code,
        [Parameter(Mandatory = $false)]
        [ValidateSet('assembly',
            'asm',
            'avrassembly',
            'avrasm',
            'c',
            'cpp',
            'c++',
            'csharp',
            'css',
            'cython',
            'cordpro',
            'diff',
            'docker',
            'dockerfile',
            'generic',
            'standard',
            'groovy',
            'go',
            'golang',
            'html',
            'ini',
            'conf',
            'java',
            'js',
            'javascript',
            'jquery',
            'mootools',
            'ext.js',
            'json',
            'kotlin',
            'less',
            'lua',
            'gfm',
            'md',
            'markdown',
            'octave',
            'matlab',
            'nsis',
            'php',
            'powershell',
            'prolog',
            'py',
            'python',
            'raw',
            'ruby',
            'rust',
            'scss',
            'sass',
            'shell',
            'bash',
            'sql',
            'squirrel',
            'swift',
            'typescript',
            'vhdl',
            'visualbasic',
            'vb',
            'xml',
            'yaml')]
        [String] $Style = 'powershell',
        [Parameter(Mandatory = $false)]
        [ValidateSet('enlighter',
            'standard',
            'classic',
            'bootstrap4',
            'beyond',
            'godzilla',
            'eclipse',
            'mootwo',
            'droide',
            'minimal',
            'atomic',
            'dracula',
            'rowhammer')][String] $Theme,
        [Parameter(Mandatory = $false)][String] $Group,
        [Parameter(Mandatory = $false)][String] $Title,
        [Parameter(Mandatory = $false)][String] $Highlight,
        [Parameter(Mandatory = $false)][nullable[bool]] $ShowLineNumbers,
        [Parameter(Mandatory = $false)][String] $LineOffset)
    $Script:HTMLSchema.Features.CodeBlocks = $true
    $Attributes = [ordered]@{'data-enlighter-language' = "$Style".ToLower()
        'data-enlighter-theme'                         = "$Theme".ToLower()
        'data-enlighter-group'                         = "$Group".ToLower()
        'data-enlighter-title'                         = "$Title"
        'data-enlighter-linenumbers'                   = "$ShowLineNumbers"
        'data-enlighter-highlight'                     = "$Highlight"
        'data-enlighter-lineoffset'                    = "$LineOffset".ToLower()
    }
    New-HTMLTag -Tag 'pre' -Attributes $Attributes { $Code }
}
function New-HTMLContainer {
    param([Parameter(Mandatory = $false, Position = 0)][ScriptBlock] $HTML)
    New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultPanelOther' } { if ($HTML) { Invoke-Command -ScriptBlock $HTML } }
}
Function New-HTMLHeading {
    [CmdletBinding()]
    Param ([validateset('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7')][string]$Heading,
        [string]$HeadingText,
        [validateset('default', 'central')][string] $Type = 'default',
        [switch] $Underline,
        [nullable[RGBColors]] $Color)
    if ($null -ne $Color) {
        $RGBcolor = ConvertFrom-Color -Color $Color
        $Attributes = @{style = "color: $RGBcolor;" }
    } else { $Attributes = @{ }
    }
    if ($Type -eq 'central') { $Attributes.Class = 'central' }
    if ($Underline) { $Attributes.Class = "$($Attributes.Class) underline" }
    New-HTMLTag -Tag $Heading -Attributes $Attributes { $HeadingText }
}
function New-HTMLHorizontalLine {
    [CmdletBinding()]
    param()
    New-HTMLTag -Tag 'hr' -SelfClosing
}
function New-HTMLImage {
    <#
    .SYNOPSIS
    Short description
 
    .DESCRIPTION
    Long description
 
    .PARAMETER Source
    Parameter description
 
    .PARAMETER UrlLink
    Parameter description
 
    .PARAMETER AlternativeText
    Parameter description
 
    .PARAMETER Class
    Parameter description
 
    .PARAMETER Target
    Parameter description
 
    .PARAMETER Width
    Parameter description
 
    .PARAMETER Height
    Parameter description
 
    .EXAMPLE
    New-HTMLImage -Source 'https://evotec.pl/image.png' -UrlLink 'https://evotec.pl/' -AlternativeText 'My other text' -Class 'otehr' -Width '100%'
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $Source,
        [Uri] $UrlLink = '',
        [string] $AlternativeText = '',
        [string] $Class = 'Logo',
        [string] $Target = '_blank',
        [string] $Width,
        [string] $Height)
    New-HTMLTag -Tag 'div' -Attributes @{class = $Class.ToLower() } { $AAttributes = [ordered]@{'target' = $Target
            'href'                                                                                       = $UrlLink
        }
        New-HTMLTag -Tag 'a' -Attributes $AAttributes { $ImgAttributes = [ordered]@{'src' = "$Source"
                'alt'                                                                     = "$AlternativeText"
                'width'                                                                   = "$Height"
                'height'                                                                  = "$Width"
            }
            New-HTMLTag -Tag 'img' -Attributes $ImgAttributes } }
}
function New-HTMLList {
    [CmdletBinding()]
    param([ScriptBlock]$ListItems,
        [ValidateSet('Unordered', 'Ordered')] [string] $Type = 'Unordered',
        [RGBColors] $Color,
        [RGBColors] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $LineBreak)
    $newHTMLSplat = @{ }
    if ($Alignment) { $newHTMLSplat.Alignment = $Alignment }
    if ($FontSize) { $newHTMLSplat.FontSize = $FontSize }
    if ($TextTransform) { $newHTMLSplat.TextTransform = $TextTransform }
    if ($Color) { $newHTMLSplat.Color = $Color }
    if ($FontFamily) { $newHTMLSplat.FontFamily = $FontFamily }
    if ($Direction) { $newHTMLSplat.Direction = $Direction }
    if ($FontStyle) { $newHTMLSplat.FontStyle = $FontStyle }
    if ($TextDecoration) { $newHTMLSplat.TextDecoration = $TextDecoration }
    if ($BackGroundColor) { $newHTMLSplat.BackGroundColor = $BackGroundColor }
    if ($FontVariant) { $newHTMLSplat.FontVariant = $FontVariant }
    if ($FontWeight) { $newHTMLSplat.FontWeight = $FontWeight }
    if ($LineBreak) { $newHTMLSplat.LineBreak = $LineBreak }
    [bool] $SpanRequired = $false
    foreach ($Entry in $newHTMLSplat.GetEnumerator()) {
        if ((Get-ObjectCount -Object $Entry.Value) -gt 0) {
            $SpanRequired = $true
            break
        }
    }
    if ($SpanRequired) { New-HTMLSpanStyle @newHTMLSplat { if ($Type -eq 'Unordered') { New-HTMLTag -Tag 'ul' { Invoke-Command -ScriptBlock $ListItems } } else { New-HTMLTag -Tag 'ol' { Invoke-Command -ScriptBlock $ListItems } } } } else { if ($Type -eq 'Unordered') { New-HTMLTag -Tag 'ul' { Invoke-Command -ScriptBlock $ListItems } } else { New-HTMLTag -Tag 'ol' { Invoke-Command -ScriptBlock $ListItems } } }
}
function New-HTMLListItem {
    [CmdletBinding()]
    param([string[]] $Text,
        [RGBColors[]] $Color = @(),
        [RGBColors[]] $BackGroundColor = @(),
        [int[]] $FontSize = @(),
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string[]] $FontWeight = @(),
        [ValidateSet('normal', 'italic', 'oblique')][string[]] $FontStyle = @(),
        [ValidateSet('normal', 'small-caps')][string[]] $FontVariant = @(),
        [string[]] $FontFamily = @(),
        [ValidateSet('left', 'center', 'right', 'justify')][string[]] $Alignment = @(),
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string[]] $TextDecoration = @(),
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string[]] $TextTransform = @(),
        [ValidateSet('rtl')][string[]] $Direction = @(),
        [switch] $LineBreak)
    $newHTMLTextSplat = @{Alignment = $Alignment
        FontSize                    = $FontSize
        TextTransform               = $TextTransform
        Text                        = $Text
        Color                       = $Color
        FontFamily                  = $FontFamily
        Direction                   = $Direction
        FontStyle                   = $FontStyle
        TextDecoration              = $TextDecoration
        BackGroundColor             = $BackGroundColor
        FontVariant                 = $FontVariant
        FontWeight                  = $FontWeight
        LineBreak                   = $LineBreak
    }
    if (($FontSize.Count -eq 0) -or ($FontSize -eq 0)) { $Size = '' } else { $size = "$($FontSize)px" }
    $Style = @{style = @{'color' = ConvertFrom-Color -Color $Color
            'background-color'   = ConvertFrom-Color -Color $BackGroundColor
            'font-size'          = $Size
            'font-weight'        = $FontWeight
            'font-variant'       = $FontVariant
            'font-family'        = $FontFamily
            'font-style'         = $FontStyle
            'text-align'         = $Alignment
            'text-decoration'    = $TextDecoration
            'text-transform'     = $TextTransform
            'direction'          = $Direction
        }
    }
    New-HTMLTag -Tag 'li' -Attributes $Style -Value { New-HTMLText @newHTMLTextSplat -SkipParagraph }
}
function New-HTMLLogo {
    param([String] $LogoPath,
        [string] $LeftLogoName = "Sample",
        [string] $RightLogoName = "Alternate",
        [string] $LeftLogoString,
        [string] $RightLogoString,
        [switch] $HideLogos)
    $LogoSources = Get-HTMLLogos -RightLogoName $RightLogoName -LeftLogoName $LeftLogoName -LeftLogoString $LeftLogoString -RightLogoString $RightLogoString
    Convert-StyleContent1 -Options $Options
    $Options = [PSCustomObject] @{Logos = $LogoSources
        ColorSchemes                    = $ColorSchemes
    }
    if ($HideLogos -eq $false) {
        $Leftlogo = $Options.Logos[$LeftLogoName]
        $Rightlogo = $Options.Logos[$RightLogoName]
        '<!-- START LOGO -->'
        $LogoContent = @"
        <table><tbody>
        <tr>
            <td class="clientlogo"><img src="$Leftlogo" /></td>
            <td class="MainLogo"><img src="$Rightlogo" /></td>
        </tr>
        </tbody></table>
"@

        $LogoContent
        '<!-- END LOGO -->'
    }
}
function New-HTMLMessage {
    param([Parameter(Mandatory = $false, Position = 0)][alias('')][ScriptBlock] $Content,
        $Text)
    $Script:HTMLSchema.Features.Message = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'message green' } { New-HTMLTag -Tag 'div' -Attributes @{class = 'message-icon' } { New-HTMLTag -Tag 'i' -Attributes @{class = 'fa fa-bell-o' } }
        New-HTMLTag -Tag 'div' -Attributes @{class = 'message-body' } { New-HTMLTag -Tag 'p' -Attributes @{class = '' } { $Text } } }
}
Function New-HTMLPanel {
    [alias('New-HTMLColumn')]
    [CmdletBinding()]
    param ([Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace with Content"),
        [alias('BackgroundShade')][RGBColors]$BackgroundColor = [RGBColors]::None,
        [switch] $Invisible)
    if ($BackgroundColor -ne [RGBColors]::None) {
        $BackGroundColorFromRGB = ConvertFrom-Color -Color $BackgroundColor
        $DivColumnStyle = "background-color:$BackGroundColorFromRGB;"
    } else { $DivColumnStyle = "" }
    if ($Invisible) { $DivColumnStyle = "$DivColumnStyle box-shadow: unset !important;" }
    New-HTMLTag -Tag 'div' -Attributes @{class = "defaultPanel defaultCard"; style = $DivColumnStyle } { Invoke-Command -ScriptBlock $Content }
}
function New-HTMLResourceCSS {
    [alias('New-ResourceCSS', 'New-CSS')]
    [CmdletBinding()]
    param([alias('ScriptContent')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content,
        [string] $Link,
        [string] $ResourceComment,
        [string[]] $FilePath,
        [System.Collections.IDictionary] $ReplaceData)
    $Output = @("<!-- CSS $ResourceComment START -->"
        foreach ($File in $FilePath) {
            if ($File -ne '') {
                if (Test-Path -LiteralPath $File) { New-HTMLTag -Tag 'style' -Attributes @{type = 'text/css' } { Write-Verbose "New-HTMLResourceCSS - Reading file from $File"
                        $FileContent = Get-Content -LiteralPath $File
                        if ($null -ne $ReplaceData) { foreach ($_ in $ReplaceData.Keys) { $FileContent = $FileContent -replace $_, $ReplaceData[$_] } }
                        $FileContent }
                }
            }
        }
        foreach ($L in $Link) {
            if ($L -ne '') {
                Write-Verbose "New-HTMLResourceCSS - Adding link $L"
                New-HTMLTag -Tag 'link' -Attributes @{rel = "stylesheet"; type = "text/css"; href = $L } -SelfClosing
            }
        }
        "<!-- CSS $ResourceComment END -->")
    if ($Output.Count -gt 2) { $Output }
}
function New-HTMLResourceJS {
    [alias('New-ResourceJS', 'New-JavaScript')]
    [CmdletBinding()]
    param([alias('ScriptContent')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content,
        [string[]] $Link,
        [string] $ResourceComment,
        [string[]] $FilePath,
        [System.Collections.IDictionary] $ReplaceData)
    $Output = @("<!-- JS $ResourceComment START -->"
        foreach ($File in $FilePath) {
            if ($File -ne '') {
                if (Test-Path -LiteralPath $File) { New-HTMLTag -Tag 'script' -Attributes @{type = 'text/javascript' } { $FileContent = Get-Content -LiteralPath $File
                        if ($null -ne $ReplaceData) { foreach ($_ in $ReplaceData.Keys) { $FileContent = $FileContent -replace $_, $ReplaceData[$_] } }
                        $FileContent }
                } else { return }
            }
        }
        foreach ($L in $Link) { if ($L -ne '') { New-HTMLTag -Tag 'script' -Attributes @{type = "text/javascript"; src = $L } } else { return }
        }
        "<!-- JS $ResourceComment END -->")
    if ($Output.Count -gt 2) { $Output }
}
Function New-HTMLSection {
    [alias('New-HTMLContent')]
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace"),
        [alias('Name')][Parameter(Mandatory = $false)][string]$HeaderText,
        [RGBColors]$HeaderTextColor = [RGBColors]::White,
        [string][ValidateSet('center', 'left', 'right', 'justify')] $HeaderTextAlignment = 'center',
        [RGBColors]$HeaderBackGroundColor = [RGBColors]::DeepSkyBlue,
        [alias('BackgroundShade')][RGBColors]$BackgroundColor = [RGBColors]::None,
        [alias('Collapsable')][Parameter(Mandatory = $false)][switch] $CanCollapse,
        [Parameter(Mandatory = $false)][switch] $IsHidden,
        [switch] $Collapsed,
        [int] $Height,
        [switch] $Invisible)
    $RandomNumber = Get-Random
    $TextHeaderColorFromRGB = ConvertFrom-Color -Color $HeaderTextColor
    if ($CanCollapse) {
        $Script:HTMLSchema.Features.HideSection = $true
        if ($IsHidden) {
            $ShowStyle = "color: $TextHeaderColorFromRGB;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        } else {
            if ($Collapsed) {
                $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
                $ShowStyle = "color: $TextHeaderColorFromRGB;"
                $HiddenDivStyle = 'display:none;'
            } else {
                $ShowStyle = "color: $TextHeaderColorFromRGB; display:none;"
                $HideStyle = "color: $TextHeaderColorFromRGB;"
            }
        }
    } else {
        if ($IsHidden) {
            $ShowStyle = "color: $TextHeaderColorFromRGB;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        } else {
            $ShowStyle = "color: $TextHeaderColorFromRGB; display:none;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        }
    }
    if ($IsHidden) {
        $DivContentStyle = @{"display" = 'none'
            "height"                   = if ($Height -ne 0) { "height: $($Height)px" } else { '' }
            "background-color"         = ConvertFrom-Color -Color $BackgroundColor
        }
    } else {
        $DivContentStyle = @{"height" = if ($Height -ne 0) { "height: $($Height)px" } else { '' }
            "background-color"        = ConvertFrom-Color -Color $BackgroundColor
        }
    }
    $DivHeaderStyle = @{"text-align" = $HeaderTextAlignment
        "background-color"           = ConvertFrom-Color -Color $HeaderBackGroundColor
    }
    $HeaderStyle = "color: $TextHeaderColorFromRGB;"
    if ($Invisible) { New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther' } -Value { New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther defaultPanelOther' } -Value { $Object = Invoke-Command -ScriptBlock $Content
                if ($null -ne $Object) { $Object } } }
    } else { New-HTMLTag -Tag 'div' -Attributes @{'class' = "defaultSection defaultCard"; 'style' = $DivContentStyle } -Value { New-HTMLTag -Tag 'div' -Attributes @{'class' = "defaultHeader"; 'style' = $DivHeaderStyle } -Value { New-HTMLAnchor -Name $HeaderText -Text $HeaderText -Style $HeaderStyle
                New-HTMLAnchor -Id "show_$RandomNumber" -Href 'javascript:void(0)' -OnClick "show('$RandomNumber');" -Style $ShowStyle -Text '(Show)'
                New-HTMLAnchor -Id "hide_$RandomNumber" -Href 'javascript:void(0)' -OnClick "hide('$RandomNumber');" -Style $HideStyle -Text '(Hide)' }
            New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther'; id = $RandomNumber; Style = $HiddenDivStyle } -Value { New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainer defaultPanelOther collapsable'; id = $RandomNumber } -Value { $Object = Invoke-Command -ScriptBlock $Content
                    if ($null -ne $Object) { $Object } } } }
    }
}
function New-HTMLSection1 {
    param([ScriptBlock] $Content,
        [string] $TextHeader)
    $ID = "AS-$(Get-RandomStringName -Size 8 -LettersOnly)"
    New-HTMLTag -Tag 'div' -Attributes @{id = 'aspect-content' } { New-HTMLTag -Tag 'div' -Attributes @{class = 'aspect-tab' } { New-HTMLTag -Tag 'input' -Attributes @{id = $ID; type = "checkbox"; class = "aspect-input"; name = "aspect" } -SelfClosing
            New-HTMLTag -Tag 'label' -Attributes @{for = $ID; class = "aspect-label" }
            New-HTMLTag -Tag 'div' -Attributes @{class = "aspect-content" } { New-HTMLTag -Tag 'div' -Attributes @{class = "aspect-info" } { New-HTMLTag -Tag 'div' -Attributes @{class = 'aspect-name' } { $TextHeader } }
                New-HTMLTag -Tag 'div' -Attributes @{class = "aspect-stat" } { New-HTMLSectionHeader -Text '14' -Type positive-count
                    New-HTMLSectionHeader -Text '12' -Type neutral-count } }
            New-HTMLTag -Tag 'div' -Attributes @{class = "aspect-tab-content" } { New-HTMLTag -Tag 'div' -Attributes @{class = "sentiment-wrapper" } { if ($null -ne $Content) { & $Content } } } } }
}
function New-HTMLSubSection {
    param([ScriptBlock] $Content,
        [string] $Text,
        [string[]] $TextHeader,
        [ValidateSet('positive', 'negative', 'neutral')][string] $Type = 'positive')
    New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultPanel defaultCar' } { New-HTMLTag -Tag 'div' { New-HTMLTag -Tag 'div' -Attributes @{class = "$Type-count opinion-header" } { New-HTMLText -Text $TextHeader }
            New-HTMLTag -Tag 'div' { if ($null -ne $Content) { & $Content } } } }
}
function New-HTMLSectionHeader {
    param([ValidateSet('all-opinions', 'positive-count', 'neutral-count', 'negative-count')][string] $Type,
        [string] $Text)
    New-HTMLTag -Tag 'span' -Attributes @{class = $Type } { $Text }
}
function New-HTMLSpanStyle {
    [CmdletBinding()]
    param([ScriptBlock] $Content,
        [nullable[RGBColors]] $Color,
        [nullable[RGBColors]] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $LineBreak)
    Write-Verbose 'New-SpanStyle - BEGIN'
    if ($FontSize -eq 0) { $Size = '' } else { $size = "$($FontSize)px" }
    $Style = @{style = @{'color' = ConvertFrom-Color -Color $Color
            'background-color'   = ConvertFrom-Color -Color $BackGroundColor
            'font-size'          = $Size
            'font-weight'        = $FontWeight
            'font-variant'       = $FontVariant
            'font-family'        = $FontFamily
            'font-style'         = $FontStyle
            'text-align'         = $Alignment
            'text-decoration'    = $TextDecoration
            'text-transform'     = $TextTransform
            'direction'          = $Direction
        }
    }
    if ($Alignment) { $StyleDiv = @{ }
        $StyleDiv.Align = $Alignment
        New-HTMLTag -Tag 'div' -Attributes $StyleDiv { New-HTMLTag -Tag 'span' -Attributes $Style { Invoke-Command -ScriptBlock $Content } }
    } else { New-HTMLTag -Tag 'span' -Attributes $Style { Invoke-Command -ScriptBlock $Content } }
}
function New-HTMLStatus {
    param([Parameter(Mandatory = $false, Position = 0)][alias('')][ScriptBlock] $Content)
    $Script:HTMLSchema.Features.StatusButtonical = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'buttonicalService' } { Invoke-Command -ScriptBlock $Content }
}
function New-HTMLStatusItem {
    param($ServiceName,
        $ServiceStatus,
        [ValidateSet('Dead', 'Bad', 'Good')]$Icon = 'Good',
        [ValidateSet('0%', '10%', '30%', '70%', '100%')][string] $Percentage = '100%')
    if ($Icon -eq 'Dead') { $IconType = 'performanceDead' } elseif ($Icon -eq 'Bad') { $IconType = 'performanceProblem' } elseif ($Icon -eq 'Good') { }
    if ($Percentage -eq '100%') { $Colors = 'background-color: #0ef49b;' } elseif ($Percentage -eq '70%') { $Colors = 'background-color: #d2dc69;' } elseif ($Percentage -eq '30%') { $Colors = 'background-color: #faa04b;' } elseif ($Percentage -eq '10%') { $Colors = 'background-color: #ff9035;' } elseif ($Percentage -eq '0%') { $Colors = 'background-color: #ff5a64;' }
    New-HTMLTag -Tag 'div' -Attributes @{class = 'buttonical'; style = $Colors } -Value { New-HTMLTag -Tag 'div' -Attributes @{class = 'label' } { New-HTMLTag -Tag 'span' -Attributes @{class = 'performance' } { $ServiceName } }
        New-HTMLTag -Tag 'div' -Attributes @{class = 'middle' }
        New-HTMLTag -Tag 'div' -Attributes @{class = 'status' } { New-HTMLTag -Tag 'input' -Attributes @{name = Get-Random; type = 'radio'; value = 'other-item'; checked = 'true' } -SelfClosing
            New-HTMLTag -Tag 'span' -Attributes @{class = "performance $IconType" } { $ServiceStatus } } }
}
function New-HTMLTab {
    [CmdLetBinding(DefaultParameterSetName = 'FontAwesomeBrands')]
    param([parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")]
        [Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $HtmlData = $(Throw "No curly brace?)"),
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")]
        [alias('TabHeading')][Parameter(Mandatory = $false, Position = 1)][String]$Heading,
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")]
        [alias('TabName')][string] $Name = 'Tab',
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [ValidateSet('500px',
            'accessible-icon',
            'accusoft',
            'acquisitions-incorporated',
            'adn',
            'adobe',
            'adversal',
            'affiliatetheme',
            'airbnb',
            'algolia',
            'alipay',
            'amazon',
            'amazon-pay',
            'amilia',
            'android',
            'angellist',
            'angrycreative',
            'angular',
            'app-store',
            'app-store-ios',
            'apper',
            'apple',
            'apple-pay',
            'artstation',
            'asymmetrik',
            'atlassian',
            'audible',
            'autoprefixer',
            'avianex',
            'aviato',
            'aws',
            'bandcamp',
            'battle-net',
            'behance',
            'behance-square',
            'bimobject',
            'bitbucket',
            'bitcoin',
            'bity',
            'black-tie',
            'blackberry',
            'blogger',
            'blogger-b',
            'bluetooth',
            'bluetooth-b',
            'bootstrap',
            'btc',
            'buffer',
            'buromobelexperte',
            'buysellads',
            'canadian-maple-leaf',
            'cc-amazon-pay',
            'cc-amex',
            'cc-apple-pay',
            'cc-diners-club',
            'cc-discover',
            'cc-jcb',
            'cc-mastercard',
            'cc-paypal',
            'cc-stripe',
            'cc-visa',
            'centercode',
            'centos',
            'chrome',
            'chromecast',
            'cloudscale',
            'cloudsmith',
            'cloudversify',
            'codepen',
            'codiepie',
            'confluence',
            'connectdevelop',
            'contao',
            'cpanel',
            'creative-commons',
            'creative-commons-by',
            'creative-commons-nc',
            'creative-commons-nc-eu',
            'creative-commons-nc-jp',
            'creative-commons-nd',
            'creative-commons-pd',
            'creative-commons-pd-alt',
            'creative-commons-remix',
            'creative-commons-sa',
            'creative-commons-sampling',
            'creative-commons-sampling-plus',
            'creative-commons-share',
            'creative-commons-zero',
            'critical-role',
            'css3',
            'css3-alt',
            'cuttlefish',
            'd-and-d',
            'd-and-d-beyond',
            'dashcube',
            'delicious',
            'deploydog',
            'deskpro',
            'dev',
            'deviantart',
            'dhl',
            'diaspora',
            'digg',
            'digital-ocean',
            'discord',
            'discourse',
            'dochub',
            'docker',
            'draft2digital',
            'dribbble',
            'dribbble-square',
            'dropbox',
            'drupal',
            'dyalog',
            'earlybirds',
            'ebay',
            'edge',
            'elementor',
            'ello',
            'ember',
            'empire',
            'envira',
            'erlang',
            'ethereum',
            'etsy',
            'evernote',
            'expeditedssl',
            'facebook',
            'facebook-f',
            'facebook-messenger',
            'facebook-square',
            'fantasy-flight-games',
            'fedex',
            'fedora',
            'figma',
            'firefox',
            'first-order',
            'first-order-alt',
            'firstdraft',
            'flickr',
            'flipboard',
            'fly',
            'font-awesome',
            'font-awesome-alt',
            'font-awesome-flag',
            'fonticons',
            'fonticons-fi',
            'fort-awesome',
            'fort-awesome-alt',
            'forumbee',
            'foursquare',
            'free-code-camp',
            'freebsd',
            'fulcrum',
            'galactic-republic',
            'galactic-senate',
            'get-pocket',
            'gg',
            'gg-circle',
            'git',
            'git-alt',
            'git-square',
            'github',
            'github-alt',
            'github-square',
            'gitkraken',
            'gitlab',
            'gitter',
            'glide',
            'glide-g',
            'gofore',
            'goodreads',
            'goodreads-g',
            'google',
            'google-drive',
            'google-play',
            'google-plus',
            'google-plus-g',
            'google-plus-square',
            'google-wallet',
            'gratipay',
            'grav',
            'gripfire',
            'grunt',
            'gulp',
            'hacker-news',
            'hacker-news-square',
            'hackerrank',
            'hips',
            'hire-a-helper',
            'hooli',
            'hornbill',
            'hotjar',
            'houzz',
            'html5',
            'hubspot',
            'imdb',
            'instagram',
            'intercom',
            'internet-explorer',
            'invision',
            'ioxhost',
            'itch-io',
            'itunes',
            'itunes-note',
            'java',
            'jedi-order',
            'jenkins',
            'jira',
            'joget',
            'joomla',
            'js',
            'js-square',
            'jsfiddle',
            'kaggle',
            'keybase',
            'keycdn',
            'kickstarter',
            'kickstarter-k',
            'korvue',
            'laravel',
            'lastfm',
            'lastfm-square',
            'leanpub',
            'less',
            'line',
            'linkedin',
            'linkedin-in',
            'linode',
            'linux',
            'lyft',
            'magento',
            'mailchimp',
            'mandalorian',
            'markdown',
            'mastodon',
            'maxcdn',
            'medapps',
            'medium',
            'medium-m',
            'medrt',
            'meetup',
            'megaport',
            'mendeley',
            'microsoft',
            'mix',
            'mixcloud',
            'mizuni',
            'modx',
            'monero',
            'napster',
            'neos',
            'nimblr',
            'node',
            'node-js',
            'npm',
            'ns8',
            'nutritionix',
            'odnoklassniki',
            'odnoklassniki-square',
            'old-republic',
            'opencart',
            'openid',
            'opera',
            'optin-monster',
            'osi',
            'page4',
            'pagelines',
            'palfed',
            'patreon',
            'paypal',
            'penny-arcade',
            'periscope',
            'phabricator',
            'phoenix-framework',
            'phoenix-squadron',
            'php',
            'pied-piper',
            'pied-piper-alt',
            'pied-piper-hat',
            'pied-piper-pp',
            'pinterest',
            'pinterest-p',
            'pinterest-square',
            'playstation',
            'product-hunt',
            'pushed',
            'python',
            'qq',
            'quinscape',
            'quora',
            'r-project',
            'raspberry-pi',
            'ravelry',
            'react',
            'reacteurope',
            'readme',
            'rebel',
            'red-river',
            'reddit',
            'reddit-alien',
            'reddit-square',
            'redhat',
            'renren',
            'replyd',
            'researchgate',
            'resolving',
            'rev',
            'rocketchat',
            'rockrms',
            'safari',
            'salesforce',
            'sass',
            'schlix',
            'scribd',
            'searchengin',
            'sellcast',
            'sellsy',
            'servicestack',
            'shirtsinbulk',
            'shopware',
            'simplybuilt',
            'sistrix',
            'sith',
            'sketch',
            'skyatlas',
            'skype',
            'slack',
            'slack-hash',
            'slideshare',
            'snapchat',
            'snapchat-ghost',
            'snapchat-square',
            'soundcloud',
            'sourcetree',
            'speakap',
            'speaker-deck',
            'spotify',
            'squarespace',
            'stack-exchange',
            'stack-overflow',
            'stackpath',
            'staylinked',
            'steam',
            'steam-square',
            'steam-symbol',
            'sticker-mule',
            'strava',
            'stripe',
            'stripe-s',
            'studiovinari',
            'stumbleupon',
            'stumbleupon-circle',
            'superpowers',
            'supple',
            'suse',
            'symfony',
            'teamspeak',
            'telegram',
            'telegram-plane',
            'tencent-weibo',
            'the-red-yeti',
            'themeco',
            'themeisle',
            'think-peaks',
            'trade-federation',
            'trello',
            'tripadvisor',
            'tumblr',
            'tumblr-square',
            'twitch',
            'twitter',
            'twitter-square',
            'typo3',
            'uber',
            'ubuntu',
            'uikit',
            'uniregistry',
            'untappd',
            'ups',
            'usb',
            'usps',
            'ussunnah',
            'vaadin',
            'viacoin',
            'viadeo',
            'viadeo-square',
            'viber',
            'vimeo',
            'vimeo-square',
            'vimeo-v',
            'vine',
            'vk',
            'vnv',
            'vuejs',
            'waze',
            'weebly',
            'weibo',
            'weixin',
            'whatsapp',
            'whatsapp-square',
            'whmcs',
            'wikipedia-w',
            'windows',
            'wix',
            'wizards-of-the-coast',
            'wolf-pack-battalion',
            'wordpress',
            'wordpress-simple',
            'wpbeginner',
            'wpexplorer',
            'wpforms',
            'wpressr',
            'xbox',
            'xing',
            'xing-square',
            'y-combinator',
            'yahoo',
            'yammer',
            'yandex',
            'yandex-international',
            'yarn',
            'yelp',
            'yoast',
            'youtube',
            'youtube-square',
            'zhihu')][string] $IconBrands,
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [ValidateSet('address-book',
            'address-card',
            'angry',
            'arrow-alt-circle-down',
            'arrow-alt-circle-left',
            'arrow-alt-circle-right',
            'arrow-alt-circle-up',
            'bell',
            'bell-slash',
            'bookmark',
            'building',
            'calendar',
            'calendar-alt',
            'calendar-check',
            'calendar-minus',
            'calendar-plus',
            'calendar-times',
            'caret-square-down',
            'caret-square-left',
            'caret-square-right',
            'caret-square-up',
            'chart-bar',
            'check-circle',
            'check-square',
            'circle',
            'clipboard',
            'clock',
            'clone',
            'closed-captioning',
            'comment',
            'comment-alt',
            'comment-dots',
            'comments',
            'compass',
            'copy',
            'copyright',
            'credit-card',
            'dizzy',
            'dot-circle',
            'edit',
            'envelope',
            'envelope-open',
            'eye',
            'eye-slash',
            'file',
            'file-alt',
            'file-archive',
            'file-audio',
            'file-code',
            'file-excel',
            'file-image',
            'file-pdf',
            'file-powerpoint',
            'file-video',
            'file-word',
            'flag',
            'flushed',
            'folder',
            'folder-open',
            'frown',
            'frown-open',
            'futbol',
            'gem',
            'grimace',
            'grin',
            'grin-alt',
            'grin-beam',
            'grin-beam-sweat',
            'grin-hearts',
            'grin-squint',
            'grin-squint-tears',
            'grin-stars',
            'grin-tears',
            'grin-tongue',
            'grin-tongue-squint',
            'grin-tongue-wink',
            'grin-wink',
            'hand-lizard',
            'hand-paper',
            'hand-peace',
            'hand-point-down',
            'hand-point-left',
            'hand-point-right',
            'hand-point-up',
            'hand-pointer',
            'hand-rock',
            'hand-scissors',
            'hand-spock',
            'handshake',
            'hdd',
            'heart',
            'hospital',
            'hourglass',
            'id-badge',
            'id-card',
            'image',
            'images',
            'keyboard',
            'kiss',
            'kiss-beam',
            'kiss-wink-heart',
            'laugh',
            'laugh-beam',
            'laugh-squint',
            'laugh-wink',
            'lemon',
            'life-ring',
            'lightbulb',
            'list-alt',
            'map',
            'meh',
            'meh-blank',
            'meh-rolling-eyes',
            'minus-square',
            'money-bill-alt',
            'moon',
            'newspaper',
            'object-group',
            'object-ungroup',
            'paper-plane',
            'pause-circle',
            'play-circle',
            'plus-square',
            'question-circle',
            'registered',
            'sad-cry',
            'sad-tear',
            'save',
            'share-square',
            'smile',
            'smile-beam',
            'smile-wink',
            'snowflake',
            'square',
            'star',
            'star-half',
            'sticky-note',
            'stop-circle',
            'sun',
            'surprise',
            'thumbs-down',
            'thumbs-up',
            'times-circle',
            'tired',
            'trash-alt',
            'user',
            'user-circle',
            'window-close',
            'window-maximize',
            'window-minimize',
            'window-restore')][string] $IconRegular,
        [parameter(ParameterSetName = "FontAwesomeSolid")]
        [ValidateSet('address-card',
            'adjust',
            'air-freshener',
            'align-center',
            'align-justify',
            'align-left',
            'align-right',
            'allergies',
            'ambulance',
            'american-sign-language-interpreting',
            'anchor',
            'angle-double-down',
            'angle-double-left',
            'angle-double-right',
            'angle-double-up',
            'angle-down',
            'angle-left',
            'angle-right',
            'angle-up',
            'angry',
            'ankh',
            'apple-alt',
            'archive',
            'archway',
            'arrow-alt-circle-down',
            'arrow-alt-circle-left',
            'arrow-alt-circle-right',
            'arrow-alt-circle-up',
            'arrow-circle-down',
            'arrow-circle-left',
            'arrow-circle-right',
            'arrow-circle-up',
            'arrow-down',
            'arrow-left',
            'arrow-right',
            'arrow-up',
            'arrows-alt',
            'arrows-alt-h',
            'arrows-alt-v',
            'assistive-listening-systems',
            'asterisk',
            'at',
            'atlas',
            'atom',
            'audio-description',
            'award',
            'baby',
            'baby-carriage',
            'backspace',
            'backward',
            'bacon',
            'balance-scale',
            'balance-scale-left',
            'balance-scale-right',
            'ban',
            'band-aid',
            'barcode',
            'bars',
            'baseball-ball',
            'basketball-ball',
            'bath',
            'battery-empty',
            'battery-full',
            'battery-half',
            'battery-quarter',
            'battery-three-quarters',
            'bed',
            'beer',
            'bell',
            'bell-slash',
            'bezier-curve',
            'bible',
            'bicycle',
            'biking',
            'binoculars',
            'biohazard',
            'birthday-cake',
            'blender',
            'blender-phone',
            'blind',
            'blog',
            'bold',
            'bolt',
            'bomb',
            'bone',
            'bong',
            'book',
            'book-dead',
            'book-medical',
            'book-open',
            'book-reader',
            'bookmark',
            'border-all',
            'border-none',
            'border-style',
            'bowling-ball',
            'box',
            'box-open',
            'boxes',
            'braille',
            'brain',
            'bread-slice',
            'briefcase',
            'briefcase-medical',
            'broadcast-tower',
            'broom',
            'brush',
            'bug',
            'building',
            'bullhorn',
            'bullseye',
            'burn',
            'bus',
            'bus-alt',
            'business-time',
            'calculator',
            'calendar',
            'calendar-alt',
            'calendar-check',
            'calendar-day',
            'calendar-minus',
            'calendar-plus',
            'calendar-times',
            'calendar-week',
            'camera',
            'camera-retro',
            'campground',
            'candy-cane',
            'cannabis',
            'capsules',
            'car',
            'car-alt',
            'car-battery',
            'car-crash',
            'car-side',
            'caret-down',
            'caret-left',
            'caret-right',
            'caret-square-down',
            'caret-square-left',
            'caret-square-right',
            'caret-square-up',
            'caret-up',
            'carrot',
            'cart-arrow-down',
            'cart-plus',
            'cash-register',
            'cat',
            'certificate',
            'chair',
            'chalkboard',
            'chalkboard-teacher',
            'charging-station',
            'chart-area',
            'chart-bar',
            'chart-line',
            'chart-pie',
            'check',
            'check-circle',
            'check-double',
            'check-square',
            'cheese',
            'chess',
            'chess-bishop',
            'chess-board',
            'chess-king',
            'chess-knight',
            'chess-pawn',
            'chess-queen',
            'chess-rook',
            'chevron-circle-down',
            'chevron-circle-left',
            'chevron-circle-right',
            'chevron-circle-up',
            'chevron-down',
            'chevron-left',
            'chevron-right',
            'chevron-up',
            'child',
            'church',
            'circle',
            'circle-notch',
            'city',
            'clinic-medical',
            'clipboard',
            'clipboard-check',
            'clipboard-list',
            'clock',
            'clone',
            'closed-captioning',
            'cloud',
            'cloud-download-alt',
            'cloud-meatball',
            'cloud-moon',
            'cloud-moon-rain',
            'cloud-rain',
            'cloud-showers-heavy',
            'cloud-sun',
            'cloud-sun-rain',
            'cloud-upload-alt',
            'cocktail',
            'code',
            'code-branch',
            'coffee',
            'cog',
            'cogs',
            'coins',
            'columns',
            'comment',
            'comment-alt',
            'comment-dollar',
            'comment-dots',
            'comment-medical',
            'comment-slash',
            'comments',
            'comments-dollar',
            'compact-disc',
            'compass',
            'compress',
            'compress-arrows-alt',
            'concierge-bell',
            'cookie',
            'cookie-bite',
            'copy',
            'copyright',
            'couch',
            'credit-card',
            'crop',
            'crop-alt',
            'cross',
            'crosshairs',
            'crow',
            'crown',
            'crutch',
            'cube',
            'cubes',
            'cut',
            'database',
            'deaf',
            'democrat',
            'desktop',
            'dharmachakra',
            'diagnoses',
            'dice',
            'dice-d20',
            'dice-d6',
            'dice-five',
            'dice-four',
            'dice-one',
            'dice-six',
            'dice-three',
            'dice-two',
            'digital-tachograph',
            'directions',
            'divide',
            'dizzy',
            'dna',
            'dog',
            'dollar-sign',
            'dolly',
            'dolly-flatbed',
            'donate',
            'door-closed',
            'door-open',
            'dot-circle',
            'dove',
            'download',
            'drafting-compass',
            'dragon',
            'draw-polygon',
            'drum',
            'drum-steelpan',
            'drumstick-bite',
            'dumbbell',
            'dumpster',
            'dumpster-fire',
            'dungeon',
            'edit',
            'egg',
            'eject',
            'ellipsis-h',
            'ellipsis-v',
            'envelope',
            'envelope-open',
            'envelope-open-text',
            'envelope-square',
            'equals',
            'eraser',
            'ethernet',
            'euro-sign',
            'exchange-alt',
            'exclamation',
            'exclamation-circle',
            'exclamation-triangle',
            'expand',
            'expand-arrows-alt',
            'external-link-alt',
            'external-link-square-alt',
            'eye',
            'eye-dropper',
            'eye-slash',
            'fan',
            'fast-backward',
            'fast-forward',
            'fax',
            'feather',
            'feather-alt',
            'female',
            'fighter-jet',
            'file',
            'file-alt',
            'file-archive',
            'file-audio',
            'file-code',
            'file-contract',
            'file-csv',
            'file-download',
            'file-excel',
            'file-export',
            'file-image',
            'file-import',
            'file-invoice',
            'file-invoice-dollar',
            'file-medical',
            'file-medical-alt',
            'file-pdf',
            'file-powerpoint',
            'file-prescription',
            'file-signature',
            'file-upload',
            'file-video',
            'file-word',
            'fill',
            'fill-drip',
            'film',
            'filter',
            'fingerprint',
            'fire',
            'fire-alt',
            'fire-extinguisher',
            'first-aid',
            'fish',
            'fist-raised',
            'flag',
            'flag-checkered',
            'flag-usa',
            'flask',
            'flushed',
            'folder',
            'folder-minus',
            'folder-open',
            'folder-plus',
            'font',
            'football-ball',
            'forward',
            'frog',
            'frown',
            'frown-open',
            'funnel-dollar',
            'futbol',
            'gamepad',
            'gas-pump',
            'gavel',
            'gem',
            'genderless',
            'ghost',
            'gift',
            'gifts',
            'glass-cheers',
            'glass-martini',
            'glass-martini-alt',
            'glass-whiskey',
            'glasses',
            'globe',
            'globe-africa',
            'globe-americas',
            'globe-asia',
            'globe-europe',
            'golf-ball',
            'gopuram',
            'graduation-cap',
            'greater-than',
            'greater-than-equal',
            'grimace',
            'grin',
            'grin-alt',
            'grin-beam',
            'grin-beam-sweat',
            'grin-hearts',
            'grin-squint',
            'grin-squint-tears',
            'grin-stars',
            'grin-tears',
            'grin-tongue',
            'grin-tongue-squint',
            'grin-tongue-wink',
            'grin-wink',
            'grip-horizontal',
            'grip-lines',
            'grip-lines-vertical',
            'grip-vertical',
            'guitar',
            'h-square',
            'hamburger',
            'hammer',
            'hamsa',
            'hand-holding',
            'hand-holding-heart',
            'hand-holding-usd',
            'hand-lizard',
            'hand-middle-finger',
            'hand-paper',
            'hand-peace',
            'hand-point-down',
            'hand-point-left',
            'hand-point-right',
            'hand-point-up',
            'hand-pointer',
            'hand-rock',
            'hand-scissors',
            'hand-spock',
            'hands',
            'hands-helping',
            'handshake',
            'hanukiah',
            'hard-hat',
            'hashtag',
            'hat-wizard',
            'haykal',
            'hdd',
            'heading',
            'headphones',
            'headphones-alt',
            'headset',
            'heart',
            'heart-broken',
            'heartbeat',
            'helicopter',
            'highlighter',
            'hiking',
            'hippo',
            'history',
            'hockey-puck',
            'holly-berry',
            'home',
            'horse',
            'horse-head',
            'hospital',
            'hospital-alt',
            'hospital-symbol',
            'hot-tub',
            'hotdog',
            'hotel',
            'hourglass',
            'hourglass-end',
            'hourglass-half',
            'hourglass-start',
            'house-damage',
            'hryvnia',
            'i-cursor',
            'ice-cream',
            'icicles',
            'icons',
            'id-badge',
            'id-card',
            'id-card-alt',
            'igloo',
            'image',
            'images',
            'inbox',
            'indent',
            'industry',
            'infinity',
            'info',
            'info-circle',
            'italic',
            'jedi',
            'joint',
            'journal-whills',
            'kaaba',
            'key',
            'keyboard',
            'khanda',
            'kiss',
            'kiss-beam',
            'kiss-wink-heart',
            'kiwi-bird',
            'landmark',
            'language',
            'laptop',
            'laptop-code',
            'laptop-medical',
            'laugh',
            'laugh-beam',
            'laugh-squint',
            'laugh-wink',
            'layer-group',
            'leaf',
            'lemon',
            'less-than',
            'less-than-equal',
            'level-down-alt',
            'level-up-alt',
            'life-ring',
            'lightbulb',
            'link',
            'lira-sign',
            'list',
            'list-alt',
            'list-ol',
            'list-ul',
            'location-arrow',
            'lock',
            'lock-open',
            'long-arrow-alt-down',
            'long-arrow-alt-left',
            'long-arrow-alt-right',
            'long-arrow-alt-up',
            'low-vision',
            'luggage-cart',
            'magic',
            'magnet',
            'mail-bulk',
            'male',
            'map',
            'map-marked',
            'map-marked-alt',
            'map-marker',
            'map-marker-alt',
            'map-pin',
            'map-signs',
            'marker',
            'mars',
            'mars-double',
            'mars-stroke',
            'mars-stroke-h',
            'mars-stroke-v',
            'mask',
            'medal',
            'medkit',
            'meh',
            'meh-blank',
            'meh-rolling-eyes',
            'memory',
            'menorah',
            'mercury',
            'meteor',
            'microchip',
            'microphone',
            'microphone-alt',
            'microphone-alt-slash',
            'microphone-slash',
            'microscope',
            'minus',
            'minus-circle',
            'minus-square',
            'mitten',
            'mobile',
            'mobile-alt',
            'money-bill',
            'money-bill-alt',
            'money-bill-wave',
            'money-bill-wave-alt',
            'money-check',
            'money-check-alt',
            'monument',
            'moon',
            'mortar-pestle',
            'mosque',
            'motorcycle',
            'mountain',
            'mouse-pointer',
            'mug-hot',
            'music',
            'network-wired',
            'neuter',
            'newspaper',
            'not-equal',
            'notes-medical',
            'object-group',
            'object-ungroup',
            'oil-can',
            'om',
            'otter',
            'outdent',
            'pager',
            'paint-brush',
            'paint-roller',
            'palette',
            'pallet',
            'paper-plane',
            'paperclip',
            'parachute-box',
            'paragraph',
            'parking',
            'passport',
            'pastafarianism',
            'paste',
            'pause',
            'pause-circle',
            'paw',
            'peace',
            'pen',
            'pen-alt',
            'pen-fancy',
            'pen-nib',
            'pen-square',
            'pencil-alt',
            'pencil-ruler',
            'people-carry',
            'pepper-hot',
            'percent',
            'percentage',
            'person-booth',
            'phone',
            'phone-alt',
            'phone-slash',
            'phone-square',
            'phone-square-alt',
            'phone-volume',
            'photo-video',
            'piggy-bank',
            'pills',
            'pizza-slice',
            'place-of-worship',
            'plane',
            'plane-arrival',
            'plane-departure',
            'play',
            'play-circle',
            'plug',
            'plus',
            'plus-circle',
            'plus-square',
            'podcast',
            'poll',
            'poll-h',
            'poo',
            'poo-storm',
            'poop',
            'portrait',
            'pound-sign',
            'power-off',
            'pray',
            'praying-hands',
            'prescription',
            'prescription-bottle',
            'prescription-bottle-alt',
            'print',
            'procedures',
            'project-diagram',
            'puzzle-piece',
            'qrcode',
            'question',
            'question-circle',
            'quidditch',
            'quote-left',
            'quote-right',
            'quran',
            'radiation',
            'radiation-alt',
            'rainbow',
            'random',
            'receipt',
            'recycle',
            'redo',
            'redo-alt',
            'registered',
            'remove-format',
            'reply',
            'reply-all',
            'republican',
            'restroom',
            'retweet',
            'ribbon',
            'ring',
            'road',
            'robot',
            'rocket',
            'route',
            'rss',
            'rss-square',
            'ruble-sign',
            'ruler',
            'ruler-combined',
            'ruler-horizontal',
            'ruler-vertical',
            'running',
            'rupee-sign',
            'sad-cry',
            'sad-tear',
            'satellite',
            'satellite-dish',
            'save',
            'school',
            'screwdriver',
            'scroll',
            'sd-card',
            'search',
            'search-dollar',
            'search-location',
            'search-minus',
            'search-plus',
            'seedling',
            'server',
            'shapes',
            'share',
            'share-alt',
            'share-alt-square',
            'share-square',
            'shekel-sign',
            'shield-alt',
            'ship',
            'shipping-fast',
            'shoe-prints',
            'shopping-bag',
            'shopping-basket',
            'shopping-cart',
            'shower',
            'shuttle-van',
            'sign',
            'sign-in-alt',
            'sign-language',
            'sign-out-alt',
            'signal',
            'signature',
            'sim-card',
            'sitemap',
            'skating',
            'skiing',
            'skiing-nordic',
            'skull',
            'skull-crossbones',
            'slash',
            'sleigh',
            'sliders-h',
            'smile',
            'smile-beam',
            'smile-wink',
            'smog',
            'smoking',
            'smoking-ban',
            'sms',
            'snowboarding',
            'snowflake',
            'snowman',
            'snowplow',
            'socks',
            'solar-panel',
            'sort',
            'sort-alpha-down',
            'sort-alpha-down-alt',
            'sort-alpha-up',
            'sort-alpha-up-alt',
            'sort-amount-down',
            'sort-amount-down-alt',
            'sort-amount-up',
            'sort-amount-up-alt',
            'sort-down',
            'sort-numeric-down',
            'sort-numeric-down-alt',
            'sort-numeric-up',
            'sort-numeric-up-alt',
            'sort-up',
            'spa',
            'space-shuttle',
            'spell-check',
            'spider',
            'spinner',
            'splotch',
            'spray-can',
            'square',
            'square-full',
            'square-root-alt',
            'stamp',
            'star',
            'star-and-crescent',
            'star-half',
            'star-half-alt',
            'star-of-david',
            'star-of-life',
            'step-backward',
            'step-forward',
            'stethoscope',
            'sticky-note',
            'stop',
            'stop-circle',
            'stopwatch',
            'store',
            'store-alt',
            'stream',
            'street-view',
            'strikethrough',
            'stroopwafel',
            'subscript',
            'subway',
            'suitcase',
            'suitcase-rolling',
            'sun',
            'superscript',
            'surprise',
            'swatchbook',
            'swimmer',
            'swimming-pool',
            'synagogue',
            'sync',
            'sync-alt',
            'syringe',
            'table',
            'table-tennis',
            'tablet',
            'tablet-alt',
            'tablets',
            'tachometer-alt',
            'tag',
            'tags',
            'tape',
            'tasks',
            'taxi',
            'teeth',
            'teeth-open',
            'temperature-high',
            'temperature-low',
            'tenge',
            'terminal',
            'text-height',
            'text-width',
            'th',
            'th-large',
            'th-list',
            'theater-masks',
            'thermometer',
            'thermometer-empty',
            'thermometer-full',
            'thermometer-half',
            'thermometer-quarter',
            'thermometer-three-quarters',
            'thumbs-down',
            'thumbs-up',
            'thumbtack',
            'ticket-alt',
            'times',
            'times-circle',
            'tint',
            'tint-slash',
            'tired',
            'toggle-off',
            'toggle-on',
            'toilet',
            'toilet-paper',
            'toolbox',
            'tools',
            'tooth',
            'torah',
            'torii-gate',
            'tractor',
            'trademark',
            'traffic-light',
            'train',
            'tram',
            'transgender',
            'transgender-alt',
            'trash',
            'trash-alt',
            'trash-restore',
            'trash-restore-alt',
            'tree',
            'trophy',
            'truck',
            'truck-loading',
            'truck-monster',
            'truck-moving',
            'truck-pickup',
            'tshirt',
            'tty',
            'tv',
            'umbrella',
            'umbrella-beach',
            'underline',
            'undo',
            'undo-alt',
            'universal-access',
            'university',
            'unlink',
            'unlock',
            'unlock-alt',
            'upload',
            'user',
            'user-alt',
            'user-alt-slash',
            'user-astronaut',
            'user-check',
            'user-circle',
            'user-clock',
            'user-cog',
            'user-edit',
            'user-friends',
            'user-graduate',
            'user-injured',
            'user-lock',
            'user-md',
            'user-minus',
            'user-ninja',
            'user-nurse',
            'user-plus',
            'user-secret',
            'user-shield',
            'user-slash',
            'user-tag',
            'user-tie',
            'user-times',
            'users',
            'users-cog',
            'utensil-spoon',
            'utensils',
            'vector-square',
            'venus',
            'venus-double',
            'venus-mars',
            'vial',
            'vials',
            'video',
            'video-slash',
            'vihara',
            'voicemail',
            'volleyball-ball',
            'volume-down',
            'volume-mute',
            'volume-off',
            'volume-up',
            'vote-yea',
            'vr-cardboard',
            'walking',
            'wallet',
            'warehouse',
            'water',
            'wave-square',
            'weight',
            'weight-hanging',
            'wheelchair',
            'wifi',
            'wind',
            'window-close',
            'window-maximize',
            'window-minimize',
            'window-restore',
            'wine-bottle',
            'wine-glass',
            'wine-glass-alt',
            'won-sign',
            'wrench',
            'x-ray',
            'yen-sign',
            'yin-yang')][string] $IconSolid,
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")][int] $TextSize,
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")][RGBColors] $TextColor = [RGBColors]::None,
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")][int] $IconSize,
        [parameter(ParameterSetName = "FontAwesomeBrands")]
        [parameter(ParameterSetName = "FontAwesomeRegular")]
        [parameter(ParameterSetName = "FontAwesomeSolid")][RGBColors] $IconColor = [RGBColors]::None)
    if (-not $Script:HTMLSchema.Features) {
        Write-Warning 'New-HTMLTab - Creation of HTML aborted. Most likely New-HTML is missing.'
        Exit
    }
    if ($IconBrands) { $Icon = "fab fa-$IconBrands" } elseif ($IconRegular) { $Icon = "far fa-$IconRegular" } elseif ($IconSolid) { $Icon = "fas fa-$IconSolid" }
    $StyleText = @{ }
    if ($TextSize -ne 0) { $StyleText.'font-size' = "$($TextSize)px" }
    if ($TextColor -ne [RGBColors]::None) { $StyleText.'color' = ConvertFrom-Color -Color $TextColor }
    $StyleIcon = @{ }
    if ($IconSize -ne 0) { $StyleIcon.'font-size' = "$($IconSize)px" }
    if ($IconColor -ne [RGBColors]::None) { $StyleIcon.'color' = ConvertFrom-Color -Color $IconColor }
    $Script:HTMLSchema.Features.Tabs = $true
    $Script:HTMLSchema.Features.JQuery = $true
    foreach ($Tab in $Script:HTMLSchema.TabsHeaders) { $Tab.Current = $false }
    $Tab = @{ }
    $Tab.ID = "Tab-$(Get-RandomStringName -Size 8)"
    $Tab.Name = " $Name"
    $Tab.StyleIcon = $StyleIcon
    $Tab.StyleText = $StyleText
    $Tab.Current = $true
    if ($Script:HTMLSchema.TabsHeaders | Where-Object { $_.Active -eq $true }) { $Tab.Active = $false } else { $Tab.Active = $true }
    $Tab.Icon = $Icon
    $Script:HTMLSchema.TabsHeaders.Add($Tab)
    if ($Tab.Active) { $Class = 'tabs-content active' } else { $Class = 'tabs-content' }
    New-HTMLTag -Tag 'div' -Attributes @{id = $Tab.ID; class = $Class } { if (-not [string]::IsNullOrWhiteSpace($Heading)) { New-HTMLTag -Tag 'h7' { $Heading } }
        Invoke-Command -ScriptBlock $HtmlData }
}
function New-HTMLTabHead {
    [CmdletBinding()]
    Param ()
    if ($Script:HTMLSchema.TabOptions.SlimTabs) { $Style = 'display: inline-block;' } else { $Style = '' }
    New-HTMLTag -Tag 'div' -Attributes @{class = 'tabsWrapper' } { New-HTMLTag -Tag 'div' -Attributes @{class = 'tabs'; style = $Style } { New-HTMLTag -Tag 'div' -Attributes @{class = 'selector' }
            foreach ($Tab in $Script:HTMLSchema.TabsHeaders) {
                $AttributesA = @{'href' = 'javascript:void(0)'
                    'data-id'           = "$($Tab.Id)"
                }
                if ($Tab.Active) { $AttributesA.class = 'active' } else { $AttributesA.class = '' }
                New-HTMLTag -Tag 'a' -Attributes $AttributesA { New-HTMLTag -Tag 'div' -Attributes @{class = $($Tab.Icon); style = $($Tab.StyleIcon) }
                    New-HTMLTag -Tag 'span' -Attributes @{style = $($Tab.StyleText) } -Value { $Tab.Name } }
            } } }
}
function New-HTMLTable {
    [CmdletBinding()]
    param([Parameter(Mandatory = $false, Position = 0)][ScriptBlock] $HTML,
        [Parameter(Mandatory = $false, Position = 1)][ScriptBlock] $PreContent,
        [Parameter(Mandatory = $false, Position = 2)][ScriptBlock] $PostContent,
        [alias('ArrayOfObjects', 'Object', 'Table')][Array] $DataTable,
        [string[]][ValidateSet('copyHtml5', 'excelHtml5', 'csvHtml5', 'pdfHtml5', 'pageLength')] $Buttons = @('copyHtml5', 'excelHtml5', 'csvHtml5', 'pdfHtml5', 'pageLength'),
        [string[]][ValidateSet('numbers', 'simple', 'simple_numbers', 'full', 'full_numbers', 'first_last_numbers')] $PagingStyle = 'full_numbers',
        [int[]]$PagingOptions = @(15, 25, 50, 100),
        [switch]$DisablePaging,
        [switch]$DisableOrdering,
        [switch]$DisableInfo,
        [switch]$HideFooter,
        [switch]$DisableColumnReorder,
        [switch]$DisableProcessing,
        [switch]$DisableResponsiveTable,
        [switch]$DisableSelect,
        [switch]$DisableStateSave,
        [switch]$DisableSearch,
        [switch]$ScrollCollapse,
        [switch]$OrderMulti,
        [switch]$Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom',
        [string[]][ValidateSet('display', 'cell-border', 'compact', 'hover', 'nowrap', 'order-column', 'row-border', 'stripe')] $Style = @('display', 'compact'),
        [switch]$Simplify,
        [string]$TextWhenNoData = 'No data available.',
        [int] $ScreenSizePercent = 0,
        [string[]] $DefaultSortColumn,
        [int[]] $DefaultSortIndex,
        [ValidateSet('Ascending', 'Descending')][string] $DefaultSortOrder = 'Ascending',
        [string[]] $DateTimeSortingFormat,
        [alias('Search')][string]$Find,
        [switch] $InvokeHTMLTags,
        [switch] $DisableNewLine,
        [switch] $ScrollX,
        [switch] $ScrollY,
        [int] $ScrollSizeY = 500,
        [int] $FreezeColumnsLeft,
        [int] $FreezeColumnsRight,
        [switch] $FixedHeader,
        [switch] $FixedFooter,
        [string[]] $ResponsivePriorityOrder,
        [int[]] $ResponsivePriorityOrderIndex)
    if (-not $Script:HTMLSchema.Features) {
        Write-Warning 'New-HTMLTable - Creation of HTML aborted. Most likely New-HTML is missing.'
        Exit
    }
    $ConditionalFormatting = [System.Collections.Generic.List[PSCustomObject]]::new()
    $CustomButtons = [System.Collections.Generic.List[PSCustomObject]]::new()
    $HeaderRows = [System.Collections.Generic.List[PSCustomObject]]::new()
    $HeaderStyle = [System.Collections.Generic.List[PSCustomObject]]::new()
    $HeaderTop = [System.Collections.Generic.List[PSCustomObject]]::new()
    if ($HTML) {
        [Array] $Output = & $HTML
        if ($Output.Count -gt 0) { foreach ($Parameters in $Output) { if ($Parameters.Type -eq 'TableButtonPDF') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonCSV') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonPageLength') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonExcel') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonPDF') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonPrint') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableButtonCopy') { $CustomButtons.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableCondition') { $ConditionalFormatting.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableHeaderMerge') { $HeaderRows.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableHeaderStyle') { $HeaderStyle.Add($Parameters.Output) } elseif ($Parameters.Type -eq 'TableHeaderFullRow') { $HeaderTop.Add($Parameters.Output) } } }
    }
    [string] $DataTableName = "DT-$(Get-RandomStringName -Size 8 -LettersOnly)"
    if ($null -eq $DataTable -or $DataTable.Count -eq 0) { $DataTable = $TextWhenNoData }
    if ($DataTable[0] -is [System.Collections.IDictionary]) {
        Write-Verbose 'New-HTMLTable - Working with IDictionary'
        [Array ] $Table = $($DataTable).GetEnumerator() | Select-Object Name, Value | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    } elseif ($DataTable[0] -is [string]) { [Array] $Table = $DataTable | ForEach-Object { [PSCustomObject]@{'Name' = $_ } } | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    } else {
        Write-Verbose 'New-HTMLTable - Working with Objects'
        [Array] $Table = $DataTable | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    }
    [string] $Header = $Table | Select-Object -First 1
    [string[]] $HeaderNames = $Header -replace '</th></tr>' -replace '<tr><th>' -split '</th><th>'
    $AddedHeader = Add-TableHeader -HeaderRows $HeaderRows -HeaderNames $HeaderNames -HeaderStyle $HeaderStyle -HeaderTop $HeaderTop
    $Table = $Table | Select-Object -Skip 1
    $Options = [ordered] @{dom = 'Bfrtip'
        buttons                = @(if ($CustomButtons) { $CustomButtons } else {
                foreach ($button in $Buttons) { if ($button -ne 'pdfHtml5') { @{extend = $button } } else {
                        @{extend        = 'pdfHtml5'
                            pageSize    = 'A3'
                            orientation = 'landscape'
                        }
                    }
                }
            })
        "colReorder"           = -not $DisableColumnReorder.IsPresent
        "paging"               = -not $DisablePaging
        "scrollCollapse"       = $ScrollCollapse.IsPresent
        "pagingType"           = $PagingStyle
        "lengthMenu"           = @(, @($PagingOptions + (-1))
            , @($PagingOptions + "All"))
        "ordering"             = -not $DisableOrdering.IsPresent
        "order"                = @()
        "info"                 = -not $DisableInfo.IsPresent
        "procesing"            = -not $DisableProcessing.IsPresent
        "select"               = -not $DisableSelect.IsPresent
        "searching"            = -not $DisableSearch.IsPresent
        "stateSave"            = -not $DisableStateSave.IsPresent
    }
    if ($ScrollX) {
        $Options.'scrollX' = $true
        $DisableResponsiveTable = $true
    }
    if ($ScrollY) { $Options.'scrollY' = "$($ScrollSizeY)px" }
    if ($FreezeColumnsLeft -or $FreezeColumnsRight) { $Options.fixedColumns = [ordered] @{ }
        if ($FreezeColumnsLeft) { $Options.fixedColumns.leftColumns = $FreezeColumnsLeft }
        if ($FreezeColumnsRight) { $Options.fixedColumns.rightColumns = $FreezeColumnsRight }
    }
    if ($FixedHeader -or $FixedFooter) { $Options.fixedHeader = [ordered] @{ }
        if ($FixedHeader) { $Options.fixedHeader.header = $FixedHeader.IsPresent }
        if ($FixedFooter) { $Options.fixedHeader.footer = $FixedFooter.IsPresent }
    }
    if (-not $DisableResponsiveTable) { $Options."responsive" = @{details = $true }
    }
    if ($OrderMulti) { $Options.orderMulti = $OrderMulti.IsPresent }
    if ($Find -ne '') { $Options.search = @{search = $Find }
    }
    if ($DefaultSortOrder -eq 'Ascending') { $Sort = 'asc' } else { $Sort = 'desc' }
    if ($DefaultSortColumn.Count -gt 0) {
        $ColumnsOrder = foreach ($Column in $DefaultSortColumn) {
            $DefaultSortingNumber = ($HeaderNames).ToLower().IndexOf($Column.ToLower())
            if ($DefaultSortingNumber -ne - 1) { , @($DefaultSortingNumber, $Sort) }
        }
    }
    if ($DefaultSortIndex.Count -gt 0 -and $DefaultSortColumn.Count -eq 0) { $ColumnsOrder = foreach ($Column in $DefaultSortIndex) { if ($Column -ne - 1) { , @($Column, $Sort) } } }
    if ($ColumnsOrder.Count -gt 0) {
        $Options."order" = @($ColumnsOrder)
        $Options.colReorder = $false
    }
    if ($ScreenSizePercent -gt 0) { $Options."scrollY" = "$($ScreenSizePercent)vh" }
    if ($null -ne $ConditionalFormatting) { $Options.createdRow = '' }
    if ($ResponsivePriorityOrderIndex -or $ResponsivePriorityOrder) {
        $PriorityOrder = 0
        [Array] $PriorityOrderBinding = @(foreach ($_ in $ResponsivePriorityOrder) {
                $Index = [array]::indexof($HeaderNames.ToUpper(), $_.ToUpper())
                if ($Index -ne -1) { @{responsivePriority = 0; targets = $Index }
                }
            }
            foreach ($_ in $ResponsivePriorityOrderIndex) { @{responsivePriority = 0; targets = $_ }
            })
        $Options.columnDefs = @(foreach ($_ in $PriorityOrderBinding) {
                $PriorityOrder++
                $_.responsivePriority = $PriorityOrder
                $_
            })
    }
    $Options = $Options | ConvertTo-Json -Depth 6
    $Options = New-TableConditionalFormatting -Options $Options -ConditionalFormatting $ConditionalFormatting -Header $HeaderNames
    [Array] $Tabs = ($Script:HTMLSchema.TabsHeaders | Where-Object { $_.Current -eq $true })
    if ($Tabs.Count -eq 0) { $Tab = @{Active = $true }
    } else { $Tab = $Tabs[0] }
    if (-not $Simplify) {
        $Script:HTMLSchema.Features.DataTables = $true
        $Script:HTMLSchema.Features.DataTablesPDF = $true
        $Script:HTMLSchema.Features.DataTablesExcel = $true
        $TableAttributes = @{id = $DataTableName; class = "$($Style -join ' ')" }
        $SortingFormatDateTime = Add-CustomFormatForDatetimeSorting -DateTimeSortingFormat $DateTimeSortingFormat
        $FilteringOutput = Add-TableFiltering -Filtering $Filtering -FilteringLocation $FilteringLocation
        $FilteringTopCode = $FilteringOutput.FilteringTopCode
        $FilteringBottomCode = $FilteringOutput.FilteringBottomCode
        $LoadSavedState = Add-TableState -DataTableName $DataTableName -Filtering $Filtering -FilteringLocation $FilteringLocation -SavedState (-not $DisableStateSave)
        if ($Tab.Active -eq $true) {
            New-HTMLTag -Tag 'script' { @"
                `$(document).ready(function() {
                    $SortingFormatDateTime
                    $LoadSavedState
                    $FilteringTopCode
                    // Table code
                    var table = `$('#$DataTableName').DataTable(
                        $($Options)
                    );
                    $FilteringBottomCode
                });
"@
 }
        } else {
            [string] $TabName = $Tab.Id
            New-HTMLTag -Tag 'script' { @"
                    `$(document).ready(function() {
                        $SortingFormatDateTime
                        `$('.tabs').on('click', 'a', function (event) {
                            if (`$(event.currentTarget).attr("data-id") == "$TabName" && !$.fn.dataTable.isDataTable("#$DataTableName")) {
                                $LoadSavedState
                                $FilteringTopCode
                                // Table code
                                var table = `$('#$DataTableName').DataTable(
                                    $($Options)
                                );
                                $FilteringBottomCode
                            };
                        });
                    });
"@
 }
        }
    } else { $TableAttributes = @{class = 'sortable' }
    }
    if ($InvokeHTMLTags) { $Table = $Table -replace '&lt;', '<' -replace '&gt;', '>' -replace '&amp;nbsp;', ' ' -replace '&quot;', '"' -replace '&#39;', "'" }
    if (-not $DisableNewLine) { $Table = $Table -replace '(?m)\s+$', "<BR>" }
    if ($OtherHTML) { $BeforeTableCode = Invoke-Command -ScriptBlock $OtherHTML } else { $BeforeTableCode = '' }
    if ($PreContent) { $BeforeTable = Invoke-Command -ScriptBlock $PreContent } else { $BeforeTable = '' }
    if ($PostContent) { $AfterTable = Invoke-Command -ScriptBlock $PostContent } else { $AfterTable = '' }
    New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultPanelOther' } -Value { $BeforeTableCode
        $BeforeTable
        New-HTMLTag -Tag 'table' -Attributes $TableAttributes { New-HTMLTag -Tag 'thead' { if ($AddedHeader) { $AddedHeader } else { $Header } }
            New-HTMLTag -Tag 'tbody' { $Table }
            if (-not $HideFooter) { New-HTMLTag -Tag 'tfoot' { $Header } } }
        $AfterTable }
}
function New-HTMLTableButtonCopy {
    [alias('TableButtonCopy', 'EmailTableButtonCopy')]
    [CmdletBinding()]
    param()
    [PSCustomObject] @{Type = 'TableButtonCopy'
        Output              = @{extend = 'copyHtml5' }
    }
}
function New-HTMLTableButtonCSV {
    [alias('TableButtonCSV', 'EmailTableButtonCSV')]
    [CmdletBinding()]
    param()
    [PSCustomObject] @{Type = 'TableButtonCSV'
        Output              = @{extend = 'csvHtml5' }
    }
}
function New-HTMLTableButtonExcel {
    [alias('TableButtonExcel', 'EmailTableButtonExcel')]
    [CmdletBinding()]
    param()
    [PSCustomObject] @{Type = 'TableButtonExcel'
        Output              = @{extend = 'excelHtml5' }
    }
}
function New-HTMLTableButtonPageLength {
    [alias('TableButtonPageLength', 'EmailTableButtonPageLength')]
    [CmdletBinding()]
    param()
    [PSCustomObject] @{Type = 'TableButtonPageLength'
        Output              = @{extend = 'pageLength' }
    }
}
function New-HTMLTableButtonPDF {
    <#
    .SYNOPSIS
    Allows more control when adding buttons to Table
 
    .DESCRIPTION
    Allows more control when adding buttons to Table. Works only within Table or New-HTMLTable scriptblock.
 
    .PARAMETER Title
    Document title (appears above the table in the generated PDF). The special character * is automatically replaced with the value read from the host document's title tag.
 
    .PARAMETER DisplayName
    The button's display text. The text can be configured using this option
 
    .PARAMETER MessageBottom
    Message to be shown at the bottom of the table, or the caption tag if displayed at the bottom of the table.
 
    .PARAMETER MessageTop
    Message to be shown at the top of the table, or the caption tag if displayed at the top of the table.
 
    .PARAMETER FileName
    File name to give the created file (plus the extension defined by the extension option). The special character * is automatically replaced with the value read from the host document's title tag.
 
    .PARAMETER Extension
    The extension to give the created file name. (default .pdf)
 
    .PARAMETER PageSize
    Paper size for the created PDF. This can be A3, A4, A5, LEGAL, LETTER or TABLOID. Other options are available.
 
    .PARAMETER Orientation
    Paper orientation for the created PDF. This can be portrait or landscape
 
    .PARAMETER Header
    Indicate if the table header should be included in the exported data or not.
 
    .PARAMETER Footer
    Indicate if the table footer should be included in the exported data or not.
 
    .EXAMPLE
    Dashboard -Name 'Dashimo Test' -FilePath $PSScriptRoot\DashboardEasy05.html -Show {
        Section -Name 'Test' -Collapsable {
            Container {
                Panel {
                    Table -DataTable $Process {
                        TableButtonPDF
                        TableButtonCopy
                        TableButtonExcel
                    } -Buttons @() -DisableSearch -DisablePaging -HideFooter
                }
                Panel {
                    Table -DataTable $Process -Buttons @() -DisableSearch -DisablePaging -HideFooter
                }
                Panel {
                    Table -DataTable $Process {
                        TableButtonPDF -PageSize A10 -Orientation landscape
                        TableButtonCopy
                        TableButtonExcel
                    } -Buttons @() -DisableSearch -DisablePaging -HideFooter
                }
            }
        }
    }
 
    .NOTES
    Options are based on this URL: https://datatables.net/reference/button/pdfHtml5
 
    #>

    [alias('TableButtonPDF', 'EmailTableButtonPDF')]
    [CmdletBinding()]
    param([string] $Title,
        [string] $DisplayName,
        [string] $MessageBottom,
        [string] $MessageTop,
        [string] $FileName,
        [string] $Extension,
        [string][ValidateSet('4A0', '2A0', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
            'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
            'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10',
            'RA0', 'RA1', 'RA2', 'RA3', 'RA4',
            'SRA0', 'SRA1', 'SRA2', 'SRA3', 'SRA4',
            'EXECUTIVE', 'FOLIO', 'LEGAL', 'LETTER', 'TABLOID')] $PageSize = 'A3',
        [string][ValidateSet('portrait', 'landscape')] $Orientation = 'landscape',
        [switch] $Header,
        [switch] $Footer)
    $Button = @{ }
    $Button.extend = 'pdfHtml5'
    $Button.pageSize = $PageSize
    $Button.orientation = $Orientation
    if ($MessageBottom) { $Button.messageBottom = $MessageBottom }
    if ($MessageTop) { $Button.messageTop = $MessageTop }
    if ($DisplayName) { $Button.text = $DisplayName }
    if ($Title) { $Button.title = $Title }
    if ($FileName) { $Button.filename = $FileName }
    if ($Extension) { $Button.extension = $Extension }
    if ($Header) { $Button.header = $Header.IsPresent }
    if ($Footer) { $Button.footer = $Footer.IsPresent }
    [PSCustomObject] @{Type = 'TableButtonPDF'
        Output              = $Button
    }
}
function New-HTMLTableButtonPrint {
    [alias('TableButtonPrint', 'EmailTableButtonPrint')]
    [CmdletBinding()]
    param()
    $Button = @{extend = 'print' }
    [PSCustomObject] @{Type = 'TableButtonPrint'
        Output              = $Button
    }
}
function New-HTMLTableCondition {
    [CmdletBinding()]
    param([alias('ColumnName')][string] $Name,
        [alias('Type')][ValidateSet('number', 'string')][string] $ComparisonType,
        [ValidateSet('lt', 'le', 'eq', 'ge', 'gt')][string] $Operator,
        [Object] $Value,
        [switch] $Row,
        [nullable[RGBColors]] $Color,
        [nullable[RGBColors]] $BackgroundColor)
    $TableCondition = [PSCustomObject] @{Row = $Row
        Type                                 = $ComparisonType
        Name                                 = $Name
        Operator                             = $Operator
        Value                                = $Value
        Color                                = $Color
        BackgroundColor                      = $BackgroundColor
    }
    [PSCustomObject] @{Type = 'TableCondition'
        Output              = $TableCondition
    }
}
function New-HTMLTableHeader {
    [alias('TableHeader', 'EmailTableHeader')]
    [CmdletBinding()]
    param([string[]] $Names,
        [string] $Title,
        [RGBColors] $Color,
        [RGBColors] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $AddRow,
        [int] $ColumnCount)
    $Style = @{Color    = $Color
        BackGroundColor = $BackGroundColor
        FontSize        = $FontSize
        FontWeight      = $FontWeight
        FontStyle       = $FontStyle
        FontVariant     = $FontVariant
        FontFamily      = $FontFamily
        Alignment       = $Alignment
        TextDecoration  = $TextDecoration
        TextTransform   = $TextTransform
        Direction       = $Direction
    }
    Remove-EmptyValues -Hashtable $Style
    if (($AddRow -and $Title) -or ($Title -and -not $Names)) { $Type = 'TableHeaderFullRow' } elseif ((-not $AddRow -and $Title) -or ($Title -and $Names)) { $Type = 'TableHeaderMerge' } else { $Type = 'TableHeaderStyle' }
    [PSCustomObject]@{Type = $Type
        Output             = @{Names = $Names
            Title                    = $Title
            Style                    = ConvertTo-HTMLStyle @Style
            ColumnCount              = $ColumnCount
        }
    }
}
function New-HTMLTabOptions {
    [alias('TabOptions')]
    [CmdletBinding()]
    param([switch] $SlimTabs,
        [RGBColors] $SelectorColor = [RGBColors]::None,
        [RGBColors] $SelectorColorTarget = [RGBColors]::None,
        [switch] $Transition,
        [switch] $LinearGradient)
    if (-not $Script:HTMLSchema) {
        Write-Warning 'New-HTMLTabOptions - Creation of HTML aborted. Most likely New-HTML is missing.'
        Exit
    }
    $Script:HTMLSchema.TabOptions.SlimTabs = $SlimTabs.IsPresent
    if ($SelectorColor -ne [RGBColors]::None) {
        $Script:Configuration.Features.Tabs.CustomActionsReplace.ColorSelector = ConvertFrom-Color -Color $SelectorColor
        $Script:Configuration.Features.TabsGradient.CustomActionsReplace.ColorSelector = ConvertFrom-Color -Color $SelectorColor
    }
    if ($SelectorColorTarget -ne [RGBColors]::None) {
        $Script:Configuration.Features.Tabs.CustomActionsReplace.ColorTarget = ConvertFrom-Color -Color $SelectorColorTarget
        $Script:Configuration.Features.TabsGradient.CustomActionsReplace.ColorTarget = ConvertFrom-Color -Color $SelectorColorTarget
    }
    $Script:HTMLSchema.Features.TabsGradient = $LinearGradient.IsPresent
    $Script:HTMLSchema.Features.TabsTransition = $Transition.IsPresent
}
function New-HTMLTag {
    [CmdletBinding()]
    param([Parameter(Mandatory = $false, Position = 0)][alias('Content')][ScriptBlock] $Value,
        [Parameter(Mandatory = $true, Position = 1)][string] $Tag,
        [System.Collections.IDictionary] $Attributes,
        [switch] $SelfClosing)
    $HTMLTag = [Ordered] @{Tag = $Tag
        Attributes             = $Attributes
        Value                  = if ($null -eq $Value) { '' } else { Invoke-Command -ScriptBlock $Value }
        SelfClosing            = $SelfClosing
    }
    $HTML = Set-Tag -HtmlObject $HTMLTag
    return $HTML
}
function New-HTMLText {
    [alias('HTMLText')]
    [CmdletBinding()]
    param([string[]] $Text,
        [RGBColors[]] $Color = @(),
        [RGBColors[]] $BackGroundColor = @(),
        [int[]] $FontSize = @(),
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string[]] $FontWeight = @(),
        [ValidateSet('normal', 'italic', 'oblique')][string[]] $FontStyle = @(),
        [ValidateSet('normal', 'small-caps')][string[]] $FontVariant = @(),
        [string[]] $FontFamily = @(),
        [ValidateSet('left', 'center', 'right', 'justify')][string[]] $Alignment = @(),
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string[]] $TextDecoration = @(),
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string[]] $TextTransform = @(),
        [ValidateSet('rtl')][string[]] $Direction = @(),
        [switch] $LineBreak,
        [switch] $SkipParagraph)
    $DefaultColor = $Color[0]
    $DefaultFontSize = $FontSize[0]
    $DefaultFontWeight = if ($null -eq $FontWeight[0]) { '' } else { $FontWeight[0] }
    $DefaultBackGroundColor = $BackGroundColor[0]
    $DefaultFontFamily = if ($null -eq $FontFamily[0]) { '' } else { $FontFamily[0] }
    $DefaultFontStyle = if ($null -eq $FontStyle[0]) { '' } else { $FontStyle[0] }
    $DefaultTextDecoration = if ($null -eq $TextDecoration[0]) { '' } else { $TextDecoration[0] }
    $DefaultTextTransform = if ($null -eq $TextTransform[0]) { '' } else { $TextTransform[0] }
    $DefaultFontVariant = if ($null -eq $FontVariant[0]) { '' } else { $FontVariant }
    $DefaultDirection = if ($null -eq $Direction[0]) { '' } else { $Direction[0] }
    $DefaultAlignment = if ($null -eq $Alignment[0]) { '' } else { $Alignment[0] }
    $Output = for ($i = 0; $i -lt $Text.Count; $i++) {
        if ($null -eq $FontWeight[$i]) { $ParamFontWeight = $DefaultFontWeight } else { $ParamFontWeight = $FontWeight[$i] }
        if ($null -eq $FontSize[$i]) { $ParamFontSize = $DefaultFontSize } else { $ParamFontSize = $FontSize[$i] }
        if ($null -eq $Color[$i]) { $ParamColor = $DefaultColor } else { $ParamColor = $Color[$i] }
        if ($null -eq $BackGroundColor[$i]) { $ParamBackGroundColor = $DefaultBackGroundColor } else { $ParamBackGroundColor = $BackGroundColor[$i] }
        if ($null -eq $FontFamily[$i]) { $ParamFontFamily = $DefaultFontFamily } else { $ParamFontFamily = $FontFamily[$i] }
        if ($null -eq $FontStyle[$i]) { $ParamFontStyle = $DefaultFontStyle } else { $ParamFontStyle = $FontStyle[$i] }
        if ($null -eq $TextDecoration[$i]) { $ParamTextDecoration = $DefaultTextDecoration } else { $ParamTextDecoration = $TextDecoration[$i] }
        if ($null -eq $TextTransform[$i]) { $ParamTextTransform = $DefaultTextTransform } else { $ParamTextTransform = $TextTransform[$i] }
        if ($null -eq $FontVariant[$i]) { $ParamFontVariant = $DefaultFontVariant } else { $ParamFontVariant = $FontVariant[$i] }
        if ($null -eq $Direction[$i]) { $ParamDirection = $DefaultDirection } else { $ParamDirection = $Direction[$i] }
        if ($null -eq $Alignment[$i]) { $ParamAlignment = $DefaultAlignment } else { $ParamAlignment = $Alignment[$i] }
        $newSpanTextSplat = @{ }
        $newSpanTextSplat.Color = $ParamColor
        $newSpanTextSplat.BackGroundColor = $ParamBackGroundColor
        $newSpanTextSplat.FontSize = $ParamFontSize
        if ($ParamFontWeight -ne '') { $newSpanTextSplat.FontWeight = $ParamFontWeight }
        $newSpanTextSplat.FontFamily = $ParamFontFamily
        if ($ParamFontStyle -ne '') { $newSpanTextSplat.FontStyle = $ParamFontStyle }
        if ($ParamFontVariant -ne '') { $newSpanTextSplat.FontVariant = $ParamFontVariant }
        if ($ParamTextDecoration -ne '') { $newSpanTextSplat.TextDecoration = $ParamTextDecoration }
        if ($ParamTextTransform -ne '') { $newSpanTextSplat.TextTransform = $ParamTextTransform }
        if ($ParamDirection -ne '') { $newSpanTextSplat.Direction = $ParamDirection }
        if ($ParamAlignment -ne '') { $newSpanTextSplat.Alignment = $ParamAlignment }
        $newSpanTextSplat.LineBreak = $LineBreak
        New-HTMLSpanStyle @newSpanTextSplat { if ($Text[$i] -match "\[([^\[]*)\)") {
                $RegexBrackets1 = [regex] "\[([^\[]*)\]"
                $RegexBrackets2 = [regex] "\(([^\[]*)\)"
                $RegexBrackets3 = [regex] "\[([^\[]*)\)"
                $Text1 = $RegexBrackets1.match($Text[$i]).Groups[1].value
                $Text2 = $RegexBrackets2.match($Text[$i]).Groups[1].value
                $Text3 = $RegexBrackets3.match($Text[$i]).Groups[0].value
                if ($Text1 -ne '' -and $Text2 -ne '') {
                    $Link = New-HTMLAnchor -HrefLink $Text2 -Text $Text1
                    $Text[$i].Replace($Text3, $Link)
                }
            } else { $Text[$i] } }
    }
    if ($SkipParagraph) { $Output -join '' } else { New-HTMLTag -Tag 'div' { $Output } }
    if ($LineBreak) { New-HTMLTag -Tag 'br' -SelfClosing }
}
function New-HTMLTimeline {
    param([Parameter(Mandatory = $false, Position = 0)][alias('TimeLineItems')][ScriptBlock] $Content)
    $Script:HTMLSchema.Features.TimeLine = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'timelineSimpleContainer' } { if ($null -eq $Value) { '' } else { Invoke-Command -ScriptBlock $Content } }
}
function New-HTMLTimelineItem {
    [CmdletBinding()]
    param([DateTime] $Date = (Get-Date),
        [string] $HeadingText,
        [string] $Text,
        [nullable[RGBColors]] $Color)
    $Attributes = @{class = 'timelineSimple-item'
        "date-is"         = $Date
    }
    if ($null -ne $Color) {
        $RGBcolor = ConvertFrom-Color -Color $Color
        $Style = "color: $RGBcolor;"
    } else { $Style = '' }
    New-HTMLTag -Tag 'div' -Attributes $Attributes -Value { New-HTMLTag -Tag 'h1' -Attributes @{class = 'timelineSimple'; style = $style } { $HeadingText }
        New-HTMLTag -Tag 'p' -Attributes @{class = 'timelineSimple' } { $Text -Replace [Environment]::NewLine, '<br>' -replace '\n', '<br>' } }
}
function New-HTMLToast {
    [CmdletBinding()]
    param([string] $TextHeader,
        [string] $Text,
        [ValidateSet('Green', 'Blue', 'Orange')] $Color = "Green",
        [ValidateSet('Success', 'Information', 'Exclamation')][string] $Icon = 'Success',
        [string] $Type = 'central')
    $Script:HTMLSchema.Features.Toast = $true
    if ($Type -eq 'central') { $DivClass = "toast $($Color.ToLower()) central" } else { $DivClass = "toast $($Color.ToLower())" }
    New-HTMLTag -Tag 'div' -Attributes @{class = $DivClass } { New-HTMLTag -Tag 'div' -Attributes @{class = 'toast__icon' } { if ($Icon -eq 'Success') { New-IconSuccess } elseif ($Icon -eq 'Information') { New-IconInfo } elseif ($Icon -eq 'Exclamation') { New-IconExclamation } }
        New-HTMLTag -Tag 'div' -Attributes @{class = 'toast__content' } { New-HTMLTag -Tag 'p' -Attributes @{class = 'toast__type' } { $TextHeader }
            New-HTMLTag -Tag 'p' -Attributes @{class = 'toast__message' } { $Text } } }
}
function New-IconExclamation {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class                            = "toast__svg"
        xmlns                            = "http://www.w3.org/2000/svg"
        'xmlns:xlink'                    = "http://www.w3.org/1999/xlink"
        x                                = "0px"
        y                                = "0px"
        viewBox                          = "0 0 301.691 301.691"
        style                            = "enable-background:new 0 0 301.691 301.691;"
        'xml:space'                      = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes { $Points = @{points = "119.151,0 129.6,218.406 172.06,218.406 182.54,0 " }
        New-HTMLTag -Tag 'polygon' -Attributes $Points
        $React = @{x = "130.563"
            y        = "261.168"
            width    = "40.525"
            height   = "40.523"
        }
        New-HTMLTag -Tag 'react' -Attributes $React }
}
function New-IconInfo {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class                            = "toast__svg"
        xmlns                            = "http://www.w3.org/2000/svg"
        'xmlns:xlink'                    = "http://www.w3.org/1999/xlink"
        x                                = "0px"
        y                                = "0px"
        viewBox                          = "0 0 32 32"
        style                            = "enable-background:new 0 0 32 32;"
        'xml:space'                      = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes { $PathAttributes = @{d = "M10,16c1.105,0,2,0.895,2,2v8c0,1.105-0.895,2-2,2H8v4h16v-4h-1.992c-1.102,0-2-0.895-2-2L20,12H8 v4H10z" }
        New-HTMLTag -Tag 'path' -Attributes $PathAttributes
        New-HTMLTag -Tag 'circle' -Attributes @{cx = "16"; cy = "4"; r = "4" } }
}
function New-IconSuccess {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class                            = "toast__svg"
        xmlns                            = "http://www.w3.org/2000/svg"
        'xmlns:xlink'                    = "http://www.w3.org/1999/xlink"
        x                                = "0px"
        y                                = "0px"
        viewBox                          = "0 0 512 512"
        style                            = "enable-background:new 0 0 512 512;"
        'xml:space'                      = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes { $PathAttributes = @{d = "M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0 c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7 C514.5,101.703,514.499,85.494,504.502,75.496z" }
        New-HTMLTag -Tag 'path' -Attributes $PathAttributes }
}
function New-TableConditionalFormatting {
    [CmdletBinding()]
    param([string] $Options,
        [Array] $ConditionalFormatting,
        [string[]] $Header)
    if ($ConditionalFormatting.Count -gt 0) {
        foreach ($Formatting in $ConditionalFormatting) { if ($Formatting.Operator -eq 'gt') { $Formatting.Operator = '>' } elseif ($Formatting.Operator -eq 'lt') { $Formatting.Operator = '<' } elseif ($Formatting.Operator -eq 'eq') { $Formatting.Operator = '==' } elseif ($Formatting.Operator -eq 'le') { $Formatting.Operator = '<=' } elseif ($Formatting.Operator -eq 'ge') { $Formatting.Operator = '>=' } }
        $Condition1 = '"createdRow": function (row, data, dataIndex, column) {'
        $Condition3 = foreach ($Condition in $ConditionalFormatting) {
            $ConditionHeaderNr = $Header.ToLower().IndexOf($($Condition.Name.ToLower()))
            [string] $ColorJSDefinition = ''
            [string] $ColorBackgroundJSDefinition = ''
            if ($null -ne $Condition.Color) {
                $RGBColor = (ConvertFrom-Color -Color $Condition.Color)
                $C = @{"color" = $RGBColor } | ConvertTo-Json
                $ColorJSDefinition = ".css($C)"
            }
            if ($null -ne $Condition.BackgroundColor) {
                $RGBBackgroundColor = (ConvertFrom-Color -Color $Condition.BackgroundColor)
                $BG = @{"background-color" = $RGBBackgroundColor } | ConvertTo-Json
                $ColorBackgroundJSDefinition = ".css($BG)"
            }
            if ($null -eq $Condition.Type -or $Condition.Type -eq 'number') { "if (data[$ConditionHeaderNr] $($Condition.Operator) $($Condition.Value)) {" } elseif ($Condition.Type -eq 'string') { "if (data[$ConditionHeaderNr] $($Condition.Operator) '$($Condition.Value)') {" } elseif ($Condition.Type -eq 'date') { "if (new Date(data[$ConditionHeaderNr]) $($Condition.Operator) new Date('$($Condition.Value)')) {" }
            if ($null -ne $Condition.Row -and $Condition.Row -eq $true) { "`$(column)$($ColorJSDefinition)$($ColorBackgroundJSDefinition);" } else { "`$(column[$ConditionHeaderNr])$($ColorJSDefinition)$($ColorBackgroundJSDefinition);" }
            "}"
        }
        $Condition5 = '}'
        $Test = $Condition1 + $Condition3 + $Condition5
        $Options = $Options -Replace ('"createdRow": ""', $Test)
    }
    return $Options
}
function Out-HtmlView {
    <#
    .SYNOPSIS
    Small function that allows to send output to HTML
 
    .DESCRIPTION
    Small function that allows to send output to HTML. When displaying in HTML it allows data to output to EXCEL, CSV and PDF. It allows sorting, searching and so on.
 
    .PARAMETER Table
    Data you want to display
 
    .PARAMETER Title
    Title of HTML Window
 
    .PARAMETER DefaultSortColumn
    Sort by Column Name
 
    .PARAMETER DefaultSortIndex
    Sort by Column Index
 
    .EXAMPLE
    Get-Process | Select-Object -First 5 | Out-HtmlView
 
    .NOTES
    General notes
    #>

    [alias('Out-GridHtml', 'ohv')]
    [CmdletBinding()]
    param([Parameter(ValueFromPipeline = $true, Mandatory = $true)] $Table,
        [string[]] $PriorityProperties,
        [string] $Title = 'Out-HTMLView',
        [string[]] $DefaultSortColumn,
        [int[]] $DefaultSortIndex,
        [string] $FilePath,
        [switch] $DisablePaging,
        [switch] $PassThru,
        [switch]$Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom',
        [alias('Search')][string]$Find,
        [switch] $InvokeHTMLTags,
        [switch] $DisableNewLine)
    Begin {
        $DataTable = [System.Collections.Generic.List[Object]]::new()
        if ($FilePath -eq '') { $FilePath = Get-FileName -Extension 'html' -Temporary }
    }
    Process { foreach ($T in $Table) { $DataTable.Add($T) } }
    End {
        if ($DataTable.Count -gt 0) {
            $Properties = $DataTable[0].PSObject.Properties.Name
            $RemainingProperties = foreach ($Property in $Properties) { if ($PriorityProperties -notcontains $Property) { $Property } }
            $AllProperties = $PriorityProperties + $RemainingProperties
            $DataTable = $DataTable | Select-Object -Property $AllProperties
        }
        New-HTML -FilePath $FilePath -UseCssLinks -UseJavaScriptLinks -TitleText $Title -ShowHTML { New-HTMLTable -DataTable $DataTable -DefaultSortColumn $DefaultSortColumn -DefaultSortIndex $DefaultSortIndex -DisablePaging:$DisablePaging -Filtering:$Filtering -FilteringLocation $FilteringLocation -Find $Find -InvokeHTMLTags:$InvokeHTMLTags -DisableNewLine:$DisableNewLine }
        if ($PassThru) { $DataTable }
    }
}
Function Save-HTML {
    <#
    .SYNOPSIS
    Short description
 
    .DESCRIPTION
    Long description
 
    .PARAMETER FilePath
    Parameter description
 
    .PARAMETER HTML
    Parameter description
 
    .PARAMETER ShowReport
    Parameter description
 
    .EXAMPLE
    An example
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param
    ([Parameter(Mandatory = $false)][string]$FilePath,
        [Parameter(Mandatory = $true)][Array] $HTML,
        [alias('Show', 'Open')][Parameter(Mandatory = $false)][switch]$ShowHTML,
        [ValidateSet('Unknown', 'String', 'Unicode', 'Byte', 'BigEndianUnicode', 'UTF8', 'UTF7', 'UTF32', 'Ascii', 'Default', 'Oem', 'BigEndianUTF32')] $Encoding = 'UTF8',
        [bool] $Supress = $true)
    if ([string]::IsNullOrEmpty($FilePath)) {
        $FilePath = Get-FileName -Temporary -Extension 'html'
        Write-Warning "Save-HTML - FilePath parameter $FilePath is empty, using Temporary $FilePath"
    } else { if (Test-Path -LiteralPath $FilePath) { Write-Warning "Save-HTML - Path $FilePath already exists. Report will be overwritten." } }
    Write-Verbose "Save-HTML - Saving HTML to file $FilePath"
    try {
        $HTML | Set-Content -LiteralPath $FilePath -Force -Encoding $Encoding
        if (-not $Supress) { $FilePath }
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning "Save-HTML - Failed with error: $ErrorMessage"
    }
    if ($ShowHTML) {
        try { Invoke-Item -LiteralPath $FilePath -ErrorAction Stop } catch {
            $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
            Write-Warning "Save-HTML - couldn't open file $FilePath in a browser. Error: $ErrorMessage"
        }
    }
}
$Script:Configuration = [ordered] @{Features = [ordered] @{Default = @{Comment = 'Always Required Default Visual Settings'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\default.css" }
        }
        DefaultHeadings                                            = @{Comment = 'Always Required Default Headings'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\headings.css" }
        }
        Accordion                                                  = @{Comment = 'Accordion'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\accordion-1.css" }
        }
        CodeBlocks                                                 = @{Comment = 'EnlighterJS CodeBlocks'
            Header                                                             = @{CssLink = 'https://evotec.xyz/wp-content/uploads/pswritehtml/enlighterjs.min.css'
                Css                        = "$PSScriptRoot\Resources\CSS\enlighterjs.min.css"
                JsLink                     = 'https://evotec.xyz/wp-content/uploads/pswritehtml/enlighterjs.min.js'
                JS                         = "$PSScriptRoot\Resources\JS\enlighterjs.min.js"
            }
            Footer                                                             = @{ }
            HeaderAlways                                                       = @{ }
            FooterAlways                                                       = @{JS = "$PSScriptRoot\Resources\JS\enlighterjs-footer.js" }
        }
        Charts                                                     = @{Comment = 'Charts JS'
            Header                                                             = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js' }
        }
        ChartsApex                                                 = @{Comment = 'Apex Charts'
            Header                                                             = @{JsLink = 'https://cdn.jsdelivr.net/npm/apexcharts@latest'
                JS                        = "$PSScriptRoot\Resources\JS\apexcharts.min.js"
            }
            HeaderAlways                                                       = @{ }
        }
        Jquery                                                     = @{Comment = 'Jquery'
            Header                                                             = @{JsLink = 'https://code.jquery.com/jquery-3.3.1.min.js'
                Js                    = "$PSScriptRoot\Resources\JS\jquery-3.3.1.min.js"
            }
        }
        DataTables                                                 = @{Comment = 'DataTables'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\datatables.css"
                CssNoscript            = "$PSScriptRoot\Resources\CSS\datatables.noscript.css"
            }
            Header                                                             = @{CssLink = 'https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/af-2.3.2/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/b-print-1.5.4/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-1.5.0/sl-1.2.6/datatables.min.css'
                Css                        = "$PSScriptRoot\Resources\CSS\datatables.min.css"
                JsLink                     = "https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/af-2.3.2/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/b-print-1.5.4/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-1.5.0/sl-1.2.6/datatables.min.js", "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js", "https://cdn.datatables.net/plug-ins/1.10.19/sorting/datetime-moment.js"
                JS                         = "$PSScriptRoot\Resources\JS\datatables.min.js", "$PSScriptRoot\Resources\JS\moment.min.js", "$PSScriptRoot\Resources\JS\datetime-moment.js"
            }
        }
        DataTablesExperimental                                     = @{Comment = 'DataTables 1.10.19'
            Header                                                             = @{JsLink = 'https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js'
                Js                                    = ""
                Css                                   = ""
                CssLink                               = 'https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css'
            }
        }
        DataTablesColReorder                                       = @{Comment = 'DataTables ColReorder'
            Header                                                             = @{JsLink = 'https://cdn.datatables.net/colreorder/1.5.0/js/dataTables.colReorder.min.js'
                Js                                  = "$PSScriptRoot\Resources\JS\dataTables.colReorder.min.js"
                Css                                 = "$PSScriptRoot\Resources\CSS\colReorder.dataTables.min.css"
                CssLink                             = 'https://cdn.datatables.net/colreorder/1.5.0/css/colReorder.dataTables.min.css'
            }
        }
        DataTablesPDF                                              = @{Comment = 'DataTables PDF Features'
            Header                                                             = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js'
                Js                           = "$PSScriptRoot\Resources\JS\pdfmake.min.js", "$PSScriptRoot\Resources\JS\vfs_fonts.min.js"
            }
        }
        DataTablesExcel                                            = @{Comment = 'DataTables Excel Features'
            Header                                                             = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js'
                JS                             = "$PSScriptRoot\Resources\JS\jszip.min.js"
            }
        }
        Fonts                                                      = @{Comment = 'Default fonts'
            HeaderAlways                                                       = @{CssLink = 'https://fonts.googleapis.com/css?family=Roboto|Hammersmith+One|Questrial|Oswald' }
        }
        FontsAwesome                                               = @{Comment = 'Default fonts icons'
            HeaderAlways                                                       = @{CssLink = 'https://use.fontawesome.com/releases/v5.7.2/css/all.css' }
        }
        HideSection                                                = @{Comment = 'Hide Section Code'
            HeaderAlways                                                       = @{JS = "$PSScriptRoot\Resources\JS\HideSection.js" }
        }
        Tabs                                                       = @{Comment = 'Elastic Tabs'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\tabs-elastic.css" }
            FooterAlways                                                       = @{JS = "$PSScriptRoot\Resources\JS\tabs-elastic.js" }
            CustomActionsReplace                                               = @{'ColorSelector' = ConvertFrom-Color -Color ([RGBColors]::DodgerBlue)
                'ColorTarget'                        = ConvertFrom-Color -Color ([RGBColors]::MediumSlateBlue)
            }
        }
        TabsGradient                                               = @{Comment = 'Elastic Tabs Gradient'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\tabs-elastic.gradient.css" }
            CustomActionsReplace                                               = @{'ColorSelector' = ConvertFrom-Color -Color ([RGBColors]::DodgerBlue)
                'ColorTarget'                        = ConvertFrom-Color -Color ([RGBColors]::MediumSlateBlue)
            }
        }
        TabsTransition                                             = @{Comment = 'Elastic Tabs Transition'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\tabs-elastic.transition.css" }
        }
        TimeLine                                                   = @{Comment = 'Timeline Simple'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\timeline-simple.css" }
        }
        StatusButtonical                                           = @{Comment = 'Status Buttonical'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\status.css" }
        }
        Toast                                                      = @{Comment = 'Toasts Looking Messages'
            HeaderAlways                                                       = @{Css = "$PSScriptRoot\Resources\CSS\toasts.css" }
        }
        TuiGrid                                                    = @{Comment = 'Tui Grid'
            Header                                                             = @{Css = "$PSScriptRoot\Resources\CSS\tuigrid.css"
                CssLink             = 'https://cdn.jsdelivr.net/npm/tui-grid@3.5.0/dist/tui-grid.css'
            }
        }
    }
}
function Set-Tag {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $HtmlObject)
    $HTML = [System.Text.StringBuilder]::new()
    [void] $HTML.Append("<$($HtmlObject.Tag)")
    foreach ($Property in $HtmlObject.Attributes.Keys) {
        $PropertyValue = $HtmlObject.Attributes[$Property]
        if ($PropertyValue -is [System.Collections.IDictionary]) {
            $OutputSubProperties = foreach ($SubAttributes in $PropertyValue.Keys) {
                $SubPropertyValue = $PropertyValue[$SubAttributes]
                if ($null -ne $SubPropertyValue -and $SubPropertyValue -ne '') { "$($SubAttributes):$($SubPropertyValue)" }
            }
            $MyValue = $OutputSubProperties -join ';'
            if ($MyValue.Trim() -ne '') { [void] $HTML.Append(" $Property=`"$MyValue`"") }
        } else { if ($null -ne $PropertyValue -and $PropertyValue -ne '') { [void] $HTML.Append(" $Property=`"$PropertyValue`"") } }
    }
    if (($null -ne $HtmlObject.Value) -and ($HtmlObject.Value -ne '')) {
        [void] $HTML.Append(">")
        if ($HtmlObject.Value.Count -eq 1) {
            if ($HtmlObject.Value -is [System.Collections.IDictionary]) {
                [string] $NewObject = Set-Tag -HtmlObject ($HtmlObject.Value)
                [void] $HTML.Append($NewObject)
            } else { [void] $HTML.Append([string] $HtmlObject.Value) }
        } else {
            foreach ($Entry in $HtmlObject.Value) {
                if ($Entry -is [System.Collections.IDictionary]) {
                    [string] $NewObject = Set-Tag -HtmlObject ($Entry)
                    [void] $HTML.Append($NewObject)
                } else { [void] $HTML.AppendLine([string] $Entry) }
            }
        }
        [void] $HTML.Append("</$($HtmlObject.Tag)>")
    } else { if ($HtmlObject.SelfClosing) { [void] $HTML.Append("/>") } else { [void] $HTML.Append("></$($HtmlObject.Tag)>") } }
    $HTML.ToString()
}
Export-ModuleMember -Function @('New-ChartAxisX', 'New-ChartAxisY', 'New-ChartBar', 'New-ChartBarOptions', 'New-ChartGrid', 'New-ChartLegend', 'New-ChartLine', 'New-ChartTheme', 'New-ChartToolbar', 'New-HTML', 'New-HTMLAnchor', 'New-HTMLAnchorLink', 'New-HTMLAnchorName', 'New-HTMLChart', 'New-HTMLCodeBlock', 'New-HTMLContainer', 'New-HTMLHeading', 'New-HTMLHorizontalLine', 'New-HTMLImage', 'New-HTMLList', 'New-HTMLListItem', 'New-HTMLLogo', 'New-HTMLMessage', 'New-HTMLPanel', 'New-HTMLResourceCSS', 'New-HTMLResourceJS', 'New-HTMLSection', 'New-HTMLSection1', 'New-HTMLSectionHeader', 'New-HTMLSpanStyle', 'New-HTMLStatus', 'New-HTMLStatusItem', 'New-HTMLSubSection', 'New-HTMLTab', 'New-HTMLTable', 'New-HTMLTableButtonCopy', 'New-HTMLTableButtonCSV', 'New-HTMLTableButtonExcel', 'New-HTMLTableButtonPageLength', 'New-HTMLTableButtonPDF', 'New-HTMLTableButtonPrint', 'New-HTMLTableCondition', 'New-HTMLTableHeader', 'New-HTMLTabOptions', 'New-HTMLTag', 'New-HTMLText', 'New-HTMLTimeline', 'New-HTMLTimelineItem', 'New-HTMLToast', 'Out-HtmlView', 'Save-HTML') -Alias @('Chart', 'ChartAxisX', 'ChartAxisY', 'ChartBar', 'ChartBarOptions', 'ChartCategory', 'ChartGrid', 'ChartLegend', 'ChartLine', 'ChartTheme', 'ChartToolbar', 'EmailTableButtonCopy', 'EmailTableButtonCSV', 'EmailTableButtonExcel', 'EmailTableButtonPageLength', 'EmailTableButtonPDF', 'EmailTableButtonPrint', 'EmailTableHeader', 'HTMLText', 'New-ChartCategory', 'New-CSS', 'New-HTMLColumn', 'New-HTMLContent', 'New-JavaScript', 'New-ResourceCSS', 'New-ResourceJS', 'ohv', 'Out-GridHtml', 'TableButtonCopy', 'TableButtonCSV', 'TableButtonExcel', 'TableButtonPageLength', 'TableButtonPDF', 'TableButtonPrint', 'TableHeader', 'TabOptions')