Private/ReportGlossary.ps1

# The chapter "Begriffe": first what Gutcheck is - the principles it keeps and the concepts a
# Report is built from, in every Report alike - then the words of the trade a Report uses,
# each said once in plain words.
#
# A Report names a DFS-Namespace or a Primary Refresh Token by the name a Technician finds it
# under in Windows and in a search, and not by a German word made up for it; what the name
# means stands here, at the end of the Report, for whoever has not met it. Each entry has its
# name in the other language beside it where that is another word: a Technician searches in
# both.
#
# Only the terms a Report uses: a list of every word Gutcheck knows is a dictionary nobody
# reads. The principles and the concepts are the exception, because every Report rests on
# them.

function Get-ReportGlossary {
    <#
    .SYNOPSIS
        Every term the glossary knows: its name, its name in the other language, what it
        is, and the other ways a text writes it. Pure.
    .DESCRIPTION
        The name itself is always found, and so is its name in the other language; Also
        names what else counts as the same term, as a regular expression: "W32Time" is the
        Windows-Zeitgeber as well. Lang is the language of the other name: English beside a
        German name, German beside an English one.
    #>

    [CmdletBinding()]
    [OutputType([psobject])]
    param()

    $entry = { param($Term, $Other, $Text, $Also, $Lang = 'en') [pscustomobject]@{ Term = $Term; Other = $Other; Lang = $Lang; Text = $Text; Also = $Also } }

    # The domain
    & $entry (Get-Text 'Glossary.Term.DfsNamespace')       ''                                         (Get-Text 'Glossary.Text.DfsNamespace')       ''
    & $entry (Get-Text 'Glossary.Term.Site')               (Get-Text 'Glossary.Other.Site')               (Get-Text 'Glossary.Text.Site')               'Standorte'
    & $entry (Get-Text 'Glossary.Term.Sysvol')             ''                                         (Get-Text 'Glossary.Text.Sysvol')             ''
    & $entry (Get-Text 'Glossary.Term.Kerberos')           ''                                         (Get-Text 'Glossary.Text.Kerberos')           ''
    & $entry (Get-Text 'Glossary.Term.Ldap')               ''                                         (Get-Text 'Glossary.Text.Ldap')               'LDAPS'
    & $entry (Get-Text 'Glossary.Term.Ntlm')               ''                                         (Get-Text 'Glossary.Text.Ntlm')               'NTLMv[12]'
    & $entry (Get-Text 'Glossary.Term.LmLevel')            (Get-Text 'Glossary.Other.LmLevel')            (Get-Text 'Glossary.Text.LmLevel')            'LmCompatibilityLevel|NTLM-Stufe|NTLM-Anmeldestufe'
    & $entry (Get-Text 'Glossary.Term.SecureChannel')      (Get-Text 'Glossary.Other.SecureChannel')      (Get-Text 'Glossary.Text.SecureChannel')      ''
    & $entry (Get-Text 'Glossary.Term.Forest')             (Get-Text 'Glossary.Other.Forest')             (Get-Text 'Glossary.Text.Forest')             ''
    & $entry (Get-Text 'Glossary.Term.Gpo')                (Get-Text 'Glossary.Other.Gpo')                (Get-Text 'Glossary.Text.Gpo')                'Gruppenrichtlinienobjekte?|GPOs?'
    & $entry (Get-Text 'Glossary.Term.ClientSideExtension') (Get-Text 'Glossary.Other.ClientSideExtension') (Get-Text 'Glossary.Text.ClientSideExtension') 'Client-Side Extensions' 'de'
    & $entry (Get-Text 'Glossary.Term.DriveMaps')          (Get-Text 'Glossary.Other.DriveMaps')          (Get-Text 'Glossary.Text.DriveMaps')          '' 'de'
    & $entry (Get-Text 'Glossary.Term.WmiFilter')          ''                                         (Get-Text 'Glossary.Text.WmiFilter')          ''
    & $entry (Get-Text 'Glossary.Term.W32Time')            (Get-Text 'Glossary.Other.W32Time')            (Get-Text 'Glossary.Text.W32Time')            'W32Time|Windows-Zeitgeber|w32tm'
    & $entry (Get-Text 'Glossary.Term.Ntp')                ''                                         (Get-Text 'Glossary.Text.Ntp')                '\(S\)NTP'
    & $entry (Get-Text 'Glossary.Term.Stratum')            ''                                         (Get-Text 'Glossary.Text.Stratum')            ''
    & $entry (Get-Text 'Glossary.Term.LeapIndicator')      (Get-Text 'Glossary.Other.LeapIndicator')      (Get-Text 'Glossary.Text.LeapIndicator')      ''

    # Signing in to Microsoft 365, and Outlook
    & $entry (Get-Text 'Glossary.Term.EntraId')            ''                                         (Get-Text 'Glossary.Text.EntraId')            'Azure AD|Entra'
    & $entry (Get-Text 'Glossary.Term.Prt')                ''                                         (Get-Text 'Glossary.Text.Prt')                'Primary Refresh Token|AzureAdPrt|PRT'
    & $entry (Get-Text 'Glossary.Term.Wam')                ''                                         (Get-Text 'Glossary.Text.Wam')                'WAM'
    & $entry (Get-Text 'Glossary.Term.AadBroker')          ''                                         (Get-Text 'Glossary.Text.AadBroker')          'AAD Broker|BrokerPlugin'
    & $entry (Get-Text 'Glossary.Term.Drs')                (Get-Text 'Glossary.Other.Drs')                (Get-Text 'Glossary.Text.Drs')                'Device Registration Service' 'de'
    & $entry (Get-Text 'Glossary.Term.Adfs')               ''                                         (Get-Text 'Glossary.Text.Adfs')               'AD ?FS'
    & $entry (Get-Text 'Glossary.Term.Mfa')                (Get-Text 'Glossary.Other.Mfa')                (Get-Text 'Glossary.Text.Mfa')                ''
    & $entry (Get-Text 'Glossary.Term.Autodiscover')       (Get-Text 'Glossary.Other.Autodiscover')       (Get-Text 'Glossary.Text.Autodiscover')       '' 'de'
    & $entry (Get-Text 'Glossary.Term.Scp')                (Get-Text 'Glossary.Other.Scp')                (Get-Text 'Glossary.Text.Scp')                'SCPs|Dienstverbindungspunkte' 'de'
    & $entry (Get-Text 'Glossary.Term.MapiHttp')           (Get-Text 'Glossary.Other.MapiHttp')           (Get-Text 'Glossary.Text.MapiHttp')           'MAPI' 'de'
    & $entry (Get-Text 'Glossary.Term.CacheMode')          (Get-Text 'Glossary.Other.CacheMode')          (Get-Text 'Glossary.Text.CacheMode')          'Cache-Modus'
    & $entry (Get-Text 'Glossary.Term.Oab')                (Get-Text 'Glossary.Other.Oab')                (Get-Text 'Glossary.Text.Oab')                'OAB'
    & $entry (Get-Text 'Glossary.Term.Ost')                ''                                         (Get-Text 'Glossary.Text.Ost')                'OST'
    & $entry (Get-Text 'Glossary.Term.Pst')                ''                                         (Get-Text 'Glossary.Text.Pst')                'PST'
    & $entry (Get-Text 'Glossary.Term.ClickToRun')         (Get-Text 'Glossary.Other.ClickToRun')         (Get-Text 'Glossary.Text.ClickToRun')         '' 'de'

    # Encryption and certificates
    & $entry (Get-Text 'Glossary.Term.Tls')                ''                                         (Get-Text 'Glossary.Text.Tls')                ''
    & $entry (Get-Text 'Glossary.Term.TlsHandshake')       ''                                         (Get-Text 'Glossary.Text.TlsHandshake')       'Handshakes?'
    & $entry (Get-Text 'Glossary.Term.Schannel')           ''                                         (Get-Text 'Glossary.Text.Schannel')           'SChannel'
    & $entry (Get-Text 'Glossary.Term.CertificateChain')   (Get-Text 'Glossary.Other.CertificateChain')   (Get-Text 'Glossary.Text.CertificateChain')   ''
    & $entry (Get-Text 'Glossary.Term.Crl')                (Get-Text 'Glossary.Other.Crl')                (Get-Text 'Glossary.Text.Crl')                'CRL'
    & $entry (Get-Text 'Glossary.Term.Ctl')                (Get-Text 'Glossary.Other.Ctl')                (Get-Text 'Glossary.Text.Ctl')                'CTL' 'de'

    # The network
    & $entry (Get-Text 'Glossary.Term.Dns')                ''                                         (Get-Text 'Glossary.Text.Dns')                ''
    & $entry (Get-Text 'Glossary.Term.Tcp')                ''                                         (Get-Text 'Glossary.Text.Tcp')                ''
    & $entry (Get-Text 'Glossary.Term.Udp')                ''                                         (Get-Text 'Glossary.Text.Udp')                ''
    & $entry (Get-Text 'Glossary.Term.Quic')               ''                                         (Get-Text 'Glossary.Text.Quic')               ''
    & $entry (Get-Text 'Glossary.Term.Port')               ''                                         (Get-Text 'Glossary.Text.Port')               'Ports'
    & $entry (Get-Text 'Glossary.Term.Ping')               ''                                         (Get-Text 'Glossary.Text.Ping')               ''
    & $entry (Get-Text 'Glossary.Term.Loss')               (Get-Text 'Glossary.Other.Loss')               (Get-Text 'Glossary.Text.Loss')               'Paketverluste?'
    & $entry (Get-Text 'Glossary.Term.Gateway')            ''                                         (Get-Text 'Glossary.Text.Gateway')            'Gateways'
    & $entry (Get-Text 'Glossary.Term.Wlan')               (Get-Text 'Glossary.Other.Wlan')               (Get-Text 'Glossary.Text.Wlan')               'WiFi'
    & $entry (Get-Text 'Glossary.Term.Vpn')                ''                                         (Get-Text 'Glossary.Text.Vpn')                ''
    & $entry (Get-Text 'Glossary.Term.Proxy')              ''                                         (Get-Text 'Glossary.Text.Proxy')              'Proxys|Proxies'
    & $entry (Get-Text 'Glossary.Term.HttpStatus')         (Get-Text 'Glossary.Other.HttpStatus')         (Get-Text 'Glossary.Text.HttpStatus')         ''
    & $entry (Get-Text 'Glossary.Term.Smb')                ''                                         (Get-Text 'Glossary.Text.Smb')                ''
    & $entry (Get-Text 'Glossary.Term.Share')              (Get-Text 'Glossary.Other.Share')              (Get-Text 'Glossary.Text.Share')              'Freigaben'
    & $entry (Get-Text 'Glossary.Term.Multichannel')       ''                                         (Get-Text 'Glossary.Text.Multichannel')       'Multichannel'
    & $entry (Get-Text 'Glossary.Term.Oplocks')            (Get-Text 'Glossary.Other.Oplocks')            (Get-Text 'Glossary.Text.Oplocks')            'Oplocks' 'de'
    & $entry (Get-Text 'Glossary.Term.WebDav')             ''                                         (Get-Text 'Glossary.Text.WebDav')             'WebClient'
    & $entry (Get-Text 'Glossary.Term.OfflineFiles')       (Get-Text 'Glossary.Other.OfflineFiles')       (Get-Text 'Glossary.Text.OfflineFiles')       ''
    & $entry (Get-Text 'Glossary.Term.FolderRedirection')  (Get-Text 'Glossary.Other.FolderRedirection')  (Get-Text 'Glossary.Text.FolderRedirection')  ''
    & $entry (Get-Text 'Glossary.Term.Dhcp')               ''                                         (Get-Text 'Glossary.Text.Dhcp')               ''
    & $entry (Get-Text 'Glossary.Term.Subnet')             (Get-Text 'Glossary.Other.Subnet')             (Get-Text 'Glossary.Text.Subnet')             'Subnetze'
    & $entry (Get-Text 'Glossary.Term.Apipa')              ''                                         (Get-Text 'Glossary.Text.Apipa')              '169\.254'
    & $entry (Get-Text 'Glossary.Term.DnsSuffix')          ''                                         (Get-Text 'Glossary.Text.DnsSuffix')          'Suffix-Suchliste'
    & $entry (Get-Text 'Glossary.Term.SrvRecord')          (Get-Text 'Glossary.Other.SrvRecord')          (Get-Text 'Glossary.Text.SrvRecord')          ''
    & $entry (Get-Text 'Glossary.Term.Ncsi')               ''                                         (Get-Text 'Glossary.Text.Ncsi')               ''
    & $entry (Get-Text 'Glossary.Term.WinHttpProxy')       ''                                         (Get-Text 'Glossary.Text.WinHttpProxy')       ''
    & $entry (Get-Text 'Glossary.Term.Pac')                ''                                         (Get-Text 'Glossary.Text.Pac')                ''
    & $entry (Get-Text 'Glossary.Term.InterruptModeration') (Get-Text 'Glossary.Other.InterruptModeration') (Get-Text 'Glossary.Text.InterruptModeration') ''
    & $entry (Get-Text 'Glossary.Term.Bits')               ''                                         (Get-Text 'Glossary.Text.Bits')               ''
    & $entry (Get-Text 'Glossary.Term.Rpc')                ''                                         (Get-Text 'Glossary.Text.Rpc')                ''
    & $entry (Get-Text 'Glossary.Term.Rdp')                (Get-Text 'Glossary.Other.Rdp')                (Get-Text 'Glossary.Text.Rdp')                'Remotedesktops?|RDP'
    & $entry (Get-Text 'Glossary.Term.Sip')                ''                                         (Get-Text 'Glossary.Text.Sip')                ''

    # Windows itself
    & $entry (Get-Text 'Glossary.Term.Registry')           (Get-Text 'Glossary.Other.Registry')           (Get-Text 'Glossary.Text.Registry')           'HKLM|HKCU|HKU'
    & $entry (Get-Text 'Glossary.Term.ServiceControlManager') (Get-Text 'Glossary.Other.ServiceControlManager') (Get-Text 'Glossary.Text.ServiceControlManager') '' 'de'
    & $entry (Get-Text 'Glossary.Term.Spooler')            (Get-Text 'Glossary.Other.Spooler')            (Get-Text 'Glossary.Text.Spooler')            'Spooler'
    & $entry (Get-Text 'Glossary.Term.FastStartup')        (Get-Text 'Glossary.Other.FastStartup')        (Get-Text 'Glossary.Text.FastStartup')        ''
    & $entry (Get-Text 'Glossary.Term.ComponentStore')     (Get-Text 'Glossary.Other.ComponentStore')     (Get-Text 'Glossary.Text.ComponentStore')     'WinSxS'
    & $entry (Get-Text 'Glossary.Term.Odbc')               (Get-Text 'Glossary.Other.Odbc')               (Get-Text 'Glossary.Text.Odbc')               'ODBC|DSN'

    # Crashes and the memory
    & $entry (Get-Text 'Glossary.Term.Bluescreen')         ''                                         (Get-Text 'Glossary.Text.Bluescreen')         'Bluescreens|Stop-Codes?|Minidumps?'
    & $entry (Get-Text 'Glossary.Term.LiveKernel')         ''                                         (Get-Text 'Glossary.Text.LiveKernel')         'Live-Kernel|LiveKernel\w*'
    & $entry (Get-Text 'Glossary.Term.Whea')               ''                                         (Get-Text 'Glossary.Text.Whea')               ''
    & $entry (Get-Text 'Glossary.Term.Win32k')             ''                                         (Get-Text 'Glossary.Text.Win32k')             ''
    & $entry (Get-Text 'Glossary.Term.AccessViolation')    (Get-Text 'Glossary.Other.AccessViolation')    (Get-Text 'Glossary.Text.AccessViolation')    ''
    & $entry (Get-Text 'Glossary.Term.StackOverflow')      (Get-Text 'Glossary.Other.StackOverflow')      (Get-Text 'Glossary.Text.StackOverflow')      '' 'de'
    & $entry (Get-Text 'Glossary.Term.StackBufferOverrun') ''                                         (Get-Text 'Glossary.Text.StackBufferOverrun') 'Stack Buffer Overrun|Fail-Fast'
    & $entry (Get-Text 'Glossary.Term.UserGdi')            (Get-Text 'Glossary.Other.UserGdi')            (Get-Text 'Glossary.Text.UserGdi')            'USER-Objekte\w*|GDI-Objekte\w*'
    & $entry (Get-Text 'Glossary.Term.WorkingSet')         (Get-Text 'Glossary.Other.WorkingSet')         (Get-Text 'Glossary.Text.WorkingSet')         ''
    & $entry (Get-Text 'Glossary.Term.Commit')             (Get-Text 'Glossary.Other.Commit')             (Get-Text 'Glossary.Text.Commit')             'Zugesichert\w*'
    & $entry (Get-Text 'Glossary.Term.PageFile')           (Get-Text 'Glossary.Other.PageFile')           (Get-Text 'Glossary.Text.PageFile')           ''
    & $entry (Get-Text 'Glossary.Term.Smart')              ''                                         (Get-Text 'Glossary.Text.Smart')              'SMART'
    & $entry (Get-Text 'Glossary.Term.AcpiThermalZone')    ''                                         (Get-Text 'Glossary.Text.AcpiThermalZone')    'ACPI Thermal Zones'
}

function Get-ReportPrinciple {
    <#
    .SYNOPSIS
        What Gutcheck holds to, each in one sentence a Technician can check the Report
        against. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param()

    Get-Text 'Glossary.Principle.AsksOnly'
    Get-Text 'Glossary.Principle.StateNotActivity'
    Get-Text 'Glossary.Principle.Confidential'
    Get-Text 'Glossary.Principle.NotMeasured'
    Get-Text 'Glossary.Principle.LogReach'
    Get-Text 'Glossary.Principle.CodeMeaning'
    Get-Text 'Glossary.Principle.Lead'
    Get-Text 'Glossary.Principle.OneServer'
    Get-Text 'Glossary.Principle.Service'
    Get-Text 'Glossary.Principle.Definitions'
}

function Get-ReportConcept {
    <#
    .SYNOPSIS
        The concepts a Report is built from, by the word the Report uses for each, with the
        English word of Gutcheck's own language beside it. Pure.
    .DESCRIPTION
        In every Report, and never looked for in its text: "Befund" and "Server" stand
        everywhere, and a page of dotted words is a page nobody reads. What a reader never
        sees - how a Check is built inside - has no entry.
    #>

    [CmdletBinding()]
    [OutputType([psobject])]
    param()

    $entry = { param($Term, $Other, $Text) [pscustomobject]@{ Term = $Term; Other = $Other; Lang = 'en'; Text = $Text; Also = '' } }

    # The Run, and what it looks at
    & $entry (Get-Text 'Glossary.Concept.Term.Run')          (Get-Text 'Glossary.Concept.Other.Run')          (Get-Text 'Glossary.Concept.Text.Run')
    & $entry (Get-Text 'Glossary.Concept.Term.Machine')      (Get-Text 'Glossary.Concept.Other.Machine')      (Get-Text 'Glossary.Concept.Text.Machine')
    & $entry (Get-Text 'Glossary.Concept.Term.User')         (Get-Text 'Glossary.Concept.Other.User')         (Get-Text 'Glossary.Concept.Text.User')
    & $entry (Get-Text 'Glossary.Concept.Term.Session')      (Get-Text 'Glossary.Concept.Other.Session')      (Get-Text 'Glossary.Concept.Text.Session')
    & $entry (Get-Text 'Glossary.Concept.Term.UserProfile')  (Get-Text 'Glossary.Concept.Other.UserProfile')  (Get-Text 'Glossary.Concept.Text.UserProfile')
    & $entry (Get-Text 'Glossary.Concept.Term.Situation')    (Get-Text 'Glossary.Concept.Other.Situation')    (Get-Text 'Glossary.Concept.Text.Situation')
    & $entry (Get-Text 'Glossary.Concept.Term.Privilege')    (Get-Text 'Glossary.Concept.Other.Privilege')    (Get-Text 'Glossary.Concept.Text.Privilege')
    & $entry (Get-Text 'Glossary.Concept.Term.Check')        (Get-Text 'Glossary.Concept.Other.Check')        (Get-Text 'Glossary.Concept.Text.Check')
    & $entry (Get-Text 'Glossary.Concept.Term.Definition')   (Get-Text 'Glossary.Concept.Other.Definition')   (Get-Text 'Glossary.Concept.Text.Definition')
    & $entry (Get-Text 'Glossary.Concept.Term.Scope')        (Get-Text 'Glossary.Concept.Other.Scope')        (Get-Text 'Glossary.Concept.Text.Scope')

    # What a Run produces
    & $entry (Get-Text 'Glossary.Concept.Term.Finding')      (Get-Text 'Glossary.Concept.Other.Finding')      (Get-Text 'Glossary.Concept.Text.Finding')
    & $entry (Get-Text 'Glossary.Concept.Term.Severity')     (Get-Text 'Glossary.Concept.Other.Severity')     (Get-Text 'Glossary.Concept.Text.Severity')
    & $entry (Get-Text 'Glossary.Concept.Term.Category')     (Get-Text 'Glossary.Concept.Other.Category')     (Get-Text 'Glossary.Concept.Text.Category')
    & $entry (Get-Text 'Glossary.Concept.Term.App')          (Get-Text 'Glossary.Concept.Other.App')          (Get-Text 'Glossary.Concept.Text.App')
    & $entry (Get-Text 'Glossary.Concept.Term.Meaning')      (Get-Text 'Glossary.Concept.Other.Meaning')      (Get-Text 'Glossary.Concept.Text.Meaning')
    & $entry (Get-Text 'Glossary.Concept.Term.Hint')         (Get-Text 'Glossary.Concept.Other.Hint')         (Get-Text 'Glossary.Concept.Text.Hint')
    & $entry (Get-Text 'Glossary.Concept.Term.Lead')         (Get-Text 'Glossary.Concept.Other.Lead')         (Get-Text 'Glossary.Concept.Text.Lead')
    & $entry (Get-Text 'Glossary.Concept.Term.Reference')    (Get-Text 'Glossary.Concept.Other.Reference')    (Get-Text 'Glossary.Concept.Text.Reference')
    & $entry (Get-Text 'Glossary.Concept.Term.Evidence')     (Get-Text 'Glossary.Concept.Other.Evidence')     (Get-Text 'Glossary.Concept.Text.Evidence')
    & $entry (Get-Text 'Glossary.Concept.Term.Section')      (Get-Text 'Glossary.Concept.Other.Section')      (Get-Text 'Glossary.Concept.Text.Section')
    & $entry (Get-Text 'Glossary.Concept.Term.Change')       (Get-Text 'Glossary.Concept.Other.Change')       (Get-Text 'Glossary.Concept.Text.Change')

    # The network
    & $entry (Get-Text 'Glossary.Concept.Term.Server')       ''                                               (Get-Text 'Glossary.Concept.Text.Server')
    & $entry (Get-Text 'Glossary.Concept.Term.Service')      (Get-Text 'Glossary.Concept.Other.Service')      (Get-Text 'Glossary.Concept.Text.Service')
    & $entry (Get-Text 'Glossary.Concept.Term.WindowsService') (Get-Text 'Glossary.Concept.Other.WindowsService') (Get-Text 'Glossary.Concept.Text.WindowsService')
    & $entry (Get-Text 'Glossary.Concept.Term.Printer')      (Get-Text 'Glossary.Concept.Other.Printer')      (Get-Text 'Glossary.Concept.Text.Printer')
    & $entry (Get-Text 'Glossary.Concept.Term.Link')         (Get-Text 'Glossary.Concept.Other.Link')         (Get-Text 'Glossary.Concept.Text.Link')
    & $entry (Get-Text 'Glossary.Concept.Term.Measurement')  (Get-Text 'Glossary.Concept.Other.Measurement')  (Get-Text 'Glossary.Concept.Text.Measurement')
    & $entry (Get-Text 'Glossary.Concept.Term.TimedEvent')   (Get-Text 'Glossary.Concept.Other.TimedEvent')   (Get-Text 'Glossary.Concept.Text.TimedEvent')
    & $entry (Get-Text 'Glossary.Concept.Term.LogReach')     ''                                               (Get-Text 'Glossary.Concept.Text.LogReach')
    & $entry (Get-Text 'Glossary.Concept.Term.BigPicture')   ''                                               (Get-Text 'Glossary.Concept.Text.BigPicture')
}

function Select-ReportGlossary {
    <#
    .SYNOPSIS
        The terms a text uses, in alphabetical order. Pure.
    .DESCRIPTION
        A term counts where it stands as a word of its own: "OST" in "Outlook-OST", and
        not in "HOST". By its name, by its name in the other language, or as Also writes
        it. Read in one pass, however long the text: a Report with its evidence is
        megabytes.
    #>

    [CmdletBinding()]
    [OutputType([psobject])]
    param([AllowNull()][AllowEmptyString()][string]$Text, [AllowNull()][AllowEmptyCollection()]$Entry)

    $entries = @($Entry | Where-Object { $_ })
    if (-not $Text -or -not $entries.Count) { return }

    # The longest name first: of two that begin alike at one place the first is taken, and
    # "DNS-Suffix" is no "DNS" with something behind it.
    $alternatives = foreach ($i in (Get-ReportGlossaryOrder -Entry $entries)) {
        $ways = @([regex]::Escape("$($entries[$i].Term)"))
        if ("$($entries[$i].Other)") { $ways += [regex]::Escape("$($entries[$i].Other)") }
        if ("$($entries[$i].Also)") { $ways += "$($entries[$i].Also)" }
        '(?<t{0}>{1})' -f $i, ($ways -join '|')
    }
    $pattern = [regex]('(?<![\w])(?:' + ($alternatives -join '|') + ')(?![\w])')

    $found = New-Object 'System.Collections.Generic.HashSet[int]'
    foreach ($match in $pattern.Matches($Text)) {
        for ($i = 0; $i -lt $entries.Count; $i++) {
            if ($match.Groups["t$i"].Success) { $null = $found.Add($i); break }
        }
        if ($found.Count -eq $entries.Count) { break }
    }
    $picked = @($found | ForEach-Object { $entries[$_] })
    # Ordinal, so that the order is the same on every machine whatever its language.
    [array]::Sort([object[]]$picked, [Comparison[object]] { param($a, $b) [StringComparer]::OrdinalIgnoreCase.Compare("$($a.Term)", "$($b.Term)") })
    $picked
}

function Get-ReportGlossaryOrder {
    <#
    .SYNOPSIS
        The indexes of the entries, the one with the longest name first, and of two as long
        the earlier first. Pure.
    #>

    [CmdletBinding()]
    [OutputType([int])]
    param([AllowNull()][AllowEmptyCollection()]$Entry)

    $entries = @($Entry)
    $order = [int[]]@(0..($entries.Count - 1) | Where-Object { $entries.Count })
    [array]::Sort($order, [Comparison[int]] {
        param($a, $b)
        $byLength = "$($entries[$b].Term)".Length.CompareTo("$($entries[$a].Term)".Length)
        if ($byLength) { $byLength } else { $a.CompareTo($b) }
    })
    $order
}

function ConvertTo-ReportGlossaryText {
    <#
    .SYNOPSIS
        What a reader reads of a piece of the Report, without its markup. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyString()][string]$Html)

    if (-not $Html) { return '' }
    [System.Net.WebUtility]::HtmlDecode(($Html -replace '<[^>]*>', ' '))
}

function ConvertTo-ReportGlossaryHtml {
    <#
    .SYNOPSIS
        The terms as a list, each with its name in the other language and what it is.
        Nothing where there is none. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyCollection()]$Entry, [string]$Id = '')

    $entries = @($Entry | Where-Object { $_ })
    if (-not $entries.Count) { return '' }
    $idAttribute = if ($Id) { ' id="{0}"' -f $Id } else { '' }
    '<dl class="glossary"{0}>{1}</dl>' -f $idAttribute, (($entries | ForEach-Object {
        $other = ''
        if ("$($_.Other)") {
            $lang = if ("$($_.Lang)" -eq 'de') { 'de' } else { 'en' }
            $other = ' <span class="other" lang="{0}">{1}</span>' -f $lang, (ConvertTo-HtmlText "$($_.Other)")
        }
        '<div><dt>{0}{1}</dt><dd>{2}</dd></div>' -f (ConvertTo-HtmlText "$($_.Term)"), $other, (ConvertTo-HtmlText "$($_.Text)")
    }) -join '')
}

function ConvertTo-ReportGlossaryChapterHtml {
    <#
    .SYNOPSIS
        The chapter "Begriffe": what Gutcheck holds to and the concepts of a Report, then
        the terms this Report uses. In every Report. Pure.
    .DESCRIPTION
        Counted by the entries it explains, the concepts and the terms together, as the
        search counts what it finds among them. A Report that uses no term says so where
        the terms would stand.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyCollection()]$Term)

    $terms = @($Term | Where-Object { $_ })
    $concepts = @(Get-ReportConcept)
    $principles = (@(Get-ReportPrinciple) | ForEach-Object { '<li>{0}</li>' -f (ConvertTo-HtmlText $_) }) -join ''
    $termList = if ($terms.Count) { ConvertTo-ReportGlossaryHtml -Entry $terms -Id 'glossary-terms' } else { '<p class="none">{0}</p>' -f (ConvertTo-HtmlText (Get-Text 'Report.Glossary.NoTerms')) }

    ("<section data-chapter=`"glossary`" id=`"ch-glossary`">`n<h2>{0} &middot; {1}</h2>`n" +
        "<div class=`"glossblock`" id=`"glossary-gutcheck`"><h3 class=`"glosshead`">{2}</h3>`n<p class=`"glossnote`">{3}</p>`n" +
        "<h4 class=`"glosssub`">{4}</h4>`n<ol class=`"principles`">{5}</ol>`n<h4 class=`"glosssub`">{6}</h4>`n{7}</div>`n" +
        "<div class=`"glossblock`"><h3 class=`"glosshead`">{8}</h3>`n<p class=`"glossnote`">{9}</p>`n{10}</div>`n</section>") -f `
        (ConvertTo-HtmlText (Get-Text 'Report.Heading.Glossary')), ($concepts.Count + $terms.Count),
        (ConvertTo-HtmlText (Get-Text 'Report.Glossary.Gutcheck')), (ConvertTo-HtmlText (Get-Text 'Report.Glossary.GutcheckIntro')),
        (ConvertTo-HtmlText (Get-Text 'Report.Glossary.Principles')), $principles,
        (ConvertTo-HtmlText (Get-Text 'Report.Glossary.Concepts')), (ConvertTo-ReportGlossaryHtml -Entry $concepts -Id 'glossary-concepts'),
        (ConvertTo-HtmlText (Get-Text 'Report.Glossary.Terms')), (ConvertTo-HtmlText (Get-Text 'Report.Glossary.Intro')), $termList
}

function ConvertTo-ReportGlossaryData {
    <#
    .SYNOPSIS
        The terms a Report uses, as data for its script: each with its name, its name in
        the other language, what it is, and what it looks like in a text as a JavaScript
        pattern. Nothing where there is none. Pure.
    .DESCRIPTION
        So that a term is explained where it stands, and not only at the end. A pattern
        of the glossary is written for .NET and for JavaScript alike; only the names
        themselves are escaped here, for JavaScript, whose escapes are fewer.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyCollection()]$Entry)

    $entries = @($Entry | Where-Object { $_ })
    if (-not $entries.Count) { return '' }
    $escape = { param([string]$Name) [regex]::Replace($Name, '[\\^$.*+?()\[\]{}|/]', '\$0') }
    # The longest name first, as Select-ReportGlossary reads them: the script takes the first
    # that fits.
    $data = @(Get-ReportGlossaryOrder -Entry $entries | ForEach-Object { $entries[$_] } | ForEach-Object {
        $pattern = & $escape "$($_.Term)"
        if ("$($_.Other)") { $pattern = '{0}|{1}' -f $pattern, (& $escape "$($_.Other)") }
        if ("$($_.Also)") { $pattern = '{0}|{1}' -f $pattern, "$($_.Also)" }
        [ordered]@{ t = "$($_.Term)"; o = "$($_.Other)"; x = "$($_.Text)"; p = $pattern }
    })
    # Inside a script element nothing may close it.
    $json = (ConvertTo-Json -InputObject $data -Compress -Depth 3) -replace '<', '\u003c'
    '<script type="application/json" id="terms">{0}</script>' -f $json
}