<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.pcgamingshelter.eu/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiVisor</id>
	<title>PC Gaming Shelter - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.pcgamingshelter.eu/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiVisor"/>
	<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/wiki/Special:Contributions/WikiVisor"/>
	<updated>2026-08-12T11:52:35Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Utility&amp;diff=2780</id>
		<title>Form:Utility</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Utility&amp;diff=2780"/>
		<updated>2026-08-12T08:02:48Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Utility&lt;br /&gt;
|button text=Create or Edit Utility Entry&lt;br /&gt;
|autocomplete on category=Utilities&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Utility}}&lt;br /&gt;
__NOCACHE__&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Utility Entry|edit title=Edit Utility Entry}}}&lt;br /&gt;
{{{for template|Utility}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has game mode&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |property=Has game mode&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game mode:&lt;br /&gt;
|property=Has game mode&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has utility type&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has utility type&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Utility type:&lt;br /&gt;
|property=Has utility type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has developer&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has developer &lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Developer:&lt;br /&gt;
|property=Has developer&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has release date&lt;br /&gt;
  |input type=year&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Release year:&lt;br /&gt;
|property=Has release date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Note:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has status&lt;br /&gt;
  |input type=radiobutton&lt;br /&gt;
  |values=Active, Completed, Abandoned, On Hold&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Active&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Status:&lt;br /&gt;
|property=Has status&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Works on&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Works on game version&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Works on:&lt;br /&gt;
|property=Works on game version&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Download links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Download link|multiple|embed in field=Utility[Download links]|add button text=Add download link}}}&lt;br /&gt;
{{Link fields|Download links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Skin&amp;diff=2779</id>
		<title>Form:Skin</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Skin&amp;diff=2779"/>
		<updated>2026-08-12T08:02:41Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Skin&lt;br /&gt;
|button text=Create or Edit Skin Entry&lt;br /&gt;
|autocomplete on category=Skins&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Skin}}&lt;br /&gt;
__NOCACHE__&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Skin Entry|edit title=Edit Skin Entry}}}&lt;br /&gt;
{{{for template|Skin}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has skin type&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has skin type&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Skin type:&lt;br /&gt;
|property=Has skin type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has developer&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has developer &lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Developer:&lt;br /&gt;
|property=Has developer&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has release date&lt;br /&gt;
  |input type=year&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Release year:&lt;br /&gt;
|property=Has release date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Note:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Download links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Download link|multiple|embed in field=Skin[Download links]|add button text=Add download link}}}&lt;br /&gt;
{{Link fields|Download links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Resource_filter&amp;diff=2778</id>
		<title>Form:Resource filter</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Resource_filter&amp;diff=2778"/>
		<updated>2026-08-12T08:02:33Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{for template|Resource filter}}}&lt;br /&gt;
{{{field|Has resource type|hidden}}}&lt;br /&gt;
{{{field|Has content type|hidden}}}&lt;br /&gt;
{{{field|Has language|hidden}}}&lt;br /&gt;
{{{field|Has date|hidden}}}&lt;br /&gt;
{{{field|Has filter|hidden}}}&lt;br /&gt;
{{{field|Related game|hidden}}}&lt;br /&gt;
{{#widget:Resource filter form}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{standard input|run query|class=d-none}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Resource&amp;diff=2777</id>
		<title>Form:Resource</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Resource&amp;diff=2777"/>
		<updated>2026-08-12T08:01:54Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|create title=Create|edit title=Edit}}}&lt;br /&gt;
{{{for template|Resource}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image (&#039;&#039;leave empty to inherit the image from the related Game&#039;&#039;):&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Short description:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has resource type&lt;br /&gt;
  |input type=dropdown&lt;br /&gt;
  |property=Has resource type&lt;br /&gt;
  |show on select=Video=&amp;gt;video;&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Video&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Media type:&lt;br /&gt;
|property=Has resource type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has content type&lt;br /&gt;
  |input type=checkboxes&lt;br /&gt;
  |property=Has content type&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Content type:&lt;br /&gt;
|property=Has resource type&lt;br /&gt;
}}&lt;br /&gt;
{{{field&lt;br /&gt;
  |Has spoilers&lt;br /&gt;
  |input type=checkbox&lt;br /&gt;
  |label=Has spoilers&lt;br /&gt;
}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has date&lt;br /&gt;
  |input type=date&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Date:&lt;br /&gt;
|property=Has date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Created by&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Created by:&lt;br /&gt;
|property=Created by&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has language&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has language&lt;br /&gt;
  |existing values only&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Language:&lt;br /&gt;
|property=Has language&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has URL&lt;br /&gt;
  |input type=regexp&lt;br /&gt;
  |regexp=/^https?:\/\/[^\s/$.?#].[^\s]*$/&lt;br /&gt;
  |message=Enter a valid URL starting with http:// or https://&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=URL:&lt;br /&gt;
|property=Has URL&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;video&amp;quot;&amp;gt;&lt;br /&gt;
{{{field&lt;br /&gt;
  |Has subtitles&lt;br /&gt;
  |input type=checkbox&lt;br /&gt;
  |label=Has subtitles&lt;br /&gt;
  |show on select=Yes=&amp;gt;subtitle-lang;&lt;br /&gt;
}}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;subtitle-lang&amp;quot;&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has subtitles language&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has language&lt;br /&gt;
  |existing values only&lt;br /&gt;
  |class=form-control&lt;br /&gt;
}}}&lt;br /&gt;
|label=Language of subtitles:&lt;br /&gt;
|property=Has subtitles language&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Resource&lt;br /&gt;
  |namespace=Resource&lt;br /&gt;
  |autocomplete on namespace=Resource&lt;br /&gt;
  |placeholder=Enter a unique name for the resource (will be used as a page name in Resource namespace).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
:{{led|green}} [[Form:Resource/Guide|+ Guide]]&lt;br /&gt;
:{{led|green}} [[Form:Resource/Interview|+ Interview]]&lt;br /&gt;
:{{led|green}} [[Form:Resource/Video|+ Video]]&lt;br /&gt;
:{{led|green}} [[Form:Resource/Screenshot|+ Screenshot]]&lt;br /&gt;
:{{led|green}} [[Form:Resource/Website|+ Website]]&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE: {{PAGENAME}}}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Player&amp;diff=2776</id>
		<title>Form:Player</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Player&amp;diff=2776"/>
		<updated>2026-08-12T08:01:40Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Player&lt;br /&gt;
|button text=Create or Edit Player Entry&lt;br /&gt;
|autocomplete on category=Players&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Player}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Player Entry|edit title=Edit Player Entry}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Player}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Avatar:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Short description:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has status&lt;br /&gt;
  |input type=radiobutton&lt;br /&gt;
  |values=Active,Not Active&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Not Active&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Status:&lt;br /&gt;
|property=Has status&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Plays game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Plays game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Plays mod&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |values from category=Mods&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Mods:&lt;br /&gt;
|property=Plays mod&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has favorite mod&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |values from category=Mods&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Favorite Mods:&lt;br /&gt;
|property=Has favorite mod&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Communities ==&lt;br /&gt;
{{{field&lt;br /&gt;
  |Communities&lt;br /&gt;
  |holds template&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
== Wiki ==&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Is mentor for&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Mentor:&lt;br /&gt;
|property=Is mentor for&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Is guardian for&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Guardian:&lt;br /&gt;
|property=Is guardian for&lt;br /&gt;
}}&lt;br /&gt;
{{{field&lt;br /&gt;
  |Contact links&lt;br /&gt;
  |holds template&lt;br /&gt;
}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Contact link|multiple|maximum instances=1|embed in field=Player[Contact links]|add button text=Add contact link}}}&lt;br /&gt;
{{Link fields|Contact links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Clan|multiple|embed in field=Player[Communities]|add button text=Add clan/guild membership record}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Member of&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Communities&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Clan/Guild:&lt;br /&gt;
|property=Member of&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has role&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has role&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Roles:&lt;br /&gt;
|property=Has role&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has note&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=A brief note:&lt;br /&gt;
|property=Has note&lt;br /&gt;
}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Mod&amp;diff=2775</id>
		<title>Form:Mod</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Mod&amp;diff=2775"/>
		<updated>2026-08-12T08:01:32Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Mod&lt;br /&gt;
|button text=Create or Edit Mod Entry&lt;br /&gt;
|autocomplete on category=Mods&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Mod}}&lt;br /&gt;
__NOCACHE__&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Mod Entry|edit title=Edit Mod Entry}}}&lt;br /&gt;
{{{for template|Mod}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has game mode&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |property=Has game mode&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game mode:&lt;br /&gt;
|property=Has game mode&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has mod type&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |property=Has mod type&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Mod type:&lt;br /&gt;
|property=Has mod type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has developer&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has developer &lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Developer:&lt;br /&gt;
|property=Has developer&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has release date&lt;br /&gt;
  |input type=year&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Release year:&lt;br /&gt;
|property=Has release date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Note:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has status&lt;br /&gt;
  |input type=radiobutton&lt;br /&gt;
  |values=Active, Completed, Abandoned, On Hold&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Active&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Status:&lt;br /&gt;
|property=Has status&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Works on&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Works on game version&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Works on:&lt;br /&gt;
|property=Works on game version&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Download links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Download link|multiple|embed in field=Mod[Download links]|add button text=Add download link}}}&lt;br /&gt;
{{Link fields|Download links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Map&amp;diff=2774</id>
		<title>Form:Map</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Map&amp;diff=2774"/>
		<updated>2026-08-12T08:01:25Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Map&lt;br /&gt;
|button text=Create or Edit Map Entry&lt;br /&gt;
|autocomplete on category=Maps&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Map}}&lt;br /&gt;
__NOCACHE__&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Map Entry|edit title=Edit Map Entry}}}&lt;br /&gt;
{{{for template|Map}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has game mode&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has game mode&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game mode:&lt;br /&gt;
|property=Has game mode&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has map type&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has map type&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Map type:&lt;br /&gt;
|property=Has map type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has developer&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has developer &lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Developer:&lt;br /&gt;
|property=Has developer&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has release date&lt;br /&gt;
  |input type=year&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Release year:&lt;br /&gt;
|property=Has release date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Note:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has status&lt;br /&gt;
  |input type=radiobutton&lt;br /&gt;
  |values=Active, Completed, Abandoned, On Hold&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Active&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Status:&lt;br /&gt;
|property=Has status&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Works on&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Works on game version&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Works on:&lt;br /&gt;
|property=Works on game version&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Download links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Download link|multiple|embed in field=Map[Download links]|add button text=Add download link}}}&lt;br /&gt;
{{Link fields|Download links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Game&amp;diff=2773</id>
		<title>Form:Game</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Game&amp;diff=2773"/>
		<updated>2026-08-12T08:01:17Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Game&lt;br /&gt;
|button text=Create or Edit Game Entry&lt;br /&gt;
|autocomplete on category=Games&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Game}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Game Entry|edit title=Edit Game Entry}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Game}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Short description:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Release date&lt;br /&gt;
  |input type=date&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Release date:&lt;br /&gt;
|property=Has release date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Developer&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has developer &lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Developer:&lt;br /&gt;
|property=Has developer&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Publisher&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has publisher&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Publisher:&lt;br /&gt;
|property=Has publisher&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Current version&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Version:&lt;br /&gt;
|property=Has version&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Gameplay &amp;amp; Genre ==&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Genre&lt;br /&gt;
  |input type=checkboxes&lt;br /&gt;
  |property=Has genre&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Genre:&lt;br /&gt;
|property=Has genre&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Series&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |values from property=Has series&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Series:&lt;br /&gt;
|property=Has series&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Setting&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has setting&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Setting:&lt;br /&gt;
|property=Has setting&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has game mode&lt;br /&gt;
  |input type=checkboxes&lt;br /&gt;
  |property=Has game mode&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Modes:&lt;br /&gt;
|property=Has game mode&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Technical Specs ==&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Platform&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |property=Has platform&lt;br /&gt;
  |max values=1&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Original Platform:&lt;br /&gt;
|property=Has platform&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Works on&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Works on&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Works on:&lt;br /&gt;
|property=Works on&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |System requirements&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=System Requirements:&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Multiplayer tools&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has multiplayer tools&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Multiplayer Tools:&lt;br /&gt;
|property=Has multiplayer tools&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&amp;lt;p class=&amp;quot;mb-0&amp;quot;&amp;gt;Store Links:&amp;lt;/p&amp;gt;&lt;br /&gt;
{{{field|Store links|holds template}}}&lt;br /&gt;
&amp;lt;p class=&amp;quot;mb-0&amp;quot;&amp;gt;Community Links:&amp;lt;/p&amp;gt;&lt;br /&gt;
{{{field|Community links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Store link|multiple|embed in field=Game[Store links]|add button text=Add store link}}}&lt;br /&gt;
{{Link fields|Store links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Community link|multiple|maximum instances=1|embed in field=Game[Community links]|add button text=Add community link}}}&lt;br /&gt;
{{Link fields|Community links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:FeaturedLink&amp;diff=2772</id>
		<title>Form:FeaturedLink</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:FeaturedLink&amp;diff=2772"/>
		<updated>2026-08-12T08:01:07Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|query title=Create featured content page - {{#time:F Y}} }}}&lt;br /&gt;
{{{for template|FeaturedLink}}}&lt;br /&gt;
{{{field|featured date|input type=date|hidden}}}&lt;br /&gt;
{{{field|mediatype|hidden}}}&lt;br /&gt;
{{{field|category|hidden}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{standard input|run query|label=Get form link}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Featured&amp;diff=2771</id>
		<title>Form:Featured</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Featured&amp;diff=2771"/>
		<updated>2026-08-12T08:00:57Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|create title=Create|edit title=Edit}}}&lt;br /&gt;
{{{for template|Featured|label=Featured content}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |mediatype&lt;br /&gt;
  |input type=dropdown&lt;br /&gt;
  |values=Video,Image&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=video&lt;br /&gt;
  |class=form-control&lt;br /&gt;
  |show on select=Video=&amp;gt;video-fields;Image=&amp;gt;image-fields&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Content type:&lt;br /&gt;
|property=Has featured media type&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |category&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from property=Has featured category&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Featured category:&lt;br /&gt;
|property=Has featured category&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |header&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |default=Featured content&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Card header text:&lt;br /&gt;
|property=Has card header&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |title&lt;br /&gt;
  |input type=text&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Card title:&lt;br /&gt;
|property=Has featured title&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |tagline&lt;br /&gt;
  |input type=text&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Card tagline:&lt;br /&gt;
|property=Has featured tagline&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;video-fields&amp;quot;&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |id&lt;br /&gt;
  |input type=text&lt;br /&gt;
 }}}&lt;br /&gt;
|label=YouTube video ID:&lt;br /&gt;
|property=Has video id&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;image-fields&amp;quot;&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |values from namespace=File&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Image:&lt;br /&gt;
|property=Has featured media&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |alt&lt;br /&gt;
  |input type=text&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Alternative text:&lt;br /&gt;
|property=Has alt text&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |attribution&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |autogrow&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Attribution:&lt;br /&gt;
|property=Has attribution&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=6&lt;br /&gt;
  |autogrow&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Description:&lt;br /&gt;
|property=Has featured description&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |max values=1&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Related game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Video of the Month (&#039;&#039;{{#time:F Y}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y}}&lt;br /&gt;
|FeaturedLink[mediatype]=Video&lt;br /&gt;
|FeaturedLink[category]=Video of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Picture of the Month (&#039;&#039;{{#time:F Y}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y}}&lt;br /&gt;
|FeaturedLink[mediatype]=Image&lt;br /&gt;
|FeaturedLink[category]=Picture of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Video of the Month (&#039;&#039;{{#time:F Y|now + 1 month}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y|now + 1 month}}&lt;br /&gt;
|FeaturedLink[mediatype]=Video&lt;br /&gt;
|FeaturedLink[category]=Video of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Picture of the Month (&#039;&#039;{{#time:F Y|now + 1 month}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y|now + 1 month}}&lt;br /&gt;
|FeaturedLink[mediatype]=Image&lt;br /&gt;
|FeaturedLink[category]=Picture of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Video of the Month (&#039;&#039;{{#time:F Y|now + 2 months}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y|now + 2 months}}&lt;br /&gt;
|FeaturedLink[mediatype]=Video&lt;br /&gt;
|FeaturedLink[category]=Video of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
* {{#queryformlink: form=FeaturedLink&lt;br /&gt;
|link text=Picture of the Month (&#039;&#039;{{#time:F Y|now + 2 months}}&#039;&#039;)&lt;br /&gt;
|FeaturedLink[featured date]={{#time:F Y|now + 2 months}}&lt;br /&gt;
|FeaturedLink[mediatype]=Image&lt;br /&gt;
|FeaturedLink[category]=Picture of the Month&lt;br /&gt;
|_run=1&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Event&amp;diff=2770</id>
		<title>Form:Event</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Event&amp;diff=2770"/>
		<updated>2026-08-12T08:00:40Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Event&lt;br /&gt;
|button text=Create or Edit Event Entry&lt;br /&gt;
|autocomplete on category=Events&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Event}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Event Entry|edit title=Edit Event Entry}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Event}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Genre&lt;br /&gt;
  |input type=checkboxes&lt;br /&gt;
  |property=Has genre&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Genre:&lt;br /&gt;
|property=Has genre&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Short description:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{{field&lt;br /&gt;
  |Is recurring&lt;br /&gt;
  |input type=checkbox&lt;br /&gt;
  |label=Recurring event&lt;br /&gt;
  |show on select=Yes=&amp;gt;recurring;Yes=&amp;gt;recurring-title;Yes=&amp;gt;recurring-start-info;Yes=&amp;gt;recurring-end-info;&lt;br /&gt;
}}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;recurring-title&amp;quot;&amp;gt;&lt;br /&gt;
;Recurring Event&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has start date&lt;br /&gt;
  |input type=datetimepicker&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Start date: &amp;lt;span id=&amp;quot;recurring-start-info&amp;quot; class=&amp;quot;text-warning&amp;quot;&amp;gt;For recurring events, the start date of the series.&amp;lt;/span&amp;gt;&lt;br /&gt;
|property=Has start date&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has end date&lt;br /&gt;
  |input type=datetimepicker&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=End date: &amp;lt;span id=&amp;quot;recurring-end-info&amp;quot; class=&amp;quot;text-warning&amp;quot;&amp;gt;For recurring events, the end date of the series. If not specified, max 100 recurring event instances will be created.&amp;lt;/span&amp;gt;&lt;br /&gt;
|property=Has end date&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;recurring&amp;quot;&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Recurring period&lt;br /&gt;
  |input type=regexp&lt;br /&gt;
  |regexp=/^\d*$/&lt;br /&gt;
  |message=Only integers!&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |placeholder=1&lt;br /&gt;
  |default=1&lt;br /&gt;
  |size=2&lt;br /&gt;
  |class=form-control w-auto&lt;br /&gt;
 }}} {{{field&lt;br /&gt;
  |Recurring unit&lt;br /&gt;
  |input type=dropdown&lt;br /&gt;
  |values=day,week,month,year&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=month&lt;br /&gt;
  |placeholder=month&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Repeat every &lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;my-2&amp;quot;&amp;gt;&lt;br /&gt;
If some occurrences do not follow the regular recurrence rule, you can explicitly include or exclude specific dates below. Enter one date per line in this format: &amp;lt;code&amp;gt;March 23, 2010 17:00&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;d-flex&amp;quot; style=&amp;quot;gap: .25rem&amp;quot;&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Exclude dates&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |list&lt;br /&gt;
  |delimiter=\n&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Exclude dates:&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Include dates&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |list&lt;br /&gt;
  |delimiter=\n&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Include dates:&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has tag&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Tags:&lt;br /&gt;
|property=Has tag&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Event links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Event link|multiple|embed in field=Event[Event links]|add button text=Add event link}}}&lt;br /&gt;
{{Link fields|Event links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Form:Community&amp;diff=2769</id>
		<title>Form:Community</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Form:Community&amp;diff=2769"/>
		<updated>2026-08-12T08:00:20Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#forminput: form=Community&lt;br /&gt;
|button text=Create or Edit Community Entry&lt;br /&gt;
|autocomplete on category=Communities&lt;br /&gt;
|no autofocus&lt;br /&gt;
}}&lt;br /&gt;
{{DISPLAYTITLE: Add a New Community}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{info|add title=Add a new Community Entry|edit title=Edit Community Entry}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Community}}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Image&lt;br /&gt;
  |input type=text&lt;br /&gt;
  |uploadable&lt;br /&gt;
  |image preview&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Cover Image:&lt;br /&gt;
|property=Image&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Related game&lt;br /&gt;
  |input type=tokens&lt;br /&gt;
  |delimiter=,&lt;br /&gt;
  |values from category=Games&lt;br /&gt;
  |placeholder=e.g. Half-Life&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Game:&lt;br /&gt;
|property=Related game&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has status&lt;br /&gt;
  |input type=radiobutton&lt;br /&gt;
  |values=Active, Not Active&lt;br /&gt;
  |mandatory&lt;br /&gt;
  |default=Not Active&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Status:&lt;br /&gt;
|property=Has status&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|from {{{field&lt;br /&gt;
  |Year active from&lt;br /&gt;
  |input type=regexp&lt;br /&gt;
  |base type=text&lt;br /&gt;
  |regexp=/^(?:[0-9]{4})?$/&lt;br /&gt;
  |message=Enter a four-digit year.&lt;br /&gt;
  |size=5&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}} to {{{field&lt;br /&gt;
  |Year active until&lt;br /&gt;
  |input type=regexp&lt;br /&gt;
  |base type=text&lt;br /&gt;
  |regexp=/^(?:[0-9]{4})?$/&lt;br /&gt;
  |message=Enter a four-digit year.&lt;br /&gt;
  |size=5&lt;br /&gt;
  |placeholder={{CURRENTYEAR}}&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Years active:&lt;br /&gt;
|property=Has activity period&lt;br /&gt;
|class=d-flex align-items-center gap-2 my-3&lt;br /&gt;
}}&lt;br /&gt;
{{form row&lt;br /&gt;
|{{{field&lt;br /&gt;
  |Has short description&lt;br /&gt;
  |input type=textarea&lt;br /&gt;
  |rows=3&lt;br /&gt;
  |class=form-control&lt;br /&gt;
 }}}&lt;br /&gt;
|label=Note:&lt;br /&gt;
|property=Has short description&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
{{{field|Community links|holds template}}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{for template|Community link|multiple|embed in field=Community[Community links]|add button text=Add community link}}}&lt;br /&gt;
{{Link fields|Community links}}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} &lt;br /&gt;
{{{standard input|preview}}} &lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2768</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2768"/>
		<updated>2026-08-12T07:54:01Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&amp;quot;#games &amp;gt; table&amp;quot;];&lt;br /&gt;
var seriesSelectors = [&amp;quot;#series &amp;gt; table&amp;quot;];&lt;br /&gt;
var assetSelectors = [&amp;quot;#assets &amp;gt; table&amp;quot;];&lt;br /&gt;
var playerSelectors = [&amp;quot;#players table&amp;quot;];&lt;br /&gt;
var clanSelectors = [&amp;quot;#clans table&amp;quot;];&lt;br /&gt;
var allSelectors = selectors.concat(&lt;br /&gt;
  seriesSelectors,&lt;br /&gt;
  assetSelectors,&lt;br /&gt;
  playerSelectors,&lt;br /&gt;
  clanSelectors,&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
  if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
    found = true;&lt;br /&gt;
    break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
  /* Load CSS. */&lt;br /&gt;
  const dtsource =&lt;br /&gt;
    &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
    $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
    $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
      id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
      text: /* css */ `&lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        table.dataTable,&lt;br /&gt;
        table.dataTable * {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
          padding: 2px 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-bordered,&lt;br /&gt;
        .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane,&lt;br /&gt;
        .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-topRow button:hover,&lt;br /&gt;
        .dtsp-topRow input:hover,&lt;br /&gt;
        .dtsp-topRow button:focus,&lt;br /&gt;
        .dtsp-topRow input:focus,&lt;br /&gt;
        .dtsp-topRow button,&lt;br /&gt;
        .dtsp-topRow input {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
          font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-topRow {&lt;br /&gt;
          background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255, 255, 255, 0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.75);&lt;br /&gt;
        }&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
          top: unset !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
          padding-left: 8px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124, 124, 124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        aside.is-open .sidebar-drawer {&lt;br /&gt;
          display: inline-block;&lt;br /&gt;
          right: 0;&lt;br /&gt;
          left: 284px;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          z-index: 3;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        aside.dt-filter-panel {&lt;br /&gt;
          background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
          background-position: bottom;&lt;br /&gt;
          background-repeat: no-repeat;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-search label {&lt;br /&gt;
          display: none;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players tbody tr td:last-child {&lt;br /&gt;
          color: var(--bg-shade-6);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games {&lt;br /&gt;
          align-items: baseline;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-wrap: wrap;&lt;br /&gt;
          gap: 0.25rem 0.5rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__more {&lt;br /&gt;
          display: inline-block;&lt;br /&gt;
          position: relative;&lt;br /&gt;
          margin-left: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle {&lt;br /&gt;
          background: none;&lt;br /&gt;
          color: var(--bs-link-color, #6ea8fe);&lt;br /&gt;
          cursor: pointer;&lt;br /&gt;
          font-size: 0.875em;&lt;br /&gt;
          list-style: none;&lt;br /&gt;
          padding: 0;&lt;br /&gt;
          white-space: nowrap;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle::-webkit-details-marker {&lt;br /&gt;
          display: none;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle:hover,&lt;br /&gt;
        #players .player-games__toggle:focus {&lt;br /&gt;
          text-decoration: underline;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__popup {&lt;br /&gt;
          background-color: var(--bg-shade-4, #11161b);&lt;br /&gt;
          border: 1px solid rgba(255, 255, 255, 0.125) !important;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);&lt;br /&gt;
          color: var(--bs-body-color, #fff);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          gap: 0.25rem;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          line-height: 1.5;&lt;br /&gt;
          min-width: max-content;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: calc(100% + 0.25rem);&lt;br /&gt;
          white-space: nowrap;&lt;br /&gt;
          z-index: 20;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        .player-games__popup::before {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			width: 6px;&lt;br /&gt;
			height: 6px;&lt;br /&gt;
			content: &#039;&#039;;&lt;br /&gt;
			border-left: 3px solid rgba(255, 255, 255, .25);&lt;br /&gt;
			border-top: 3px solid rgba(255, 255, 255, .25);&lt;br /&gt;
			border-right: 3px solid transparent;&lt;br /&gt;
			border-bottom: 3px solid transparent;&lt;br /&gt;
			transform: rotate(45deg);&lt;br /&gt;
			margin-top: -12px;&lt;br /&gt;
        }&lt;br /&gt;
      `,&lt;br /&gt;
    }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  /* Load JavaScript. */&lt;br /&gt;
  $.when(&lt;br /&gt;
    mw.loader.getScript(&lt;br /&gt;
      &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
    ),&lt;br /&gt;
  ).then(&lt;br /&gt;
    () =&amp;gt; {&lt;br /&gt;
      window.datatablesLoaded = true;&lt;br /&gt;
      initDataTable();&lt;br /&gt;
    },&lt;br /&gt;
    (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
  function getDataTableColumnCount(table) {&lt;br /&gt;
    var headerRow =&lt;br /&gt;
      table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
        ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
        : null;&lt;br /&gt;
&lt;br /&gt;
    if (headerRow) {&lt;br /&gt;
      return headerRow.cells.length;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
    $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
      var row = this;&lt;br /&gt;
      var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
      if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
        row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
        cellCount++;&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function waitForTableToSettle(table, callback) {&lt;br /&gt;
    var settleTimer;&lt;br /&gt;
    var timeoutTimer;&lt;br /&gt;
    var observer;&lt;br /&gt;
    var settled = false;&lt;br /&gt;
&lt;br /&gt;
    function finish() {&lt;br /&gt;
      if (settled) return;&lt;br /&gt;
&lt;br /&gt;
      settled = true;&lt;br /&gt;
      clearTimeout(settleTimer);&lt;br /&gt;
      clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
      if (observer) {&lt;br /&gt;
        observer.disconnect();&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function scheduleFinish() {&lt;br /&gt;
      clearTimeout(settleTimer);&lt;br /&gt;
      settleTimer = setTimeout(finish, 500);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (window.MutationObserver) {&lt;br /&gt;
      observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
      observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
        childList: true,&lt;br /&gt;
        subtree: true,&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
    scheduleFinish();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getAcceptsValues(html) {&lt;br /&gt;
    return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
      .map((value) =&amp;gt; value.trim())&lt;br /&gt;
      .filter(Boolean);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPlainAcceptsValues(html) {&lt;br /&gt;
    return getAcceptsValues(html)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
        return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function renderPlayerGames(html) {&lt;br /&gt;
    var games = getAcceptsValues(html);&lt;br /&gt;
&lt;br /&gt;
    if (games.length &amp;lt; 2) {&lt;br /&gt;
      return games[0] || &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return (&lt;br /&gt;
      &#039;&amp;lt;div class=&amp;quot;player-games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      &#039;&amp;lt;span class=&amp;quot;player-games__first&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      games[0] +&lt;br /&gt;
      &amp;quot;&amp;lt;/span&amp;gt;&amp;quot; +&lt;br /&gt;
      &#039;&amp;lt;details class=&amp;quot;player-games__more&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      &#039;&amp;lt;summary class=&amp;quot;player-games__toggle&amp;quot;&amp;gt;+&#039; +&lt;br /&gt;
      (games.length - 1) +&lt;br /&gt;
      &amp;quot; more&amp;lt;/summary&amp;gt;&amp;quot; +&lt;br /&gt;
      &#039;&amp;lt;div class=&amp;quot;player-games__popup&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Other games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      games&lt;br /&gt;
        .slice(1)&lt;br /&gt;
        .map(function (game) {&lt;br /&gt;
          return &amp;quot;&amp;lt;div&amp;gt;&amp;quot; + game + &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
        })&lt;br /&gt;
        .join(&amp;quot;&amp;quot;) +&lt;br /&gt;
      &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;/details&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPlainSearchPaneRender() {&lt;br /&gt;
    return {&lt;br /&gt;
      display: function (data) {&lt;br /&gt;
        return data;&lt;br /&gt;
      },&lt;br /&gt;
      sp: function (data) {&lt;br /&gt;
        return getPlainAcceptsValues(data);&lt;br /&gt;
      },&lt;br /&gt;
    };&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeText(html) {&lt;br /&gt;
    var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var values = [];&lt;br /&gt;
&lt;br /&gt;
    container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
    values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
      [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(&lt;br /&gt;
        function (attribute) {&lt;br /&gt;
          var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
          if (value) {&lt;br /&gt;
            values.push(value);&lt;br /&gt;
          }&lt;br /&gt;
        },&lt;br /&gt;
      );&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeValue(html) {&lt;br /&gt;
    var text = getGameModeText(html).toLowerCase().replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;SP&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;MP&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeValues(html) {&lt;br /&gt;
    var selectedModes = new Set(&lt;br /&gt;
      getAcceptsValues(html).map(getGameModeValue).filter(Boolean),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
      return selectedModes.has(mode);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
    var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var link;&lt;br /&gt;
&lt;br /&gt;
    container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
    link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!link) {&lt;br /&gt;
      return mode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link = link.cloneNode(false);&lt;br /&gt;
    link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
    return link.outerHTML;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeDisplayValues(html) {&lt;br /&gt;
    var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
    getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
      var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
      if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
        valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
      .filter(function (mode) {&lt;br /&gt;
        return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
      })&lt;br /&gt;
      .map(function (mode) {&lt;br /&gt;
        return valuesByMode[mode];&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function normaliseColumnName(value) {&lt;br /&gt;
    return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
      .trim()&lt;br /&gt;
      .toLowerCase()&lt;br /&gt;
      .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getTableConfigElement(table) {&lt;br /&gt;
    return (&lt;br /&gt;
      table.closest(&lt;br /&gt;
        &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
      ) || table.parentElement&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getFirstColumnName(table) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var columnName = configElement&lt;br /&gt;
      ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
      : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var rawValue = configElement&lt;br /&gt;
      ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
      : &amp;quot;&amp;quot;;&lt;br /&gt;
    var titleIndexes = {};&lt;br /&gt;
    var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
    titles.forEach(function (title, index) {&lt;br /&gt;
      titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/[,\|]/)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        return value.trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean)&lt;br /&gt;
      .forEach(function (value) {&lt;br /&gt;
        var numberValue = Number(value);&lt;br /&gt;
        var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Number.isInteger(numberValue) &amp;amp;&amp;amp;&lt;br /&gt;
          numberValue &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
          numberValue &amp;lt; titles.length&lt;br /&gt;
        ) {&lt;br /&gt;
          hiddenIndexes.add(numberValue);&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)&lt;br /&gt;
        ) {&lt;br /&gt;
          hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
    return hiddenIndexes;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var attributes = [&lt;br /&gt;
      &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
      &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
      &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
    ];&lt;br /&gt;
    var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
      return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
    });&lt;br /&gt;
    var titleIndexes = {};&lt;br /&gt;
    var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
    if (!configuredAttribute) {&lt;br /&gt;
      return fallbackIndexes.slice();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    titles.forEach(function (title, index) {&lt;br /&gt;
      titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/[,\|]/)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        return value.trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean)&lt;br /&gt;
      .forEach(function (value) {&lt;br /&gt;
        var numberValue = Number(value);&lt;br /&gt;
        var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
        var index = Number.isInteger(numberValue)&lt;br /&gt;
          ? numberValue&lt;br /&gt;
          : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
          index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
          index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
          paneIndexes.indexOf(index) === -1&lt;br /&gt;
        ) {&lt;br /&gt;
          paneIndexes.push(index);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
    return paneIndexes;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getTableData(table, columnCount) {&lt;br /&gt;
    return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
      .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
      .map((row) =&amp;gt; {&lt;br /&gt;
        var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
        while (data.length &amp;lt; columnCount) {&lt;br /&gt;
          data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return data.slice(0, columnCount);&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function buildTableLayout(table, titles) {&lt;br /&gt;
    var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
    var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    titles.forEach((title) =&amp;gt; {&lt;br /&gt;
      var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
      headerCell.textContent = title;&lt;br /&gt;
      headerRow.appendChild(headerCell);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
    tableHead.appendChild(headerRow);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function suppressSearchPaneBorders(container) {&lt;br /&gt;
    if (!container) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeBorderClass() {&lt;br /&gt;
      container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
        element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
    new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
      attributes: true,&lt;br /&gt;
      attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
      childList: true,&lt;br /&gt;
      subtree: true,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
    dataTable&lt;br /&gt;
      .column(0)&lt;br /&gt;
      .nodes()&lt;br /&gt;
      .toArray()&lt;br /&gt;
      .forEach(function (cell) {&lt;br /&gt;
        cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
          link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
    var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
    var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
    toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
      searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
    } else {&lt;br /&gt;
      wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
    if (search) {&lt;br /&gt;
      toolbar.appendChild(search);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      searchRow &amp;amp;&amp;amp;&lt;br /&gt;
      searchRow.parentNode &amp;amp;&amp;amp;&lt;br /&gt;
      !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      searchRow.remove();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getCurrentPageName() {&lt;br /&gt;
    var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
      pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!pageName) {&lt;br /&gt;
      pageName =&lt;br /&gt;
        (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent ||&lt;br /&gt;
        document.title ||&lt;br /&gt;
        &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
    var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
    if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
      return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return pageName;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
    var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
    var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
    if (!wrapper || !panes) {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
      return document.getElementById(&lt;br /&gt;
        wrapper&lt;br /&gt;
          .querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)&lt;br /&gt;
          .getAttribute(&amp;quot;aria-controls&amp;quot;),&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
    var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
    var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
    var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
    toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
    toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
    toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    panel.id = panelId;&lt;br /&gt;
    panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
    panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
    panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
    drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
    drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
    drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
    title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
    title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
    close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
    close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
    close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
    close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    header.append(title, close);&lt;br /&gt;
    body.appendChild(panes);&lt;br /&gt;
    panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
    setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
    document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
    function openPanel() {&lt;br /&gt;
      lastFocusedElement = document.activeElement;&lt;br /&gt;
      panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
      panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
      close.focus();&lt;br /&gt;
      dataTable.columns.adjust();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function closePanel() {&lt;br /&gt;
      panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
      panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
        lastFocusedElement.focus();&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      dataTable.columns.adjust();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
    close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
    drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
    backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
      if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
        closePanel();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return panel;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
    .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
    .each(function () {&lt;br /&gt;
      var table = this;&lt;br /&gt;
&lt;br /&gt;
      waitForTableToSettle(table, function () {&lt;br /&gt;
        if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
        $(table).DataTable({&lt;br /&gt;
          language: {&lt;br /&gt;
            search: &amp;quot;&amp;quot;,&lt;br /&gt;
            searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              title: {&lt;br /&gt;
                _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                0: &amp;quot;&amp;quot;,&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          retrieve: true,&lt;br /&gt;
          order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
          pageLength: 1000,&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
  $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
      /*&lt;br /&gt;
       * The source table is emitted as Games, Series.&lt;br /&gt;
       * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
       */&lt;br /&gt;
      var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
        return {&lt;br /&gt;
          series: row[1],&lt;br /&gt;
          games: row[0],&lt;br /&gt;
        };&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      normaliseDataTableRows(table, titles.length);&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      try {&lt;br /&gt;
        var dataTable = new DataTable(table, {&lt;br /&gt;
          data: data,&lt;br /&gt;
&lt;br /&gt;
          columns: [&lt;br /&gt;
            {&lt;br /&gt;
              data: &amp;quot;games&amp;quot;,&lt;br /&gt;
              name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
              title: &amp;quot;Game&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              data: &amp;quot;series&amp;quot;,&lt;br /&gt;
              name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              visible: false,&lt;br /&gt;
              searchable: true,&lt;br /&gt;
              type: &amp;quot;string&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          ],&lt;br /&gt;
&lt;br /&gt;
          layout: {&lt;br /&gt;
            topStart: null,&lt;br /&gt;
            topEnd: null,&lt;br /&gt;
            top1: {&lt;br /&gt;
              searchBuilder: {&lt;br /&gt;
                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                preDefined: {&lt;br /&gt;
                  logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                  criteria: [&lt;br /&gt;
                    {&lt;br /&gt;
                      data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                      origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                      condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                      type: &amp;quot;string&amp;quot;,&lt;br /&gt;
                    },&lt;br /&gt;
                  ],&lt;br /&gt;
                },&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
            top2: {},&lt;br /&gt;
          },&lt;br /&gt;
&lt;br /&gt;
          language: {&lt;br /&gt;
            searchBuilder: {&lt;br /&gt;
              data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              value: &amp;quot;Select a series&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
&lt;br /&gt;
          order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
          paging: false,&lt;br /&gt;
&lt;br /&gt;
          initComplete: function () {&lt;br /&gt;
            var api = this.api();&lt;br /&gt;
            var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
            function emptySeriesCriterion() {&lt;br /&gt;
              return {&lt;br /&gt;
                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                criteria: [&lt;br /&gt;
                  {&lt;br /&gt;
                    data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                    origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                    condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                    type: &amp;quot;string&amp;quot;,&lt;br /&gt;
                  },&lt;br /&gt;
                ],&lt;br /&gt;
              };&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            function enableAllSeriesOption() {&lt;br /&gt;
              var valueSelect = container.find(&amp;quot;.dtsb-value&amp;quot;).first();&lt;br /&gt;
              var emptyOption = valueSelect&lt;br /&gt;
                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                .first();&lt;br /&gt;
&lt;br /&gt;
              emptyOption&lt;br /&gt;
                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            container[0].addEventListener(&lt;br /&gt;
              &amp;quot;change&amp;quot;,&lt;br /&gt;
              function (event) {&lt;br /&gt;
                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                  !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                  select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                ) {&lt;br /&gt;
                  return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                /*&lt;br /&gt;
                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                 * Stop its listener before it calls toString()&lt;br /&gt;
                 * on undefined, then reset the criterion here.&lt;br /&gt;
                 */&lt;br /&gt;
                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                api.searchBuilder.rebuild(emptySeriesCriterion(), false);&lt;br /&gt;
                api.draw(false);&lt;br /&gt;
                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
              },&lt;br /&gt;
              true,&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
          },&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        dataTable.columns.adjust().draw(false);&lt;br /&gt;
      } catch (error) {&lt;br /&gt;
        mw.log.error(&amp;quot;Could not initialise the Series DataTable:&amp;quot;, error);&lt;br /&gt;
      } finally {&lt;br /&gt;
        $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&lt;br /&gt;
        &amp;quot;Asset&amp;quot;,&lt;br /&gt;
        &amp;quot;Type&amp;quot;,&lt;br /&gt;
        &amp;quot;Subtype&amp;quot;,&lt;br /&gt;
        &amp;quot;Mode&amp;quot;,&lt;br /&gt;
        &amp;quot;Developer&amp;quot;,&lt;br /&gt;
        &amp;quot;Released&amp;quot;,&lt;br /&gt;
        &amp;quot;Status&amp;quot;,&lt;br /&gt;
        &amp;quot;Description&amp;quot;,&lt;br /&gt;
        &amp;quot;Version&amp;quot;,&lt;br /&gt;
        &amp;quot;Files&amp;quot;,&lt;br /&gt;
        &amp;quot;Game&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
&lt;br /&gt;
      var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
      if (mw.config.get(&amp;quot;wgPageName&amp;quot;) === &amp;quot;Mods&amp;quot;) {&lt;br /&gt;
        paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: titles.map(function (title, index) {&lt;br /&gt;
          var column = {&lt;br /&gt;
            title: title,&lt;br /&gt;
            visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
            },&lt;br /&gt;
          };&lt;br /&gt;
&lt;br /&gt;
          if (index === 0) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
            column.render = {&lt;br /&gt;
              display: function (cellData) {&lt;br /&gt;
                if (index === 4) {&lt;br /&gt;
                  return (&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                  );&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return cellData;&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (cellData) {&lt;br /&gt;
                return getPlainAcceptsValues(cellData);&lt;br /&gt;
              },&lt;br /&gt;
            };&lt;br /&gt;
            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          if (index === 9) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
              wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
              var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
              if (!links.length) {&lt;br /&gt;
                return &amp;quot;&amp;quot;;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
              links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                link.textContent =&lt;br /&gt;
                  links.length === 1&lt;br /&gt;
                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                  downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                }&lt;br /&gt;
              });&lt;br /&gt;
&lt;br /&gt;
              return downloads.innerHTML;&lt;br /&gt;
            };&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          return column;&lt;br /&gt;
        }),&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        new Set(),&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
      var paneIndexes = [1, 4];&lt;br /&gt;
      var clanColorClasses = Array.from(&lt;br /&gt;
        table.tBodies[0] ? table.tBodies[0].rows : [],&lt;br /&gt;
      )&lt;br /&gt;
        .filter(function (row) {&lt;br /&gt;
          return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
        })&lt;br /&gt;
        .map(function (row) {&lt;br /&gt;
          return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        data: data,&lt;br /&gt;
        columns: [&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
            createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
              var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
              if (!colorClasses) {&lt;br /&gt;
                return;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              colorClasses&lt;br /&gt;
                .split(/\s+/)&lt;br /&gt;
                .filter(Boolean)&lt;br /&gt;
                .forEach(function (className) {&lt;br /&gt;
                  cell.classList.add(className);&lt;br /&gt;
                });&lt;br /&gt;
            },&lt;br /&gt;
            render: function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
            render: function (cellData, type) {&lt;br /&gt;
              if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
              container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
              container&lt;br /&gt;
                .querySelectorAll(&amp;quot;a.external[href]&amp;quot;)&lt;br /&gt;
                .forEach(function (link) {&lt;br /&gt;
                  var hostname;&lt;br /&gt;
&lt;br /&gt;
                  try {&lt;br /&gt;
                    hostname = new URL(link.href, window.location.href)&lt;br /&gt;
                      .hostname;&lt;br /&gt;
                  } catch (error) {&lt;br /&gt;
                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                  }&lt;br /&gt;
&lt;br /&gt;
                  if (hostname) {&lt;br /&gt;
                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                  }&lt;br /&gt;
&lt;br /&gt;
                  link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                  link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
              return container.innerHTML;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        ],&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        new Set(),&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var fallbackTitles = [&lt;br /&gt;
        &amp;quot;Player&amp;quot;,&lt;br /&gt;
        &amp;quot;Games&amp;quot;,&lt;br /&gt;
        &amp;quot;Clans&amp;quot;,&lt;br /&gt;
        &amp;quot;Roles&amp;quot;,&lt;br /&gt;
        &amp;quot;Clan (Role)&amp;quot;,&lt;br /&gt;
        &amp;quot;Status&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
      var headerCells =&lt;br /&gt;
        table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
          ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
          : [];&lt;br /&gt;
      var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
        var title = headerCells[index]&lt;br /&gt;
          ? headerCells[index].textContent.trim()&lt;br /&gt;
          : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return title || fallbackTitle;&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
      var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
      var playerColorClasses = Array.from(&lt;br /&gt;
        table.tBodies[0] ? table.tBodies[0].rows : [],&lt;br /&gt;
      )&lt;br /&gt;
        .filter(function (row) {&lt;br /&gt;
          return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
        })&lt;br /&gt;
        .map(function (row) {&lt;br /&gt;
          return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: titles.map(function (title, index) {&lt;br /&gt;
          var column = {&lt;br /&gt;
            title: title,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
            },&lt;br /&gt;
          };&lt;br /&gt;
&lt;br /&gt;
          if (index === 0) {&lt;br /&gt;
            column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
              var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
              if (!colorClasses) {&lt;br /&gt;
                return;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              colorClasses&lt;br /&gt;
                .split(/\s+/)&lt;br /&gt;
                .filter(Boolean)&lt;br /&gt;
                .forEach(function (className) {&lt;br /&gt;
                  cell.classList.add(className);&lt;br /&gt;
                });&lt;br /&gt;
            };&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
          } else if (index === 1) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return renderPlayerGames(cellData);&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              if (type === &amp;quot;sp&amp;quot;) {&lt;br /&gt;
                return getPlainAcceptsValues(cellData);&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
&lt;br /&gt;
            if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
              column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
          } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
            column.render = {&lt;br /&gt;
              display: function (cellData) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (cellData) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                var linkedValues;&lt;br /&gt;
                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                linkedValues = Array.from(&lt;br /&gt;
                  container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                  function (link) {&lt;br /&gt;
                    return link.textContent.trim();&lt;br /&gt;
                  },&lt;br /&gt;
                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                if (linkedValues.length) {&lt;br /&gt;
                  return linkedValues;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                blockValues = Array.from(&lt;br /&gt;
                  container.children,&lt;br /&gt;
                  function (element) {&lt;br /&gt;
                    return element.textContent.trim();&lt;br /&gt;
                  },&lt;br /&gt;
                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                return blockValues.length&lt;br /&gt;
                  ? blockValues&lt;br /&gt;
                  : getAcceptsValues(cellData);&lt;br /&gt;
              },&lt;br /&gt;
            };&lt;br /&gt;
            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          return column;&lt;br /&gt;
        }),&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        hiddenColumnIndexes,&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&lt;br /&gt;
        getFirstColumnName(table),&lt;br /&gt;
        &amp;quot;Developer&amp;quot;,&lt;br /&gt;
        &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
        &amp;quot;Genre&amp;quot;,&lt;br /&gt;
        &amp;quot;Platform&amp;quot;,&lt;br /&gt;
        &amp;quot;Mode&amp;quot;,&lt;br /&gt;
        &amp;quot;Released&amp;quot;,&lt;br /&gt;
        &amp;quot;Category&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
      var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
      var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
        return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
      });&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: [&lt;br /&gt;
          {&lt;br /&gt;
            title: titles[0],&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
            render: function (data, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  data +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return data;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
            render: {&lt;br /&gt;
              display: function (data) {&lt;br /&gt;
                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (data) {&lt;br /&gt;
                return getGameModeValues(data);&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        ],&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var filterPanel;&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
      filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        hiddenColumnIndexes,&lt;br /&gt;
      );&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2767</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2767"/>
		<updated>2026-08-12T07:40:58Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&amp;quot;#games &amp;gt; table&amp;quot;];&lt;br /&gt;
var seriesSelectors = [&amp;quot;#series &amp;gt; table&amp;quot;];&lt;br /&gt;
var assetSelectors = [&amp;quot;#assets &amp;gt; table&amp;quot;];&lt;br /&gt;
var playerSelectors = [&amp;quot;#players table&amp;quot;];&lt;br /&gt;
var clanSelectors = [&amp;quot;#clans table&amp;quot;];&lt;br /&gt;
var allSelectors = selectors.concat(&lt;br /&gt;
  seriesSelectors,&lt;br /&gt;
  assetSelectors,&lt;br /&gt;
  playerSelectors,&lt;br /&gt;
  clanSelectors,&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
  if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
    found = true;&lt;br /&gt;
    break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
  /* Load CSS. */&lt;br /&gt;
  const dtsource =&lt;br /&gt;
    &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
    $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
    $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
      id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
      text: /* css */ `&lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        table.dataTable,&lt;br /&gt;
        table.dataTable * {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
          padding: 2px 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-bordered,&lt;br /&gt;
        .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane,&lt;br /&gt;
        .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-topRow button:hover,&lt;br /&gt;
        .dtsp-topRow input:hover,&lt;br /&gt;
        .dtsp-topRow button:focus,&lt;br /&gt;
        .dtsp-topRow input:focus,&lt;br /&gt;
        .dtsp-topRow button,&lt;br /&gt;
        .dtsp-topRow input {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
          font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-topRow {&lt;br /&gt;
          background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255, 255, 255, 0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.75);&lt;br /&gt;
        }&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
          top: unset !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
          padding-left: 8px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124, 124, 124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        aside.is-open .sidebar-drawer {&lt;br /&gt;
          display: inline-block;&lt;br /&gt;
          right: 0;&lt;br /&gt;
          left: 284px;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          z-index: 3;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        aside.dt-filter-panel {&lt;br /&gt;
          background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
          background-position: bottom;&lt;br /&gt;
          background-repeat: no-repeat;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-search label {&lt;br /&gt;
          display: none;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players tbody tr td:last-child {&lt;br /&gt;
          color: var(--bg-shade-6);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games {&lt;br /&gt;
          align-items: baseline;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-wrap: wrap;&lt;br /&gt;
          gap: 0.25rem 0.5rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__more {&lt;br /&gt;
          display: inline-block;&lt;br /&gt;
          position: relative;&lt;br /&gt;
          margin-left: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle {&lt;br /&gt;
          background: none;&lt;br /&gt;
          color: var(--bs-link-color, #6ea8fe);&lt;br /&gt;
          cursor: pointer;&lt;br /&gt;
          font-size: 0.875em;&lt;br /&gt;
          list-style: none;&lt;br /&gt;
          padding: 0;&lt;br /&gt;
          white-space: nowrap;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle::-webkit-details-marker {&lt;br /&gt;
          display: none;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle:hover,&lt;br /&gt;
        #players .player-games__toggle:focus {&lt;br /&gt;
          text-decoration: underline;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__popup {&lt;br /&gt;
          background-color: var(--bg-shade-4, #11161b);&lt;br /&gt;
          border: 1px solid rgba(255, 255, 255, 0.125) !important;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);&lt;br /&gt;
          color: var(--bs-body-color, #fff);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          gap: 0.25rem;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          line-height: 1.5;&lt;br /&gt;
          min-width: max-content;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: calc(100% + 0.25rem);&lt;br /&gt;
          white-space: nowrap;&lt;br /&gt;
          z-index: 20;&lt;br /&gt;
        }&lt;br /&gt;
      `,&lt;br /&gt;
    }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  /* Load JavaScript. */&lt;br /&gt;
  $.when(&lt;br /&gt;
    mw.loader.getScript(&lt;br /&gt;
      &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
    ),&lt;br /&gt;
  ).then(&lt;br /&gt;
    () =&amp;gt; {&lt;br /&gt;
      window.datatablesLoaded = true;&lt;br /&gt;
      initDataTable();&lt;br /&gt;
    },&lt;br /&gt;
    (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
  function getDataTableColumnCount(table) {&lt;br /&gt;
    var headerRow =&lt;br /&gt;
      table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
        ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
        : null;&lt;br /&gt;
&lt;br /&gt;
    if (headerRow) {&lt;br /&gt;
      return headerRow.cells.length;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
    $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
      var row = this;&lt;br /&gt;
      var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
      if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
        row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
        cellCount++;&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function waitForTableToSettle(table, callback) {&lt;br /&gt;
    var settleTimer;&lt;br /&gt;
    var timeoutTimer;&lt;br /&gt;
    var observer;&lt;br /&gt;
    var settled = false;&lt;br /&gt;
&lt;br /&gt;
    function finish() {&lt;br /&gt;
      if (settled) return;&lt;br /&gt;
&lt;br /&gt;
      settled = true;&lt;br /&gt;
      clearTimeout(settleTimer);&lt;br /&gt;
      clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
      if (observer) {&lt;br /&gt;
        observer.disconnect();&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function scheduleFinish() {&lt;br /&gt;
      clearTimeout(settleTimer);&lt;br /&gt;
      settleTimer = setTimeout(finish, 500);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (window.MutationObserver) {&lt;br /&gt;
      observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
      observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
        childList: true,&lt;br /&gt;
        subtree: true,&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
    scheduleFinish();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getAcceptsValues(html) {&lt;br /&gt;
    return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
      .map((value) =&amp;gt; value.trim())&lt;br /&gt;
      .filter(Boolean);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPlainAcceptsValues(html) {&lt;br /&gt;
    return getAcceptsValues(html)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
        return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function renderPlayerGames(html) {&lt;br /&gt;
    var games = getAcceptsValues(html);&lt;br /&gt;
&lt;br /&gt;
    if (games.length &amp;lt; 2) {&lt;br /&gt;
      return games[0] || &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return (&lt;br /&gt;
      &#039;&amp;lt;div class=&amp;quot;player-games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      &#039;&amp;lt;span class=&amp;quot;player-games__first&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      games[0] +&lt;br /&gt;
      &amp;quot;&amp;lt;/span&amp;gt;&amp;quot; +&lt;br /&gt;
      &#039;&amp;lt;details class=&amp;quot;player-games__more&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      &#039;&amp;lt;summary class=&amp;quot;player-games__toggle&amp;quot;&amp;gt;+&#039; +&lt;br /&gt;
      (games.length - 1) +&lt;br /&gt;
      &amp;quot; more&amp;lt;/summary&amp;gt;&amp;quot; +&lt;br /&gt;
      &#039;&amp;lt;div class=&amp;quot;player-games__popup&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Other games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
      games&lt;br /&gt;
        .slice(1)&lt;br /&gt;
        .map(function (game) {&lt;br /&gt;
          return &amp;quot;&amp;lt;div&amp;gt;&amp;quot; + game + &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
        })&lt;br /&gt;
        .join(&amp;quot;&amp;quot;) +&lt;br /&gt;
      &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;/details&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPlainSearchPaneRender() {&lt;br /&gt;
    return {&lt;br /&gt;
      display: function (data) {&lt;br /&gt;
        return data;&lt;br /&gt;
      },&lt;br /&gt;
      sp: function (data) {&lt;br /&gt;
        return getPlainAcceptsValues(data);&lt;br /&gt;
      },&lt;br /&gt;
    };&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeText(html) {&lt;br /&gt;
    var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var values = [];&lt;br /&gt;
&lt;br /&gt;
    container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
    values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
      [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(&lt;br /&gt;
        function (attribute) {&lt;br /&gt;
          var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
          if (value) {&lt;br /&gt;
            values.push(value);&lt;br /&gt;
          }&lt;br /&gt;
        },&lt;br /&gt;
      );&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeValue(html) {&lt;br /&gt;
    var text = getGameModeText(html).toLowerCase().replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;SP&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;MP&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
      return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeValues(html) {&lt;br /&gt;
    var selectedModes = new Set(&lt;br /&gt;
      getAcceptsValues(html).map(getGameModeValue).filter(Boolean),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
      return selectedModes.has(mode);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
    var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var link;&lt;br /&gt;
&lt;br /&gt;
    container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
    link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!link) {&lt;br /&gt;
      return mode;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link = link.cloneNode(false);&lt;br /&gt;
    link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
    return link.outerHTML;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getGameModeDisplayValues(html) {&lt;br /&gt;
    var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
    getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
      var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
      if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
        valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
      .filter(function (mode) {&lt;br /&gt;
        return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
      })&lt;br /&gt;
      .map(function (mode) {&lt;br /&gt;
        return valuesByMode[mode];&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function normaliseColumnName(value) {&lt;br /&gt;
    return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
      .trim()&lt;br /&gt;
      .toLowerCase()&lt;br /&gt;
      .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getTableConfigElement(table) {&lt;br /&gt;
    return (&lt;br /&gt;
      table.closest(&lt;br /&gt;
        &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
      ) || table.parentElement&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getFirstColumnName(table) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var columnName = configElement&lt;br /&gt;
      ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
      : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var rawValue = configElement&lt;br /&gt;
      ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
        configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
      : &amp;quot;&amp;quot;;&lt;br /&gt;
    var titleIndexes = {};&lt;br /&gt;
    var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
    titles.forEach(function (title, index) {&lt;br /&gt;
      titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/[,\|]/)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        return value.trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean)&lt;br /&gt;
      .forEach(function (value) {&lt;br /&gt;
        var numberValue = Number(value);&lt;br /&gt;
        var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Number.isInteger(numberValue) &amp;amp;&amp;amp;&lt;br /&gt;
          numberValue &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
          numberValue &amp;lt; titles.length&lt;br /&gt;
        ) {&lt;br /&gt;
          hiddenIndexes.add(numberValue);&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)&lt;br /&gt;
        ) {&lt;br /&gt;
          hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
    return hiddenIndexes;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
    var configElement = getTableConfigElement(table);&lt;br /&gt;
    var attributes = [&lt;br /&gt;
      &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
      &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
      &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
    ];&lt;br /&gt;
    var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
      return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
    });&lt;br /&gt;
    var titleIndexes = {};&lt;br /&gt;
    var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
    if (!configuredAttribute) {&lt;br /&gt;
      return fallbackIndexes.slice();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    titles.forEach(function (title, index) {&lt;br /&gt;
      titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
      .split(/[,\|]/)&lt;br /&gt;
      .map(function (value) {&lt;br /&gt;
        return value.trim();&lt;br /&gt;
      })&lt;br /&gt;
      .filter(Boolean)&lt;br /&gt;
      .forEach(function (value) {&lt;br /&gt;
        var numberValue = Number(value);&lt;br /&gt;
        var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
        var index = Number.isInteger(numberValue)&lt;br /&gt;
          ? numberValue&lt;br /&gt;
          : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
          Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
          index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
          index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
          paneIndexes.indexOf(index) === -1&lt;br /&gt;
        ) {&lt;br /&gt;
          paneIndexes.push(index);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
    return paneIndexes;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getTableData(table, columnCount) {&lt;br /&gt;
    return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
      .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
      .map((row) =&amp;gt; {&lt;br /&gt;
        var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
        while (data.length &amp;lt; columnCount) {&lt;br /&gt;
          data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return data.slice(0, columnCount);&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function buildTableLayout(table, titles) {&lt;br /&gt;
    var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
    var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    titles.forEach((title) =&amp;gt; {&lt;br /&gt;
      var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
      headerCell.textContent = title;&lt;br /&gt;
      headerRow.appendChild(headerCell);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
    tableHead.appendChild(headerRow);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function suppressSearchPaneBorders(container) {&lt;br /&gt;
    if (!container) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function removeBorderClass() {&lt;br /&gt;
      container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
        element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
    new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
      attributes: true,&lt;br /&gt;
      attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
      childList: true,&lt;br /&gt;
      subtree: true,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
    dataTable&lt;br /&gt;
      .column(0)&lt;br /&gt;
      .nodes()&lt;br /&gt;
      .toArray()&lt;br /&gt;
      .forEach(function (cell) {&lt;br /&gt;
        cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
          link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
    var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
    var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
    toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
      searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
    } else {&lt;br /&gt;
      wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
    if (search) {&lt;br /&gt;
      toolbar.appendChild(search);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      searchRow &amp;amp;&amp;amp;&lt;br /&gt;
      searchRow.parentNode &amp;amp;&amp;amp;&lt;br /&gt;
      !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      searchRow.remove();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getCurrentPageName() {&lt;br /&gt;
    var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
      pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!pageName) {&lt;br /&gt;
      pageName =&lt;br /&gt;
        (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent ||&lt;br /&gt;
        document.title ||&lt;br /&gt;
        &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
    var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
    if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
      return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return pageName;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
    var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
    var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
    if (!wrapper || !panes) {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
      return document.getElementById(&lt;br /&gt;
        wrapper&lt;br /&gt;
          .querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)&lt;br /&gt;
          .getAttribute(&amp;quot;aria-controls&amp;quot;),&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
    var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
    var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
    var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
    toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
    toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
    toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    panel.id = panelId;&lt;br /&gt;
    panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
    panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
    panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
    drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
    drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
    drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
    title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
    title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
    close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
    close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
    close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
    close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    header.append(title, close);&lt;br /&gt;
    body.appendChild(panes);&lt;br /&gt;
    panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
    setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
    document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
    function openPanel() {&lt;br /&gt;
      lastFocusedElement = document.activeElement;&lt;br /&gt;
      panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
      panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
      close.focus();&lt;br /&gt;
      dataTable.columns.adjust();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function closePanel() {&lt;br /&gt;
      panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
      document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
      panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
        lastFocusedElement.focus();&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      dataTable.columns.adjust();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
    close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
    drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
    backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
      if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
        closePanel();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return panel;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
    .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
    .each(function () {&lt;br /&gt;
      var table = this;&lt;br /&gt;
&lt;br /&gt;
      waitForTableToSettle(table, function () {&lt;br /&gt;
        if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
        $(table).DataTable({&lt;br /&gt;
          language: {&lt;br /&gt;
            search: &amp;quot;&amp;quot;,&lt;br /&gt;
            searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              title: {&lt;br /&gt;
                _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                0: &amp;quot;&amp;quot;,&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          retrieve: true,&lt;br /&gt;
          order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
          pageLength: 1000,&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
  $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
      /*&lt;br /&gt;
       * The source table is emitted as Games, Series.&lt;br /&gt;
       * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
       */&lt;br /&gt;
      var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
        return {&lt;br /&gt;
          series: row[1],&lt;br /&gt;
          games: row[0],&lt;br /&gt;
        };&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      normaliseDataTableRows(table, titles.length);&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      try {&lt;br /&gt;
        var dataTable = new DataTable(table, {&lt;br /&gt;
          data: data,&lt;br /&gt;
&lt;br /&gt;
          columns: [&lt;br /&gt;
            {&lt;br /&gt;
              data: &amp;quot;games&amp;quot;,&lt;br /&gt;
              name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
              title: &amp;quot;Game&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
              data: &amp;quot;series&amp;quot;,&lt;br /&gt;
              name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              visible: false,&lt;br /&gt;
              searchable: true,&lt;br /&gt;
              type: &amp;quot;string&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          ],&lt;br /&gt;
&lt;br /&gt;
          layout: {&lt;br /&gt;
            topStart: null,&lt;br /&gt;
            topEnd: null,&lt;br /&gt;
            top1: {&lt;br /&gt;
              searchBuilder: {&lt;br /&gt;
                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                preDefined: {&lt;br /&gt;
                  logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                  criteria: [&lt;br /&gt;
                    {&lt;br /&gt;
                      data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                      origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                      condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                      type: &amp;quot;string&amp;quot;,&lt;br /&gt;
                    },&lt;br /&gt;
                  ],&lt;br /&gt;
                },&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
            top2: {},&lt;br /&gt;
          },&lt;br /&gt;
&lt;br /&gt;
          language: {&lt;br /&gt;
            searchBuilder: {&lt;br /&gt;
              data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
              value: &amp;quot;Select a series&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
&lt;br /&gt;
          order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
          paging: false,&lt;br /&gt;
&lt;br /&gt;
          initComplete: function () {&lt;br /&gt;
            var api = this.api();&lt;br /&gt;
            var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
            function emptySeriesCriterion() {&lt;br /&gt;
              return {&lt;br /&gt;
                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                criteria: [&lt;br /&gt;
                  {&lt;br /&gt;
                    data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                    origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                    condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                    type: &amp;quot;string&amp;quot;,&lt;br /&gt;
                  },&lt;br /&gt;
                ],&lt;br /&gt;
              };&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            function enableAllSeriesOption() {&lt;br /&gt;
              var valueSelect = container.find(&amp;quot;.dtsb-value&amp;quot;).first();&lt;br /&gt;
              var emptyOption = valueSelect&lt;br /&gt;
                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                .first();&lt;br /&gt;
&lt;br /&gt;
              emptyOption&lt;br /&gt;
                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            container[0].addEventListener(&lt;br /&gt;
              &amp;quot;change&amp;quot;,&lt;br /&gt;
              function (event) {&lt;br /&gt;
                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                  !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                  select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                ) {&lt;br /&gt;
                  return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                /*&lt;br /&gt;
                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                 * Stop its listener before it calls toString()&lt;br /&gt;
                 * on undefined, then reset the criterion here.&lt;br /&gt;
                 */&lt;br /&gt;
                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                api.searchBuilder.rebuild(emptySeriesCriterion(), false);&lt;br /&gt;
                api.draw(false);&lt;br /&gt;
                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
              },&lt;br /&gt;
              true,&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
          },&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        dataTable.columns.adjust().draw(false);&lt;br /&gt;
      } catch (error) {&lt;br /&gt;
        mw.log.error(&amp;quot;Could not initialise the Series DataTable:&amp;quot;, error);&lt;br /&gt;
      } finally {&lt;br /&gt;
        $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&lt;br /&gt;
        &amp;quot;Asset&amp;quot;,&lt;br /&gt;
        &amp;quot;Type&amp;quot;,&lt;br /&gt;
        &amp;quot;Subtype&amp;quot;,&lt;br /&gt;
        &amp;quot;Mode&amp;quot;,&lt;br /&gt;
        &amp;quot;Developer&amp;quot;,&lt;br /&gt;
        &amp;quot;Released&amp;quot;,&lt;br /&gt;
        &amp;quot;Status&amp;quot;,&lt;br /&gt;
        &amp;quot;Description&amp;quot;,&lt;br /&gt;
        &amp;quot;Version&amp;quot;,&lt;br /&gt;
        &amp;quot;Files&amp;quot;,&lt;br /&gt;
        &amp;quot;Game&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
&lt;br /&gt;
      var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
      if (mw.config.get(&amp;quot;wgPageName&amp;quot;) === &amp;quot;Mods&amp;quot;) {&lt;br /&gt;
        paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: titles.map(function (title, index) {&lt;br /&gt;
          var column = {&lt;br /&gt;
            title: title,&lt;br /&gt;
            visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
            },&lt;br /&gt;
          };&lt;br /&gt;
&lt;br /&gt;
          if (index === 0) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
            column.render = {&lt;br /&gt;
              display: function (cellData) {&lt;br /&gt;
                if (index === 4) {&lt;br /&gt;
                  return (&lt;br /&gt;
                    &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                    getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                  );&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return cellData;&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (cellData) {&lt;br /&gt;
                return getPlainAcceptsValues(cellData);&lt;br /&gt;
              },&lt;br /&gt;
            };&lt;br /&gt;
            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          if (index === 9) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
              wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
              var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
              if (!links.length) {&lt;br /&gt;
                return &amp;quot;&amp;quot;;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
              links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                link.textContent =&lt;br /&gt;
                  links.length === 1&lt;br /&gt;
                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                  downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                }&lt;br /&gt;
              });&lt;br /&gt;
&lt;br /&gt;
              return downloads.innerHTML;&lt;br /&gt;
            };&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          return column;&lt;br /&gt;
        }),&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        new Set(),&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
      var paneIndexes = [1, 4];&lt;br /&gt;
      var clanColorClasses = Array.from(&lt;br /&gt;
        table.tBodies[0] ? table.tBodies[0].rows : [],&lt;br /&gt;
      )&lt;br /&gt;
        .filter(function (row) {&lt;br /&gt;
          return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
        })&lt;br /&gt;
        .map(function (row) {&lt;br /&gt;
          return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        data: data,&lt;br /&gt;
        columns: [&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
            createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
              var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
              if (!colorClasses) {&lt;br /&gt;
                return;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              colorClasses&lt;br /&gt;
                .split(/\s+/)&lt;br /&gt;
                .filter(Boolean)&lt;br /&gt;
                .forEach(function (className) {&lt;br /&gt;
                  cell.classList.add(className);&lt;br /&gt;
                });&lt;br /&gt;
            },&lt;br /&gt;
            render: function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
            render: function (cellData, type) {&lt;br /&gt;
              if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
              container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
              container&lt;br /&gt;
                .querySelectorAll(&amp;quot;a.external[href]&amp;quot;)&lt;br /&gt;
                .forEach(function (link) {&lt;br /&gt;
                  var hostname;&lt;br /&gt;
&lt;br /&gt;
                  try {&lt;br /&gt;
                    hostname = new URL(link.href, window.location.href)&lt;br /&gt;
                      .hostname;&lt;br /&gt;
                  } catch (error) {&lt;br /&gt;
                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                  }&lt;br /&gt;
&lt;br /&gt;
                  if (hostname) {&lt;br /&gt;
                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                  }&lt;br /&gt;
&lt;br /&gt;
                  link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                  link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
              return container.innerHTML;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        ],&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        new Set(),&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var fallbackTitles = [&lt;br /&gt;
        &amp;quot;Player&amp;quot;,&lt;br /&gt;
        &amp;quot;Games&amp;quot;,&lt;br /&gt;
        &amp;quot;Clans&amp;quot;,&lt;br /&gt;
        &amp;quot;Roles&amp;quot;,&lt;br /&gt;
        &amp;quot;Clan (Role)&amp;quot;,&lt;br /&gt;
        &amp;quot;Status&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
      var headerCells =&lt;br /&gt;
        table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
          ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
          : [];&lt;br /&gt;
      var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
        var title = headerCells[index]&lt;br /&gt;
          ? headerCells[index].textContent.trim()&lt;br /&gt;
          : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return title || fallbackTitle;&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
      var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
      var playerColorClasses = Array.from(&lt;br /&gt;
        table.tBodies[0] ? table.tBodies[0].rows : [],&lt;br /&gt;
      )&lt;br /&gt;
        .filter(function (row) {&lt;br /&gt;
          return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
        })&lt;br /&gt;
        .map(function (row) {&lt;br /&gt;
          return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: titles.map(function (title, index) {&lt;br /&gt;
          var column = {&lt;br /&gt;
            title: title,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
            },&lt;br /&gt;
          };&lt;br /&gt;
&lt;br /&gt;
          if (index === 0) {&lt;br /&gt;
            column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
              var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
              if (!colorClasses) {&lt;br /&gt;
                return;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              colorClasses&lt;br /&gt;
                .split(/\s+/)&lt;br /&gt;
                .filter(Boolean)&lt;br /&gt;
                .forEach(function (className) {&lt;br /&gt;
                  cell.classList.add(className);&lt;br /&gt;
                });&lt;br /&gt;
            };&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  cellData +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
          } else if (index === 1) {&lt;br /&gt;
            column.render = function (cellData, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return renderPlayerGames(cellData);&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              if (type === &amp;quot;sp&amp;quot;) {&lt;br /&gt;
                return getPlainAcceptsValues(cellData);&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return cellData;&lt;br /&gt;
            };&lt;br /&gt;
&lt;br /&gt;
            if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
              column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
          } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
            column.render = {&lt;br /&gt;
              display: function (cellData) {&lt;br /&gt;
                return cellData;&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (cellData) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                var linkedValues;&lt;br /&gt;
                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                linkedValues = Array.from(&lt;br /&gt;
                  container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                  function (link) {&lt;br /&gt;
                    return link.textContent.trim();&lt;br /&gt;
                  },&lt;br /&gt;
                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                if (linkedValues.length) {&lt;br /&gt;
                  return linkedValues;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                blockValues = Array.from(&lt;br /&gt;
                  container.children,&lt;br /&gt;
                  function (element) {&lt;br /&gt;
                    return element.textContent.trim();&lt;br /&gt;
                  },&lt;br /&gt;
                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                return blockValues.length&lt;br /&gt;
                  ? blockValues&lt;br /&gt;
                  : getAcceptsValues(cellData);&lt;br /&gt;
              },&lt;br /&gt;
            };&lt;br /&gt;
            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          return column;&lt;br /&gt;
        }),&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
      var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        hiddenColumnIndexes,&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
    var table = this;&lt;br /&gt;
&lt;br /&gt;
    waitForTableToSettle(table, function () {&lt;br /&gt;
      if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var titles = [&lt;br /&gt;
        getFirstColumnName(table),&lt;br /&gt;
        &amp;quot;Developer&amp;quot;,&lt;br /&gt;
        &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
        &amp;quot;Genre&amp;quot;,&lt;br /&gt;
        &amp;quot;Platform&amp;quot;,&lt;br /&gt;
        &amp;quot;Mode&amp;quot;,&lt;br /&gt;
        &amp;quot;Released&amp;quot;,&lt;br /&gt;
        &amp;quot;Category&amp;quot;,&lt;br /&gt;
      ];&lt;br /&gt;
      var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
      var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
        return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
      });&lt;br /&gt;
      var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
      buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
      var dataTable = new DataTable(table, {&lt;br /&gt;
        columns: [&lt;br /&gt;
          {&lt;br /&gt;
            title: titles[0],&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
            render: function (data, type) {&lt;br /&gt;
              if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                return (&lt;br /&gt;
                  &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                  data +&lt;br /&gt;
                  &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                );&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              return data;&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: false,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
            render: {&lt;br /&gt;
              display: function (data) {&lt;br /&gt;
                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
              },&lt;br /&gt;
              sp: function (data) {&lt;br /&gt;
                return getGameModeValues(data);&lt;br /&gt;
              },&lt;br /&gt;
            },&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
            visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          {&lt;br /&gt;
            title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
            visible: false,&lt;br /&gt;
            render: getPlainSearchPaneRender(),&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              show: true,&lt;br /&gt;
              orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        ],&lt;br /&gt;
        layout: {&lt;br /&gt;
          topStart: null,&lt;br /&gt;
          topEnd: null,&lt;br /&gt;
          top2: {&lt;br /&gt;
            searchPanes: {&lt;br /&gt;
              cascadePanes: true,&lt;br /&gt;
              dtOpts: {&lt;br /&gt;
                scroller: false,&lt;br /&gt;
              },&lt;br /&gt;
              initCollapsed: true,&lt;br /&gt;
              layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
              columns: paneIndexes,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          top1: {&lt;br /&gt;
            search: {&lt;br /&gt;
              className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
        language: {&lt;br /&gt;
          search: &amp;quot;&amp;quot;,&lt;br /&gt;
          searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
          searchPanes: {&lt;br /&gt;
            title: {&lt;br /&gt;
              _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
              0: &amp;quot;&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        paging: false,&lt;br /&gt;
        searchDelay: 400,&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
      dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
        var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
        openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
        if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
        paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
          dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
        });&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      var filterPanel;&lt;br /&gt;
&lt;br /&gt;
      dataTable.rows.add(data).draw();&lt;br /&gt;
      $(table).removeClass(&amp;quot;dt-loading&amp;quot;).removeAttr(&amp;quot;aria-busy&amp;quot;).show();&lt;br /&gt;
      dataTable.searchPanes.rebuildPane();&lt;br /&gt;
      filterPanel = setupFilterOffCanvas(&lt;br /&gt;
        dataTable,&lt;br /&gt;
        table,&lt;br /&gt;
        titles,&lt;br /&gt;
        hiddenColumnIndexes,&lt;br /&gt;
      );&lt;br /&gt;
      suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
      dataTable.columns.adjust().draw(false);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2766</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2766"/>
		<updated>2026-08-12T07:20:07Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        #players .player-games {&lt;br /&gt;
          align-items: baseline;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-wrap: wrap;&lt;br /&gt;
          gap: 0.25rem 0.5rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__more {&lt;br /&gt;
          display: inline-block;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle {&lt;br /&gt;
          background: none;&lt;br /&gt;
          color: var(--bs-link-color, #6ea8fe);&lt;br /&gt;
          cursor: pointer;&lt;br /&gt;
          font-size: 0.875em;&lt;br /&gt;
          list-style: none;&lt;br /&gt;
          padding: 0;&lt;br /&gt;
          white-space: nowrap;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle::-webkit-details-marker {&lt;br /&gt;
          display: none;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__toggle:hover,&lt;br /&gt;
        #players .player-games__toggle:focus {&lt;br /&gt;
          text-decoration: underline;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__popup {&lt;br /&gt;
          background: var(--bs-body-bg, #11161b);&lt;br /&gt;
          border: 1px solid rgba(255, 255, 255, 0.25) !important;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);&lt;br /&gt;
          color: var(--bs-body-color, #fff);&lt;br /&gt;
          left: 0;&lt;br /&gt;
          min-width: max-content;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: calc(100% + 0.25rem);&lt;br /&gt;
          z-index: 20;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #players .player-games__popup &amp;gt; div + div {&lt;br /&gt;
          margin-top: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function renderPlayerGames(html) {&lt;br /&gt;
        var games = getAcceptsValues(html);&lt;br /&gt;
&lt;br /&gt;
        if (games.length &amp;lt; 2) {&lt;br /&gt;
            return games[0] || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return (&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;player-games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;span class=&amp;quot;player-games__first&amp;quot;&amp;gt;&#039; + games[0] + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot; +&lt;br /&gt;
            &#039;&amp;lt;details class=&amp;quot;player-games__more&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            &#039;&amp;lt;summary class=&amp;quot;player-games__toggle&amp;quot;&amp;gt;+&#039; +&lt;br /&gt;
            (games.length - 1) +&lt;br /&gt;
            &amp;quot; more&amp;lt;/summary&amp;gt;&amp;quot; +&lt;br /&gt;
            &#039;&amp;lt;div class=&amp;quot;player-games__popup&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Other games&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
            games.slice(1).map(function (game) {&lt;br /&gt;
                return &amp;quot;&amp;lt;div&amp;gt;&amp;quot; + game + &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
            }).join(&amp;quot;&amp;quot;) +&lt;br /&gt;
            &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;/details&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (index === 1) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return renderPlayerGames(cellData);&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            if (type === &amp;quot;sp&amp;quot;) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
&lt;br /&gt;
                        if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2762</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2762"/>
		<updated>2026-08-11T09:05:32Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		local target = link:match(&amp;quot;^%[%[([^|%]]+)&amp;quot;)&lt;br /&gt;
		local subpage = target and target:match(&amp;quot;/([^/]+)$&amp;quot;)&lt;br /&gt;
		local label = subpage and labels[subpage]&lt;br /&gt;
&lt;br /&gt;
		if label then&lt;br /&gt;
			results[i] = string.format(&amp;quot;[[%s|%s]]&amp;quot;, target, label)&lt;br /&gt;
		else&lt;br /&gt;
			results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(existingLabel)&lt;br /&gt;
				return &amp;quot;|&amp;quot; .. (labels[existingLabel] or existingLabel) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
			end)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local hasStatus = formatCellValue(row[&amp;quot;Has status&amp;quot;])&lt;br /&gt;
		local statusClass = hasStatus == &amp;quot;Active&amp;quot; and &amp;quot;text-success&amp;quot; or &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(statusClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	--[[&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
	]]--&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	-- html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	--[[&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
	]]--&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	-- html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	--[[&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
	]]--&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	-- html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &amp;quot;+&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	--[[&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
	]]--&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	-- html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2758</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2758"/>
		<updated>2026-08-10T12:00:42Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (index === 1) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return getAcceptsValues(cellData)[0] || &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            if (type === &amp;quot;sp&amp;quot;) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
&lt;br /&gt;
                        if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                            column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                        }&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2757</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2757"/>
		<updated>2026-08-10T11:57:12Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: true,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return getAcceptsValues(cellData)[0] || &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            if (type === &amp;quot;sp&amp;quot;) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2756</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2756"/>
		<updated>2026-08-10T11:52:55Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2755</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2755"/>
		<updated>2026-08-10T11:51:44Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Main_Page&amp;diff=2751</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Main_Page&amp;diff=2751"/>
		<updated>2026-08-07T15:35:33Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Welcome to the PC Gaming Shelter  =&lt;br /&gt;
&amp;lt;p class=&amp;quot;my-4&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Welcome to the PC Gaming Shelter. This archive is currently under technical reconstruction.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p class=&amp;quot;my-4&amp;quot;&amp;gt;&lt;br /&gt;
The PC Gaming Shelter is a community-driven archive dedicated to preserving PC gaming history. Since the loss of legendary repositories like Filefront and Gamespy, much of our shared digital heritage has become difficult to find. This wiki serves as a central home for that &amp;quot;lost&amp;quot; information, documenting everything from classic maps, skins, and mods in The Vault to the stories of the developers and players who shaped the industry. &lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
{{Thumbwall&lt;br /&gt;
|show thumbs=0&lt;br /&gt;
|Game Genres&lt;br /&gt;
|label1=Action&lt;br /&gt;
|image1=NewIcon_Action.png&lt;br /&gt;
|label2=Adventure&lt;br /&gt;
|image2=NewIcon_Adventure-alternative.png&lt;br /&gt;
|label3=MMO&lt;br /&gt;
|image3=NewIcon_MMO.png&lt;br /&gt;
|label4=Racing&lt;br /&gt;
|image4=NewIcon_Racing.png&lt;br /&gt;
|label5=RPG&lt;br /&gt;
|image5=NewIcon_RPG.png&lt;br /&gt;
|label6=Shooter&lt;br /&gt;
|image6=NewIcon_Shooter.png&lt;br /&gt;
|label7=Simulation&lt;br /&gt;
|image7=NewIcon_Simulation.png&lt;br /&gt;
|label8=Sport&lt;br /&gt;
|image8=NewIcon_Sport.png&lt;br /&gt;
|label9=Strategy&lt;br /&gt;
|image9=NewIcon_Strategy.png&lt;br /&gt;
|label10=Survival&lt;br /&gt;
|image10=NewIcon_Survival.png&lt;br /&gt;
|label11=Platform&lt;br /&gt;
|image11=NewIcon_Platform.png&lt;br /&gt;
|label12=Sandbox&lt;br /&gt;
|image12=NewIcon_Sandbox.png&lt;br /&gt;
}}&lt;br /&gt;
{{Thumbwall&lt;br /&gt;
|show thumbs=0&lt;br /&gt;
|Mods, Players &amp;amp; Communities&lt;br /&gt;
|label1=Players&lt;br /&gt;
|image1=NewIcon_Player.png&lt;br /&gt;
|label2=Community&lt;br /&gt;
|image2=NewIcon_Community.png&lt;br /&gt;
|target2=Active Communities&lt;br /&gt;
|label3=Media&lt;br /&gt;
|image3=NewIcon_Media.png&lt;br /&gt;
|label4=Mods&lt;br /&gt;
|image4=NewIcon_Mods.png&lt;br /&gt;
|label5=Events&lt;br /&gt;
|image5=NewIcon_Events.png&lt;br /&gt;
|target5=Event Calendar&lt;br /&gt;
|label6=Dead Places&lt;br /&gt;
|image6=NewIcon_DeadPlaces.png&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;d-flex flex-column flex-cmln-row&amp;quot; style=&amp;quot;gap: .5rem&amp;quot;&amp;gt;&lt;br /&gt;
{{Thumbwall&lt;br /&gt;
|show thumbs=0&lt;br /&gt;
|20 Latest changes&lt;br /&gt;
|free text={{#tag: rss|{{int:shelter-recent-changes}}|max=20}}&lt;br /&gt;
|footer=&lt;br /&gt;
&amp;lt;span class=&amp;quot;thumbwall-scroll&amp;quot; type=&amp;quot;button&amp;quot; data-scroll-dir=&amp;quot;-1&amp;quot; aria-label=&amp;quot;Scroll latest changes up&amp;quot;&amp;gt;&amp;amp;#8249;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;thumbwall-scroll&amp;quot; type=&amp;quot;button&amp;quot; data-scroll-dir=&amp;quot;1&amp;quot; aria-label=&amp;quot;Scroll latest changes down&amp;quot;&amp;gt;&amp;amp;#8250;&amp;lt;/span&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
{{Thumbwall&lt;br /&gt;
|show thumbs=0&lt;br /&gt;
|20 Last created pages&lt;br /&gt;
|free text={{#tag: rss|{{int:shelter-new-pages}}|max=20}}&lt;br /&gt;
|footer=&lt;br /&gt;
&amp;lt;span class=&amp;quot;thumbwall-scroll&amp;quot; type=&amp;quot;button&amp;quot; data-scroll-dir=&amp;quot;-1&amp;quot; aria-label=&amp;quot;Scroll new pages up&amp;quot;&amp;gt;&amp;amp;#8249;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;thumbwall-scroll&amp;quot; type=&amp;quot;button&amp;quot; data-scroll-dir=&amp;quot;1&amp;quot; aria-label=&amp;quot;Scroll new pages down&amp;quot;&amp;gt;&amp;amp;#8250;&amp;lt;/span&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{Thumbwall&lt;br /&gt;
|show thumbs=0&lt;br /&gt;
|title=Statistics &amp;lt;span class=&amp;quot;float-right text-muted&amp;quot;&amp;gt; Archive Size: &amp;lt;span class=&amp;quot;stat-badge&amp;quot;&amp;gt;35G&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
|label1=Games &amp;lt;span class=&amp;quot;stat-badge&amp;quot;&amp;gt;164&amp;lt;/span&amp;gt;&lt;br /&gt;
|image1=NewIcon_Games-documented.png&lt;br /&gt;
|target1=Games&lt;br /&gt;
|label2=Files &amp;lt;span class=&amp;quot;stat-badge&amp;quot;&amp;gt;732&amp;lt;/span&amp;gt;&lt;br /&gt;
|image2=NewIcon_Files.png&lt;br /&gt;
|target2=Special:ListFiles&lt;br /&gt;
|label3=Guardians &amp;lt;span class=&amp;quot;stat-badge&amp;quot;&amp;gt;14&amp;lt;/span&amp;gt;&lt;br /&gt;
|image3=NewIcon_Guardians.png&lt;br /&gt;
|target3=Guardians&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;to-info-panel&amp;quot;&amp;gt;{{upcoming events}}&lt;br /&gt;
{{#ask: &lt;br /&gt;
[[Featured:+]]&lt;br /&gt;
[[Featured date::&amp;gt;{{#time:Y-m-01}}]]&lt;br /&gt;
[[Featured date::&amp;lt;{{#time:Y-m-t}}]]&lt;br /&gt;
[[Has featured category::Video of the Month||Picture of the Month]] &lt;br /&gt;
|format=embedded&lt;br /&gt;
|embedonly=yes&lt;br /&gt;
|default=&amp;lt;div class=&amp;quot;text-center&amp;quot;&amp;gt;No featured media has been archived yet.&amp;lt;/div&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Common.css&amp;diff=2750</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Common.css&amp;diff=2750"/>
		<updated>2026-08-07T15:34:48Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* CSS placed here will be applied to all skins */&lt;br /&gt;
&lt;br /&gt;
/* Hide user menu icon for anonymous */&lt;br /&gt;
.personal-tools-icon {&lt;br /&gt;
	display: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox-value ul {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#rightMenu #p-contentnavigation.pagetools .tab-group &amp;gt; div#ca-talk {&lt;br /&gt;
	display: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.card.thumbwall {&lt;br /&gt;
	flex: 1;&lt;br /&gt;
}&lt;br /&gt;
.card.thumbwall .card-img img {&lt;br /&gt;
	height: 100% !important;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall .card-footer {&lt;br /&gt;
	border-top: 1px solid rgba(255,255,255,0.05);&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll {&lt;br /&gt;
	font-size: 2.5rem;&lt;br /&gt;
	line-height: 0.35;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	flex: 1;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll[data-scroll-dir=&amp;quot;1&amp;quot;] {&lt;br /&gt;
	float: right;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll:disabled,&lt;br /&gt;
.thumbwall-scroll.is-inactive {&lt;br /&gt;
    opacity: .4;&lt;br /&gt;
    cursor: default;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.collab-icons {&lt;br /&gt;
	margin-top: .25rem !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navthumb a:hover {&lt;br /&gt;
	text-decoration: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Embed video **/&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader__fakeButton {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  width: 4rem;&lt;br /&gt;
  height: 4rem;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  border-radius: 50%;&lt;br /&gt;
  background: rgba(0, 0, 0, 0.72);&lt;br /&gt;
  color: transparent;&lt;br /&gt;
  font-size: 0;&lt;br /&gt;
  line-height: 0;&lt;br /&gt;
  place-items: center;&lt;br /&gt;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.35);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader__fakeButton::before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  margin-left: 0.25rem;&lt;br /&gt;
  border-top: 0.75rem solid transparent;&lt;br /&gt;
  border-bottom: 0.75rem solid transparent;&lt;br /&gt;
  border-left: 1.1rem solid #fff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader:hover .embedvideo-loader__fakeButton {&lt;br /&gt;
  background: #e26e1f;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.two-cards &amp;gt; div {&lt;br /&gt;
	flex: 1 1 50%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.page-Special_RunQuery_FeaturedLink .pf-runquery-formcontent,&lt;br /&gt;
.page-Special_RunQuery_FeaturedLink .dayInput {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.gap-2 {&lt;br /&gt;
	gap: .5rem;&lt;br /&gt;
}&lt;br /&gt;
.card .navthumb {&lt;br /&gt;
	min-width: 20%;&lt;br /&gt;
}&lt;br /&gt;
.card-body .navthumb .with-icon a {&lt;br /&gt;
	display: flex !important;&lt;br /&gt;
    height: 100%;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	justify-content: center;&lt;br /&gt;
	min-height: 45px !important;&lt;br /&gt;
	align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#tab-content-smw-property-constraint {&lt;br /&gt;
  filter: invert(1) hue-rotate(180deg) contrast(.8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#games &amp;gt; table {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.upcoming-event-row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  min-height: 56px;&lt;br /&gt;
  gap: 0 1rem;&lt;br /&gt;
  font-weight: 500;&lt;br /&gt;
  text-shadow: 0 0 10px var(--light);&lt;br /&gt;
  line-height: 1.15;&lt;br /&gt;
  scroll-snap-align: start;&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .shelter-stats-item-name {&lt;br /&gt;
	min-height: 40px;&lt;br /&gt;
	font-weight: 500;&lt;br /&gt;
	text-shadow: 0 0 10px var(--light);&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .shelter-stats-item-name a {&lt;br /&gt;
	color: var(--light);&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-date {&lt;br /&gt;
	color: var(--shelter-accent-light); &lt;br /&gt;
	font-size: 1.25rem;&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .smw-subobject-entity {&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
}&lt;br /&gt;
.to-info-panel {&lt;br /&gt;
	visibility: hidden;&lt;br /&gt;
	width: 300px;&lt;br /&gt;
}&lt;br /&gt;
@media all and ( max-width: 576px ) {&lt;br /&gt;
	.to-info-panel {&lt;br /&gt;
		width: 100%;&lt;br /&gt;
	}	&lt;br /&gt;
}&lt;br /&gt;
#bottom-notice .to-info-panel {&lt;br /&gt;
	visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
.stat-badge {&lt;br /&gt;
  padding: .125rem .5rem;&lt;br /&gt;
  color: #d2a383;&lt;br /&gt;
  font-size: 1.25rem;&lt;br /&gt;
}&lt;br /&gt;
.rss-item .external:visited,&lt;br /&gt;
.rss-item .external {&lt;br /&gt;
	color: #81beff !important;&lt;br /&gt;
	font-weight: 500;&lt;br /&gt;
}&lt;br /&gt;
.card-body:has(.rss-item) {&lt;br /&gt;
	height: 250px;&lt;br /&gt;
	overflow-y: scroll;&lt;br /&gt;
    scroll-behavior: smooth;&lt;br /&gt;
    scroll-snap-type: y mandatory;&lt;br /&gt;
    scroll-padding-block: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.thumbwall .rss-item {&lt;br /&gt;
    min-height: 64px;&lt;br /&gt;
    scroll-snap-align: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.oo-ui-messageWidget.oo-ui-messageWidget-block.oo-ui-flaggedElement-success {&lt;br /&gt;
	background-color: #005234;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ns-3002 #mw-content-text &amp;gt; .mw-parser-output:first-of-type {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	flex-direction: column;&lt;br /&gt;
}&lt;br /&gt;
@media screen and ( min-width: 576px ) {&lt;br /&gt;
	.ns-3002 #mw-content-text &amp;gt; .mw-parser-output:first-of-type {&lt;br /&gt;
		flex-direction: row-reverse;&lt;br /&gt;
		gap: 1rem;&lt;br /&gt;
	}	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.checkboxSwitches {&lt;br /&gt;
	min-height: 49px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* RESOURCES LIST */&lt;br /&gt;
.resources-header {&lt;br /&gt;
	background-color: rgba(255,255,255,.1);&lt;br /&gt;
	padding: 0 1rem;&lt;br /&gt;
}&lt;br /&gt;
@media screen and ( min-width: 576px ) {&lt;br /&gt;
	.resources-header {&lt;br /&gt;
		flex: 0 0 100px;&lt;br /&gt;
		border-right: 1px solid var(--secondary);&lt;br /&gt;
		padding: 0 .5rem;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infoMessage.mainForms,&lt;br /&gt;
.infoMessage.otherForms {&lt;br /&gt;
	background-color: var(--bg-shade-4);&lt;br /&gt;
	border: 0;&lt;br /&gt;
}&lt;br /&gt;
.infoMessage.otherForms, .infoMessage ~ p {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Common.css&amp;diff=2749</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Common.css&amp;diff=2749"/>
		<updated>2026-08-07T15:32:14Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* CSS placed here will be applied to all skins */&lt;br /&gt;
&lt;br /&gt;
/* Hide user menu icon for anonymous */&lt;br /&gt;
.personal-tools-icon {&lt;br /&gt;
	display: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox-value ul {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#rightMenu #p-contentnavigation.pagetools .tab-group &amp;gt; div#ca-talk {&lt;br /&gt;
	display: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.card.thumbwall {&lt;br /&gt;
	flex: 1;&lt;br /&gt;
}&lt;br /&gt;
.card.thumbwall .card-img img {&lt;br /&gt;
	height: 100% !important;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall .card-footer {&lt;br /&gt;
	border-top: 1px solid rgba(255,255,255,0.05);&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll {&lt;br /&gt;
	font-size: 2.5rem;&lt;br /&gt;
	line-height: 0.35;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	flex: 1;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll[data-scroll-dir=&amp;quot;1&amp;quot;] {&lt;br /&gt;
	float: right;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;br /&gt;
.thumbwall-scroll:disabled,&lt;br /&gt;
.thumbwall-scroll.is-inactive {&lt;br /&gt;
    opacity: .4;&lt;br /&gt;
    cursor: default;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.collab-icons {&lt;br /&gt;
	margin-top: .25rem !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navthumb a:hover {&lt;br /&gt;
	text-decoration: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Embed video **/&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader__fakeButton {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  width: 4rem;&lt;br /&gt;
  height: 4rem;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  border-radius: 50%;&lt;br /&gt;
  background: rgba(0, 0, 0, 0.72);&lt;br /&gt;
  color: transparent;&lt;br /&gt;
  font-size: 0;&lt;br /&gt;
  line-height: 0;&lt;br /&gt;
  place-items: center;&lt;br /&gt;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.35);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader__fakeButton::before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  margin-left: 0.25rem;&lt;br /&gt;
  border-top: 0.75rem solid transparent;&lt;br /&gt;
  border-bottom: 0.75rem solid transparent;&lt;br /&gt;
  border-left: 1.1rem solid #fff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.embedvideo-loader:hover .embedvideo-loader__fakeButton {&lt;br /&gt;
  background: #e26e1f;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.two-cards &amp;gt; div {&lt;br /&gt;
	flex: 1 1 50%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.page-Special_RunQuery_FeaturedLink .pf-runquery-formcontent,&lt;br /&gt;
.page-Special_RunQuery_FeaturedLink .dayInput {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.gap-2 {&lt;br /&gt;
	gap: .5rem;&lt;br /&gt;
}&lt;br /&gt;
.card .navthumb {&lt;br /&gt;
	min-width: 20%;&lt;br /&gt;
}&lt;br /&gt;
.card-body .navthumb .with-icon a {&lt;br /&gt;
	display: flex !important;&lt;br /&gt;
    height: 100%;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	justify-content: center;&lt;br /&gt;
	min-height: 45px !important;&lt;br /&gt;
	align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#tab-content-smw-property-constraint {&lt;br /&gt;
  filter: invert(1) hue-rotate(180deg) contrast(.8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#games &amp;gt; table {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.upcoming-event-row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  min-height: 56px;&lt;br /&gt;
  gap: 0 1rem;&lt;br /&gt;
  font-weight: 500;&lt;br /&gt;
  text-shadow: 0 0 10px var(--light);&lt;br /&gt;
  line-height: 1.15;&lt;br /&gt;
  scroll-snap-align: start;&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .shelter-stats-item-name {&lt;br /&gt;
	min-height: 40px;&lt;br /&gt;
	font-weight: 500;&lt;br /&gt;
	text-shadow: 0 0 10px var(--light);&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .shelter-stats-item-name a {&lt;br /&gt;
	color: var(--light);&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-date {&lt;br /&gt;
	color: var(--shelter-accent-light); &lt;br /&gt;
	font-size: 1.25rem;&lt;br /&gt;
}&lt;br /&gt;
.upcoming-event-row .smw-subobject-entity {&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
}&lt;br /&gt;
.to-info-panel {&lt;br /&gt;
	visibility: hidden;&lt;br /&gt;
	width: 300px;&lt;br /&gt;
}&lt;br /&gt;
@media all and ( max-width: 576px ) {&lt;br /&gt;
	.to-info-panel {&lt;br /&gt;
		width: 100%;&lt;br /&gt;
	}	&lt;br /&gt;
}&lt;br /&gt;
#bottom-notice .to-info-panel {&lt;br /&gt;
	visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
.stat-badge {&lt;br /&gt;
  padding: .125rem .5rem;&lt;br /&gt;
  color: #d2a383;&lt;br /&gt;
  font-size: 1.25rem;&lt;br /&gt;
}&lt;br /&gt;
.rss-item .external:visited,&lt;br /&gt;
.rss-item .external {&lt;br /&gt;
	color: #81beff !important;&lt;br /&gt;
	font-weight: 500;&lt;br /&gt;
}&lt;br /&gt;
.card-body:has(.rss-item) {&lt;br /&gt;
	height: 250px;&lt;br /&gt;
	overflow-y: scroll;&lt;br /&gt;
    scroll-behavior: smooth;&lt;br /&gt;
    scroll-snap-type: y mandatory;&lt;br /&gt;
    scroll-padding-block: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.thumbwall .rss-item {&lt;br /&gt;
    min-height: 64px;&lt;br /&gt;
    scroll-snap-align: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.oo-ui-messageWidget.oo-ui-messageWidget-block.oo-ui-flaggedElement-success {&lt;br /&gt;
	background-color: #005234;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ns-3002 #mw-content-text &amp;gt; .mw-parser-output:first-of-type {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	flex-direction: column;&lt;br /&gt;
}&lt;br /&gt;
@media screen and ( min-width: 576px ) {&lt;br /&gt;
	.ns-3002 #mw-content-text &amp;gt; .mw-parser-output:first-of-type {&lt;br /&gt;
		flex-direction: row-reverse;&lt;br /&gt;
		gap: 1rem;&lt;br /&gt;
	}	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.checkboxSwitches {&lt;br /&gt;
	min-height: 49px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* RESOURCES LIST */&lt;br /&gt;
.resources-header {&lt;br /&gt;
	background-color: rgba(255,255,255,.1);&lt;br /&gt;
	padding: 0 1rem;&lt;br /&gt;
}&lt;br /&gt;
@media screen and ( min-width: 576px ) {&lt;br /&gt;
	.resources-header {&lt;br /&gt;
		flex: 0 0 100px;&lt;br /&gt;
		border-right: 1px solid var(--secondary);&lt;br /&gt;
		padding: 0 .5rem;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infoMessage.mainForms,&lt;br /&gt;
.infoMessage.otherForms {&lt;br /&gt;
	background-color: var(--bg-shade-4);&lt;br /&gt;
	border: 0;&lt;br /&gt;
}&lt;br /&gt;
.infoMessage.otherForms {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2748</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2748"/>
		<updated>2026-08-06T13:10:40Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var clanColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0] ? row.cells[0].className : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        createdCell: function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = clanColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        },&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2747</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2747"/>
		<updated>2026-08-06T13:10:25Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		local target = link:match(&amp;quot;^%[%[([^|%]]+)&amp;quot;)&lt;br /&gt;
		local subpage = target and target:match(&amp;quot;/([^/]+)$&amp;quot;)&lt;br /&gt;
		local label = subpage and labels[subpage]&lt;br /&gt;
&lt;br /&gt;
		if label then&lt;br /&gt;
			results[i] = string.format(&amp;quot;[[%s|%s]]&amp;quot;, target, label)&lt;br /&gt;
		else&lt;br /&gt;
			results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(existingLabel)&lt;br /&gt;
				return &amp;quot;|&amp;quot; .. (labels[existingLabel] or existingLabel) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
			end)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local hasStatus = formatCellValue(row[&amp;quot;Has status&amp;quot;])&lt;br /&gt;
		local statusClass = hasStatus == &amp;quot;Active&amp;quot; and &amp;quot;text-success&amp;quot; or &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(statusClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &amp;quot;+&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2746</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2746"/>
		<updated>2026-08-06T13:07:07Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1, 4];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                data: data,&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2745</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2745"/>
		<updated>2026-08-06T13:05:32Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		local target = link:match(&amp;quot;^%[%[([^|%]]+)&amp;quot;)&lt;br /&gt;
		local subpage = target and target:match(&amp;quot;/([^/]+)$&amp;quot;)&lt;br /&gt;
		local label = subpage and labels[subpage]&lt;br /&gt;
&lt;br /&gt;
		if label then&lt;br /&gt;
			results[i] = string.format(&amp;quot;[[%s|%s]]&amp;quot;, target, label)&lt;br /&gt;
		else&lt;br /&gt;
			results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(existingLabel)&lt;br /&gt;
				return &amp;quot;|&amp;quot; .. (labels[existingLabel] or existingLabel) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
			end)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &amp;quot;+&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2744</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2744"/>
		<updated>2026-08-06T13:04:09Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		local target = link:match(&amp;quot;^%[%[([^|%]]+)&amp;quot;)&lt;br /&gt;
		local subpage = target and target:match(&amp;quot;/([^/]+)$&amp;quot;)&lt;br /&gt;
		local label = subpage and labels[subpage]&lt;br /&gt;
&lt;br /&gt;
		if label then&lt;br /&gt;
			results[i] = string.format(&amp;quot;[[%s|%s]]&amp;quot;, target, label)&lt;br /&gt;
		else&lt;br /&gt;
			results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(existingLabel)&lt;br /&gt;
				return &amp;quot;|&amp;quot; .. (labels[existingLabel] or existingLabel) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
			end)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &amp;quot;+&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2743</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2743"/>
		<updated>2026-08-06T13:00:25Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
					{&lt;br /&gt;
                        title: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2742</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2742"/>
		<updated>2026-08-06T12:03:21Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2741</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2741"/>
		<updated>2026-08-06T12:02:04Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Status&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            &lt;br /&gt;
            function isInCommunitiesCategory() {&lt;br /&gt;
    			const categories = mw.config.get(&amp;quot;wgCategories&amp;quot;) || [];&lt;br /&gt;
    			return categories.includes(&amp;quot;Communities&amp;quot;);&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if (isInCommunitiesCategory()) {&lt;br /&gt;
				paneIndexes = [1, 4];&lt;br /&gt;
    		}&lt;br /&gt;
    		&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2740</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2740"/>
		<updated>2026-08-06T11:56:55Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &#039;+&#039;&lt;br /&gt;
	&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2739</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2739"/>
		<updated>2026-08-06T11:45:03Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                            container.querySelectorAll(&amp;quot;a.external[href]&amp;quot;).forEach(function (link) {&lt;br /&gt;
                                var hostname;&lt;br /&gt;
&lt;br /&gt;
                                try {&lt;br /&gt;
                                    hostname = new URL(link.href, window.location.href).hostname;&lt;br /&gt;
                                } catch (error) {&lt;br /&gt;
                                    hostname = &amp;quot;&amp;quot;;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if (hostname) {&lt;br /&gt;
                                    link.textContent = hostname.replace(/^www\./i, &amp;quot;&amp;quot;);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return container.innerHTML;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2738</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2738"/>
		<updated>2026-08-06T11:41:20Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set()&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Dead_Communities&amp;diff=2737</id>
		<title>Dead Communities</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Dead_Communities&amp;diff=2737"/>
		<updated>2026-08-06T11:38:01Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: /* The Archives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Navigation:&#039;&#039;&#039; [[Active Communities|Active Communities]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This archive is dedicated to the communities, clans, and guilds that are no longer active. We preserve their names, their members and their achievements so they are not forgotten by time.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== The Archives ==&lt;br /&gt;
{{#invoke:Universe|allClans|hasStatus=Not Active}}&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE: Historical Communities &amp;amp; Dead Clans}}&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2736</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2736"/>
		<updated>2026-08-06T11:36:23Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]]&amp;quot; .. &amp;quot;[[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args.hasStatus or &#039;+&#039;&lt;br /&gt;
	&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Active_Communities&amp;diff=2735</id>
		<title>Active Communities</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Active_Communities&amp;diff=2735"/>
		<updated>2026-08-06T11:35:48Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&#039;&#039;&#039;Navigation:&#039;&#039;&#039; [[Players|Players]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This directory features gaming communities, clans, and groups that are currently active. For groups that are no longer operational, please visit the [[Dead_Communities|Historical Archive]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Active Groups ==&lt;br /&gt;
{{#invoke:Universe|allClans|hasStatus=Active}}&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE:Active Communities &amp;amp; Clans (Guilds)}}&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MyClanName&amp;diff=2734</id>
		<title>MyClanName</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MyClanName&amp;diff=2734"/>
		<updated>2026-08-06T11:35:11Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Community&lt;br /&gt;
|Related game=Half-Life&lt;br /&gt;
|Has status=Not Active&lt;br /&gt;
|Year active from=2017&lt;br /&gt;
|Has short description=This is a brief / essential note about the clan.&lt;br /&gt;
|Community links={{Community link&lt;br /&gt;
|URL=https://discord.com/&lt;br /&gt;
|Link text=Discord&lt;br /&gt;
|Link group=Community links&lt;br /&gt;
}}{{Community link&lt;br /&gt;
|URL=https://www.patreon.com/&lt;br /&gt;
|Link text=Patreon&lt;br /&gt;
|Link group=Community links&lt;br /&gt;
}}{{Community link&lt;br /&gt;
|URL=https://halflife.fandom.com/es/wiki/Portada&lt;br /&gt;
|Link text=Fandom HL (es)&lt;br /&gt;
|Link group=Community links&lt;br /&gt;
}}&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2733</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2733"/>
		<updated>2026-08-06T11:33:16Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]]&amp;quot; .. &amp;quot;[[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args[&#039;Has status&#039;] or &#039;+&#039;&lt;br /&gt;
	&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2732</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2732"/>
		<updated>2026-08-06T11:32:10Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]]&amp;quot; .. &amp;quot;[[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local hasStatus = args[&#039;Has status&#039;]&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2731</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2731"/>
		<updated>2026-08-06T11:29:32Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var clanSelectors = [&lt;br /&gt;
    &amp;quot;#clans table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors, clanSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(clanSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Clan&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Links&amp;quot;, &amp;quot;Description&amp;quot;];&lt;br /&gt;
            var paneIndexes = [1];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Clan&amp;quot;,&lt;br /&gt;
                        render: function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Links&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Description&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search clans&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
                dataTable.searchPanes.rebuildPane(1, true);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                new Set([1])&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2730</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2730"/>
		<updated>2026-08-06T11:29:18Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;clans&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Community links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]]&amp;quot; .. &amp;quot;[[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame, hasStatus)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Has status::&amp;quot; .. hasStatus .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Community links&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2729</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2729"/>
		<updated>2026-08-06T11:22:42Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]]&amp;quot; ..&lt;br /&gt;
		&amp;quot;[[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allClans(frame, hasStatus)&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&#039;[[Category:Communities]][[Has status::&#039; ..hasStatus .. &#039;]]&#039;,&lt;br /&gt;
		&#039;?Related game&#039;,&lt;br /&gt;
		&#039;?Community links&#039;,&lt;br /&gt;
		&#039;?Has short description&#039;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Has status]=&amp;quot; .. hasStatus,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderClanTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Template:Infobox/Community_Info&amp;diff=2728</id>
		<title>Template:Infobox/Community Info</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Template:Infobox/Community_Info&amp;diff=2728"/>
		<updated>2026-08-06T11:12:57Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if: {{{Related game|}}}&lt;br /&gt;
  |{{Infobox/Generic&lt;br /&gt;
     |Game&lt;br /&gt;
     |{{{Related game|}}}&lt;br /&gt;
     |links=1&lt;br /&gt;
     |multiple=1&lt;br /&gt;
     |form=Game&lt;br /&gt;
   }}&lt;br /&gt;
}}&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;{{#if: {{{Has status|}}}&lt;br /&gt;
  |{{Infobox/Generic&lt;br /&gt;
     |Status&lt;br /&gt;
     |{{{Has status|}}}&lt;br /&gt;
     |links=0&lt;br /&gt;
     |indicator={{#switch:{{{Has status|}}}|Active=green|#default=gray}}&lt;br /&gt;
   }}&lt;br /&gt;
}}&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;{{#if: {{{Year active from|}}}{{{Year active until|}}}&lt;br /&gt;
  |{{Infobox/Generic&lt;br /&gt;
     |Years&lt;br /&gt;
     |{{#invoke:Community|yearsActive|from={{{Year active from|}}}|until={{{Year active until|}}}}}&lt;br /&gt;
     |links=0&lt;br /&gt;
   }}&lt;br /&gt;
}}&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
@WikiVisor: Actually, unneccesary, since we have categorized them already as &amp;quot;Communities&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;{{set category|Clans}}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Community&amp;diff=2727</id>
		<title>Module:Community</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Community&amp;diff=2727"/>
		<updated>2026-08-06T11:10:40Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require( &#039;Module:Utils&#039; )&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function propertiesPlan()&lt;br /&gt;
	-- [&#039;Form field name&#039;] = { &#039;Semantic property&#039;, &#039;delimiter&#039; }&lt;br /&gt;
	local propMap = {&lt;br /&gt;
		[&#039;Image&#039;]               = {&#039;Image&#039;, &#039;file&#039; },&lt;br /&gt;
		[&#039;Related game&#039;]        = {&#039;Related game&#039;, &#039;,&#039; },&lt;br /&gt;
		[&#039;Has status&#039;]          = {&#039;Has status&#039; },&lt;br /&gt;
		[&#039;Has short description&#039;] = {&#039;Has short description&#039; }&lt;br /&gt;
	}&lt;br /&gt;
	return propMap&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function infoboxSectionPlan()&lt;br /&gt;
	local sectionMap = {&lt;br /&gt;
		[&#039;Cover image&#039;] = {&lt;br /&gt;
			heading = &#039;&#039;,&lt;br /&gt;
			template = &#039;Infobox/Cover&#039;,&lt;br /&gt;
			order = &#039;1&#039;,&lt;br /&gt;
			rows = {&lt;br /&gt;
				&#039;Image&#039;&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
		[&#039;Clan Info&#039;] = {&lt;br /&gt;
			heading = &#039;Community Info&#039;,&lt;br /&gt;
			template = &#039;Infobox/Community Info&#039;,&lt;br /&gt;
			order = &#039;2&#039;,&lt;br /&gt;
			rows = {&lt;br /&gt;
				&#039;Related game&#039;,&lt;br /&gt;
				&#039;Has status&#039;,&lt;br /&gt;
				&#039;Year active from&#039;,&lt;br /&gt;
				&#039;Year active until&#039;,&lt;br /&gt;
				&#039;Has short description&#039;&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
		[&#039;Community links&#039;] = {&lt;br /&gt;
			heading = &#039;Join&#039;,&lt;br /&gt;
			template = &#039;Infobox/Community links&#039;,&lt;br /&gt;
			order = &#039;3&#039;,&lt;br /&gt;
			rows = {&lt;br /&gt;
				&#039;Community links&#039;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return sectionMap&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.infobox(frame)&lt;br /&gt;
	local category   = &#039;Communities&#039;&lt;br /&gt;
	local properties = propertiesPlan()&lt;br /&gt;
	local sections   = infoboxSectionPlan()&lt;br /&gt;
	local footer     = &#039;Community footer&#039;&lt;br /&gt;
	local infobox    = utils.createInfobox(frame, category, properties, sections, footer)&lt;br /&gt;
	return infobox&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.yearsActive(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local from = utils.clean(args[&#039;from&#039;])&lt;br /&gt;
	local until_year = utils.clean(args[&#039;until&#039;])&lt;br /&gt;
&lt;br /&gt;
	local result&lt;br /&gt;
&lt;br /&gt;
	if from and until_year then&lt;br /&gt;
		if from == until_year then&lt;br /&gt;
			result = from&lt;br /&gt;
		else&lt;br /&gt;
			result = from .. &#039;–&#039; .. until_year&lt;br /&gt;
		end&lt;br /&gt;
	elseif from then&lt;br /&gt;
		result = from .. &#039;–present&#039;&lt;br /&gt;
	elseif until_year then&lt;br /&gt;
		result = &#039;until &#039; .. until_year&lt;br /&gt;
	else&lt;br /&gt;
		return &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&#039;Has activity period&#039;] = result,&lt;br /&gt;
		[&#039;Year active from&#039;] = from,&lt;br /&gt;
		[&#039;Year active until&#039;] = until_year&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2726</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2726"/>
		<updated>2026-08-06T10:51:30Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainSearchPaneRender() {&lt;br /&gt;
        return {&lt;br /&gt;
            display: function (data) {&lt;br /&gt;
                return data;&lt;br /&gt;
            },&lt;br /&gt;
            sp: function (data) {&lt;br /&gt;
                return getPlainAcceptsValues(data);&lt;br /&gt;
            },&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: getPlainSearchPaneRender(),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2725</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2725"/>
		<updated>2026-08-06T10:47:52Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8, 10].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return data;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getAcceptsValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2724</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2724"/>
		<updated>2026-08-06T10:45:42Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPlainAcceptsValues(html) {&lt;br /&gt;
        return getAcceptsValues(html)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                container.innerHTML = value;&lt;br /&gt;
&lt;br /&gt;
                return (container.textContent || &amp;quot;&amp;quot;).trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getPlainAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return data;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getAcceptsValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2723</id>
		<title>MediaWiki:Datatables.js</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=MediaWiki:Datatables.js&amp;diff=2723"/>
		<updated>2026-08-06T10:15:23Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;var selectors = [&lt;br /&gt;
    &amp;quot;#games &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var seriesSelectors = [&lt;br /&gt;
    &amp;quot;#series &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var assetSelectors = [&lt;br /&gt;
    &amp;quot;#assets &amp;gt; table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var playerSelectors = [&lt;br /&gt;
    &amp;quot;#players table&amp;quot;,&lt;br /&gt;
];&lt;br /&gt;
var allSelectors = selectors.concat(seriesSelectors, assetSelectors, playerSelectors);&lt;br /&gt;
&lt;br /&gt;
var found = false;&lt;br /&gt;
for (var i = 0; i &amp;lt; allSelectors.length; i++) {&lt;br /&gt;
    if (document.querySelector(allSelectors[i])) {&lt;br /&gt;
        found = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables Loader and initialisation ---------------- */&lt;br /&gt;
&lt;br /&gt;
if (found === true) {&lt;br /&gt;
    /* Load CSS. */&lt;br /&gt;
    const dtsource =&lt;br /&gt;
        &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.css&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&#039;link[href*=&amp;quot;datatables.min.css&amp;quot;]&#039;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;link/&amp;gt;&amp;quot;, { rel: &amp;quot;stylesheet&amp;quot;, href: dtsource }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!document.querySelector(&amp;quot;#datatable-styles&amp;quot;)) {&lt;br /&gt;
        $(&amp;quot;&amp;lt;style/&amp;gt;&amp;quot;, {&lt;br /&gt;
            id: &amp;quot;datatable-styles&amp;quot;,&lt;br /&gt;
            text: `&lt;br /&gt;
            &lt;br /&gt;
        table.dataTable &amp;gt; tbody &amp;gt; tr &amp;gt; td {&lt;br /&gt;
          padding-top: 0.25rem;&lt;br /&gt;
          padding-bottom: 0.25rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		table.dataTable, table.dataTable * {&lt;br /&gt;
		  border: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dt-loading {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          min-height: 4rem;&lt;br /&gt;
          position: relative;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading &amp;gt; * {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-loading::before {&lt;br /&gt;
          animation: dt-loading 0.8s linear infinite;&lt;br /&gt;
          border: 0.25rem solid #dee2e6;&lt;br /&gt;
          border-radius: 50%;&lt;br /&gt;
          border-top-color: #6c757d;&lt;br /&gt;
          content: &amp;quot;&amp;quot;;&lt;br /&gt;
          height: 2rem;&lt;br /&gt;
          left: calc(50% - 1rem);&lt;br /&gt;
          position: absolute;&lt;br /&gt;
          top: 1rem;&lt;br /&gt;
          width: 2rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @keyframes dt-loading {&lt;br /&gt;
          to {&lt;br /&gt;
            transform: rotate(360deg);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		div.dtsp-panesContainer div.dtsp-title {&lt;br /&gt;
			padding: 2px 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-bordered, .dtsp-bordered:hover,&lt;br /&gt;
        .dtsp-searchPane, .dtsp-searchPane:hover {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
		.dtsp-topRow button:hover, .dtsp-topRow input:hover,&lt;br /&gt;
		.dtsp-topRow button:focus, .dtsp-topRow input:focus,&lt;br /&gt;
		.dtsp-topRow button, .dtsp-topRow input {&lt;br /&gt;
			margin: 0 !important;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
        .dtsp-paneButton.clearButton {&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
		  line-height: 0;&lt;br /&gt;
          padding-bottom: 6px;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-paneButton.clearButton:not(:disabled) {&lt;br /&gt;
          color: #dc3545 !important;&lt;br /&gt;
		  font-size: 3rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
		.dtsp-topRow {&lt;br /&gt;
		  background-color: #1e2d59;&lt;br /&gt;
          background-image: url(/w/extensions/wikivisor/images/embossed-leather-pattern.png);&lt;br /&gt;
          background-blend-mode: darken;&lt;br /&gt;
          background-size: cover;&lt;br /&gt;
          border: 1px solid rgba(255,255,255,0.2);&lt;br /&gt;
          box-shadow: inset 0 0 30px rgba(0,0,0,0.75);&lt;br /&gt;
		}&lt;br /&gt;
        .dtsp-caret {&lt;br /&gt;
          align-items: end;&lt;br /&gt;
          display: inline-flex !important;&lt;br /&gt;
          font-size: 0 !important;&lt;br /&gt;
          height: 1rem;&lt;br /&gt;
          justify-content: center;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          width: 1rem;&lt;br /&gt;
          align-items: center;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-topRow button.dtsp-collapseButton span.dtsp-caret {&lt;br /&gt;
			top: unset !important;        	&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dtsp-caret::before {&lt;br /&gt;
          content: &amp;quot;\\2335&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [aria-expanded=&amp;quot;true&amp;quot;] .dtsp-caret::before,&lt;br /&gt;
        .dtsp-caret-u::before,&lt;br /&gt;
        .dtsp-caret-up::before {&lt;br /&gt;
          content: &amp;quot;\\2303&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        div.dtsp-searchPane div.dtsp-topRow div.dtsp-searchCont input.dtsp-search {&lt;br /&gt;
		  padding-left: 8px;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          background: var(--bs-primary, #0d6efd);&lt;br /&gt;
          border: 0;&lt;br /&gt;
          border-radius: 0.25rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: inline-flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          gap: 0.375rem;&lt;br /&gt;
          line-height: 1.25;&lt;br /&gt;
          padding: 0.5rem 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          gap: 0.75rem;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          margin-bottom: 0.75rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          gap: 0.5rem;&lt;br /&gt;
          justify-content: flex-end;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toolbar .dt-search input {&lt;br /&gt;
          margin-left: 0 !important;&lt;br /&gt;
          max-width: 24rem;&lt;br /&gt;
          width: 100%;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @media (max-width: 576px) {&lt;br /&gt;
          .dt-filter-toolbar {&lt;br /&gt;
            align-items: stretch;&lt;br /&gt;
            flex-direction: column;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          .dt-filter-toolbar .dt-filter-toggle,&lt;br /&gt;
          .dt-filter-toolbar .dt-search,&lt;br /&gt;
          .dt-filter-toolbar .dt-search input {&lt;br /&gt;
            max-width: none;&lt;br /&gt;
            width: 100%;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle:focus {&lt;br /&gt;
          box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);&lt;br /&gt;
          outline: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-toggle::before {&lt;br /&gt;
          content: &amp;quot;\\2630&amp;quot;;&lt;br /&gt;
          font-size: 1rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop {&lt;br /&gt;
          background: rgba(0, 0, 0, 0);&lt;br /&gt;
          inset: 0;&lt;br /&gt;
          opacity: 0;&lt;br /&gt;
          pointer-events: none;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          transition: opacity 180ms ease;&lt;br /&gt;
          z-index: 1040;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-backdrop.is-open {&lt;br /&gt;
          opacity: 1;&lt;br /&gt;
          pointer-events: auto;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel {&lt;br /&gt;
          background-color: #11161b !important;&lt;br /&gt;
          border-color: var(--bg-content);&lt;br /&gt;
          border-style: solid;&lt;br /&gt;
          border-width: 0.5rem;&lt;br /&gt;
          border-bottom-right-radius: 0.625rem;&lt;br /&gt;
          border-top-right-radius: 0.625rem;&lt;br /&gt;
          color: #fff;&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex-direction: column;&lt;br /&gt;
          height: 100vh;&lt;br /&gt;
          left: 0;&lt;br /&gt;
          max-width: min(92vw, 20rem);&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
          position: fixed;&lt;br /&gt;
          top: 0;&lt;br /&gt;
          transform: translateX(-100%);&lt;br /&gt;
          transition: transform 220ms ease;&lt;br /&gt;
          width: 20rem;&lt;br /&gt;
          z-index: 1050;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel.is-open {&lt;br /&gt;
          box-shadow: 0 0 20px rgba(255,255,255,0.2);&lt;br /&gt;
          transform: translateX(0);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__header {&lt;br /&gt;
          align-items: center;&lt;br /&gt;
          border-bottom: 1px solid var(--accent);&lt;br /&gt;
          display: flex;&lt;br /&gt;
          flex: 0 0 auto;&lt;br /&gt;
          justify-content: space-between;&lt;br /&gt;
          padding: 0.75rem 1rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__title {&lt;br /&gt;
          font-size: 1.4rem;&lt;br /&gt;
          font-weight: 600;&lt;br /&gt;
          margin: 0;&lt;br /&gt;
          border-bottom: 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__close {&lt;br /&gt;
          background: transparent;&lt;br /&gt;
          border: 0;&lt;br /&gt;
          color: rgb(124,124,124);&lt;br /&gt;
          font-size: 2.5rem;&lt;br /&gt;
          line-height: 1;&lt;br /&gt;
          padding: 0.125rem 0.375rem 6px 0.375rem;&lt;br /&gt;
          width: 35px;&lt;br /&gt;
          height: 35px;&lt;br /&gt;
		  display: flex;&lt;br /&gt;
		  align-items: center;&lt;br /&gt;
		  justify-content: center;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body {&lt;br /&gt;
          flex: 1 1 auto;&lt;br /&gt;
          overflow: auto;&lt;br /&gt;
          padding: 0.75rem;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-panesContainer {&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPanes {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        .dt-filter-panel__body .dtsp-searchPane {&lt;br /&gt;
          margin-bottom: 0.75rem !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        body.dt-filter-panel-open {&lt;br /&gt;
          overflow: hidden;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * The series table uses SearchBuilder as a single, fixed selector.&lt;br /&gt;
         * Keep only the criterion&#039;s value dropdown visible.&lt;br /&gt;
         */&lt;br /&gt;
        #series .dt-container .dtsb-titleRow,&lt;br /&gt;
        #series .dt-container .dtsb-logicContainer,&lt;br /&gt;
        #series .dt-container .dtsb-data,&lt;br /&gt;
        #series .dt-container .dtsb-condition,&lt;br /&gt;
        #series .dt-container .dtsb-add,&lt;br /&gt;
        #series .dt-container .dtsb-clearAll,&lt;br /&gt;
        #series .dt-container .dtsb-clearGroup,&lt;br /&gt;
        #series .dt-container .dtsb-search,&lt;br /&gt;
        #series .dt-container .dtsb-buttonContainer,&lt;br /&gt;
        #series .dt-container .dtsb-joiner,&lt;br /&gt;
        #series .dt-container .dtsb-delete,&lt;br /&gt;
        #series .dt-container .dtsb-left,&lt;br /&gt;
        #series .dt-container .dtsb-right {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder &amp;gt; :not(.dtsb-group),&lt;br /&gt;
        #series .dt-container .dtsb-group &amp;gt; :not(.dtsb-criteria),&lt;br /&gt;
        #series .dt-container .dtsb-criteria &amp;gt; :not(.dtsb-inputCont),&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(select.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-searchBuilder,&lt;br /&gt;
        #series .dt-container .dtsb-group,&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          border: 0 !important;&lt;br /&gt;
          margin: 0 !important;&lt;br /&gt;
          padding: 0 !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-criteria {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: min(100%, 24rem) !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-inputCont &amp;gt; :not(.dtsb-value) {&lt;br /&gt;
          display: none !important;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        #series .dt-container .dtsb-value {&lt;br /&gt;
          display: block !important;&lt;br /&gt;
          width: 100% !important;&lt;br /&gt;
        }&lt;br /&gt;
		&lt;br /&gt;
		aside.is-open .sidebar-drawer {&lt;br /&gt;
			display: inline-block;&lt;br /&gt;
			right: 0;&lt;br /&gt;
			left: 284px;&lt;br /&gt;
			border: 0;&lt;br /&gt;
			z-index: 3;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		aside.dt-filter-panel {&lt;br /&gt;
			background-image: url(/w/images/d/de/File_Icon-Guardians-semitransparent.png);&lt;br /&gt;
			background-position: bottom;&lt;br /&gt;
			background-repeat: no-repeat;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		.dt-search label {&lt;br /&gt;
			display: none;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		#players tbody tr td:last-child {&lt;br /&gt;
			color: var(--bg-shade-6);&lt;br /&gt;
		}&lt;br /&gt;
      `,&lt;br /&gt;
        }).appendTo(&amp;quot;head&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(allSelectors.join(&amp;quot;,&amp;quot;)).addClass(&amp;quot;dt-loading&amp;quot;).attr(&amp;quot;aria-busy&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    /* Load JavaScript. */&lt;br /&gt;
    $.when(&lt;br /&gt;
        mw.loader.getScript(&lt;br /&gt;
            &amp;quot;https://cdn.datatables.net/v/dt/moment-2.29.4/dt-2.3.7/b-3.2.6/b-colvis-3.2.6/b-html5-3.2.6/b-print-3.2.6/cc-1.2.0/date-1.6.3/fh-4.0.5/r-3.0.8/sc-2.4.3/sb-1.8.4/sp-2.3.5/sl-3.1.3/sr-1.4.3/datatables.min.js&amp;quot;,&lt;br /&gt;
        ),&lt;br /&gt;
    ).then(&lt;br /&gt;
        () =&amp;gt; {&lt;br /&gt;
            window.datatablesLoaded = true;&lt;br /&gt;
            initDataTable();&lt;br /&gt;
        },&lt;br /&gt;
        (e) =&amp;gt; mw.log.error(e.message),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* ------------- DataTables configuration ---------------------------- */&lt;br /&gt;
&lt;br /&gt;
function initDataTable() {&lt;br /&gt;
    function getDataTableColumnCount(table) {&lt;br /&gt;
        var headerRow =&lt;br /&gt;
            table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? table.tHead.rows[table.tHead.rows.length - 1]&lt;br /&gt;
                : null;&lt;br /&gt;
&lt;br /&gt;
        if (headerRow) {&lt;br /&gt;
            return headerRow.cells.length;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return table.rows.length ? table.rows[0].cells.length : 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseDataTableRows(table, expectedColumnCount) {&lt;br /&gt;
        $(&amp;quot;tbody tr&amp;quot;, table).each(function () {&lt;br /&gt;
            var row = this;&lt;br /&gt;
            var cellCount = row.cells.length;&lt;br /&gt;
&lt;br /&gt;
            if (cellCount === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            while (cellCount &amp;lt; expectedColumnCount) {&lt;br /&gt;
                row.appendChild(document.createElement(&amp;quot;td&amp;quot;));&lt;br /&gt;
                cellCount++;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function waitForTableToSettle(table, callback) {&lt;br /&gt;
        var settleTimer;&lt;br /&gt;
        var timeoutTimer;&lt;br /&gt;
        var observer;&lt;br /&gt;
        var settled = false;&lt;br /&gt;
&lt;br /&gt;
        function finish() {&lt;br /&gt;
            if (settled) return;&lt;br /&gt;
&lt;br /&gt;
            settled = true;&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            clearTimeout(timeoutTimer);&lt;br /&gt;
&lt;br /&gt;
            if (observer) {&lt;br /&gt;
                observer.disconnect();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            callback();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function scheduleFinish() {&lt;br /&gt;
            clearTimeout(settleTimer);&lt;br /&gt;
            settleTimer = setTimeout(finish, 500);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (window.MutationObserver) {&lt;br /&gt;
            observer = new MutationObserver(scheduleFinish);&lt;br /&gt;
            observer.observe(table.tBodies[0] || table, {&lt;br /&gt;
                childList: true,&lt;br /&gt;
                subtree: true,&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        timeoutTimer = setTimeout(finish, 30000);&lt;br /&gt;
        scheduleFinish();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getAcceptsValues(html) {&lt;br /&gt;
        return (html || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/&amp;lt;br\s*\/?&amp;gt;/i)&lt;br /&gt;
            .map((value) =&amp;gt; value.trim())&lt;br /&gt;
            .filter(Boolean);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeText(html) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var values = [];&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        values.push(container.textContent || &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        container.querySelectorAll(&amp;quot;*&amp;quot;).forEach(function (element) {&lt;br /&gt;
            [&amp;quot;alt&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;aria-label&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;src&amp;quot;].forEach(function (attribute) {&lt;br /&gt;
                var value = element.getAttribute(attribute);&lt;br /&gt;
&lt;br /&gt;
                if (value) {&lt;br /&gt;
                    values.push(value);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return values.join(&amp;quot; &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValue(html) {&lt;br /&gt;
        var text = getGameModeText(html)&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[_-]+/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (/\b(single\s*player|singleplayer|solo|sp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;SP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(multi\s*player|multiplayer|mp)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;MP&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (/\b(co\s*op|coop|cooperative)\b/.test(text)) {&lt;br /&gt;
            return &amp;quot;Coop&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeValues(html) {&lt;br /&gt;
        var selectedModes = new Set(getAcceptsValues(html)&lt;br /&gt;
            .map(getGameModeValue)&lt;br /&gt;
            .filter(Boolean));&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;].filter(function (mode) {&lt;br /&gt;
            return selectedModes.has(mode);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValue(html, mode) {&lt;br /&gt;
        var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var link;&lt;br /&gt;
&lt;br /&gt;
        container.innerHTML = html || &amp;quot;&amp;quot;;&lt;br /&gt;
        link = container.querySelector(&amp;quot;a[href]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (!link) {&lt;br /&gt;
            return mode;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        link = link.cloneNode(false);&lt;br /&gt;
        link.textContent = mode;&lt;br /&gt;
&lt;br /&gt;
        return link.outerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getGameModeDisplayValues(html) {&lt;br /&gt;
        var valuesByMode = {};&lt;br /&gt;
&lt;br /&gt;
        getAcceptsValues(html).forEach(function (value) {&lt;br /&gt;
            var mode = getGameModeValue(value);&lt;br /&gt;
&lt;br /&gt;
            if (mode &amp;amp;&amp;amp; !valuesByMode[mode]) {&lt;br /&gt;
                valuesByMode[mode] = getGameModeDisplayValue(value, mode);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return [&amp;quot;SP&amp;quot;, &amp;quot;MP&amp;quot;, &amp;quot;Coop&amp;quot;]&lt;br /&gt;
            .filter(function (mode) {&lt;br /&gt;
                return Object.prototype.hasOwnProperty.call(valuesByMode, mode);&lt;br /&gt;
            })&lt;br /&gt;
            .map(function (mode) {&lt;br /&gt;
                return valuesByMode[mode];&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function normaliseColumnName(value) {&lt;br /&gt;
        return String(value || &amp;quot;&amp;quot;)&lt;br /&gt;
            .trim()&lt;br /&gt;
            .toLowerCase()&lt;br /&gt;
            .replace(/[\s_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableConfigElement(table) {&lt;br /&gt;
        return table.closest(&lt;br /&gt;
            &amp;quot;[data-hidden-columns], [data-hide-columns], [data-dt-hidden-columns], [data-dt-hide-columns], [data-pane-columns], [data-search-pane-columns], [data-dt-pane-columns], [data-first-column-name], [data-first-column], [data-page-column-name], [data-dt-first-column-name]&amp;quot;,&lt;br /&gt;
        ) || table.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFirstColumnName(table) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var columnName = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-first-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-first-column&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-page-column-name&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-first-column-name&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return String(columnName || &amp;quot;Page&amp;quot;).trim() || &amp;quot;Page&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getHiddenColumnIndexes(table, titles) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var rawValue = configElement&lt;br /&gt;
            ? configElement.getAttribute(&amp;quot;data-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-hide-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hidden-columns&amp;quot;) ||&lt;br /&gt;
            configElement.getAttribute(&amp;quot;data-dt-hide-columns&amp;quot;)&lt;br /&gt;
            : &amp;quot;&amp;quot;;&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var hiddenIndexes = new Set();&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(rawValue || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
&lt;br /&gt;
                if (Number.isInteger(numberValue) &amp;amp;&amp;amp; numberValue &amp;gt;= 0 &amp;amp;&amp;amp; numberValue &amp;lt; titles.length) {&lt;br /&gt;
                    hiddenIndexes.add(numberValue);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (Object.prototype.hasOwnProperty.call(titleIndexes, normalisedValue)) {&lt;br /&gt;
                    hiddenIndexes.add(titleIndexes[normalisedValue]);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return hiddenIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getPaneColumnIndexes(table, titles, fallbackIndexes) {&lt;br /&gt;
        var configElement = getTableConfigElement(table);&lt;br /&gt;
        var attributes = [&lt;br /&gt;
            &amp;quot;data-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-search-pane-columns&amp;quot;,&lt;br /&gt;
            &amp;quot;data-dt-pane-columns&amp;quot;,&lt;br /&gt;
        ];&lt;br /&gt;
        var configuredAttribute = attributes.find(function (attribute) {&lt;br /&gt;
            return configElement &amp;amp;&amp;amp; configElement.hasAttribute(attribute);&lt;br /&gt;
        });&lt;br /&gt;
        var titleIndexes = {};&lt;br /&gt;
        var paneIndexes = [];&lt;br /&gt;
&lt;br /&gt;
        if (!configuredAttribute) {&lt;br /&gt;
            return fallbackIndexes.slice();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        titles.forEach(function (title, index) {&lt;br /&gt;
            titleIndexes[normaliseColumnName(title)] = index;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        String(configElement.getAttribute(configuredAttribute) || &amp;quot;&amp;quot;)&lt;br /&gt;
            .split(/[,\|]/)&lt;br /&gt;
            .map(function (value) {&lt;br /&gt;
                return value.trim();&lt;br /&gt;
            })&lt;br /&gt;
            .filter(Boolean)&lt;br /&gt;
            .forEach(function (value) {&lt;br /&gt;
                var numberValue = Number(value);&lt;br /&gt;
                var normalisedValue = normaliseColumnName(value);&lt;br /&gt;
                var index = Number.isInteger(numberValue)&lt;br /&gt;
                    ? numberValue&lt;br /&gt;
                    : titleIndexes[normalisedValue];&lt;br /&gt;
&lt;br /&gt;
                if (&lt;br /&gt;
                    Number.isInteger(index) &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;gt;= 0 &amp;amp;&amp;amp;&lt;br /&gt;
                    index &amp;lt; titles.length &amp;amp;&amp;amp;&lt;br /&gt;
                    paneIndexes.indexOf(index) === -1&lt;br /&gt;
                ) {&lt;br /&gt;
                    paneIndexes.push(index);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        return paneIndexes;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getTableData(table, columnCount) {&lt;br /&gt;
        return Array.from(table.tBodies[0] ? table.tBodies[0].rows : [])&lt;br /&gt;
            .filter((row) =&amp;gt; !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1))&lt;br /&gt;
            .map((row) =&amp;gt; {&lt;br /&gt;
                var data = Array.from(row.cells, (cell) =&amp;gt; cell.innerHTML.trim());&lt;br /&gt;
&lt;br /&gt;
                while (data.length &amp;lt; columnCount) {&lt;br /&gt;
                    data.push(&amp;quot;&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                return data.slice(0, columnCount);&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function buildTableLayout(table, titles) {&lt;br /&gt;
        var headerRow = document.createElement(&amp;quot;tr&amp;quot;);&lt;br /&gt;
        var tableHead = document.createElement(&amp;quot;thead&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        titles.forEach((title) =&amp;gt; {&lt;br /&gt;
            var headerCell = document.createElement(&amp;quot;th&amp;quot;);&lt;br /&gt;
            headerCell.textContent = title;&lt;br /&gt;
            headerRow.appendChild(headerCell);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        table.replaceChildren(tableHead, document.createElement(&amp;quot;tbody&amp;quot;));&lt;br /&gt;
        tableHead.appendChild(headerRow);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function suppressSearchPaneBorders(container) {&lt;br /&gt;
        if (!container) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function removeBorderClass() {&lt;br /&gt;
            container.querySelectorAll(&amp;quot;.dtsp-bordered&amp;quot;).forEach(function (element) {&lt;br /&gt;
                element.classList.remove(&amp;quot;dtsp-bordered&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        removeBorderClass();&lt;br /&gt;
&lt;br /&gt;
        new MutationObserver(removeBorderClass).observe(container, {&lt;br /&gt;
            attributes: true,&lt;br /&gt;
            attributeFilter: [&amp;quot;class&amp;quot;],&lt;br /&gt;
            childList: true,&lt;br /&gt;
            subtree: true,&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function openFellowshipLinksInNewTab(dataTable) {&lt;br /&gt;
        dataTable&lt;br /&gt;
            .column(0)&lt;br /&gt;
            .nodes()&lt;br /&gt;
            .toArray()&lt;br /&gt;
            .forEach(function (cell) {&lt;br /&gt;
                cell.querySelectorAll(&amp;quot;a&amp;quot;).forEach(function (link) {&lt;br /&gt;
                    link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterToolbar(wrapper, toggle) {&lt;br /&gt;
        var toolbar = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var search = wrapper.querySelector(&amp;quot;.dt-search&amp;quot;);&lt;br /&gt;
        var searchRow = search ? search.closest(&amp;quot;.dt-layout-row&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        toolbar.className = &amp;quot;dt-filter-toolbar&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode) {&lt;br /&gt;
            searchRow.parentNode.insertBefore(toolbar, searchRow);&lt;br /&gt;
        } else {&lt;br /&gt;
            wrapper.insertBefore(toolbar, wrapper.firstChild);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toolbar.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
        if (search) {&lt;br /&gt;
            toolbar.appendChild(search);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (searchRow &amp;amp;&amp;amp; searchRow.parentNode &amp;amp;&amp;amp; !searchRow.querySelector(&amp;quot;.dt-search&amp;quot;)) {&lt;br /&gt;
            searchRow.remove();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getCurrentPageName() {&lt;br /&gt;
        var pageName = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if (window.mw &amp;amp;&amp;amp; mw.config) {&lt;br /&gt;
            pageName = mw.config.get(&amp;quot;wgTitle&amp;quot;) || mw.config.get(&amp;quot;wgPageName&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!pageName) {&lt;br /&gt;
            pageName = (document.querySelector(&amp;quot;#firstHeading&amp;quot;) || {}).textContent || document.title || &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName.replace(/_/g, &amp;quot; &amp;quot;).trim();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function getFilterPanelTitle(titles, hiddenColumnIndexes) {&lt;br /&gt;
        var pageName = getCurrentPageName();&lt;br /&gt;
&lt;br /&gt;
        if (hiddenColumnIndexes &amp;amp;&amp;amp; hiddenColumnIndexes.size === 1) {&lt;br /&gt;
            return titles[Array.from(hiddenColumnIndexes)[0]] + &amp;quot;: &amp;quot; + pageName;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return pageName;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes) {&lt;br /&gt;
        var wrapper = table.closest(&amp;quot;.dt-container&amp;quot;) || table.parentNode;&lt;br /&gt;
        var panes = wrapper ? wrapper.querySelector(&amp;quot;.dtsp-panesContainer&amp;quot;) : null;&lt;br /&gt;
&lt;br /&gt;
        if (!wrapper || !panes) {&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;)) {&lt;br /&gt;
            return document.getElementById(wrapper.querySelector(&amp;quot;.dt-filter-toggle&amp;quot;).getAttribute(&amp;quot;aria-controls&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var panel = document.createElement(&amp;quot;aside&amp;quot;);&lt;br /&gt;
        var backdrop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var drawer = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var header = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var title = document.createElement(&amp;quot;h2&amp;quot;);&lt;br /&gt;
        var close = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
        var body = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        var panelId = &amp;quot;dt-filter-panel-&amp;quot; + $(&amp;quot;.dt-filter-panel&amp;quot;).length;&lt;br /&gt;
        var lastFocusedElement = null;&lt;br /&gt;
&lt;br /&gt;
        toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        toggle.className = &amp;quot;dt-filter-toggle&amp;quot;;&lt;br /&gt;
        toggle.textContent = &amp;quot;Filters&amp;quot;;&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-controls&amp;quot;, panelId);&lt;br /&gt;
        toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        panel.id = panelId;&lt;br /&gt;
        panel.className = &amp;quot;dt-filter-panel&amp;quot;;&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
        panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Data filters&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        backdrop.className = &amp;quot;dt-filter-backdrop&amp;quot;;&lt;br /&gt;
        drawer.className = &amp;quot;sidebar-drawer&amp;quot;;&lt;br /&gt;
        drawer.setAttribute(&amp;quot;type&amp;quot;, &amp;quot;button&amp;quot;);&lt;br /&gt;
        drawer.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        header.className = &amp;quot;dt-filter-panel__header&amp;quot;;&lt;br /&gt;
        title.className = &amp;quot;dt-filter-panel__title&amp;quot;;&lt;br /&gt;
        title.textContent = getFilterPanelTitle(titles, hiddenColumnIndexes);&lt;br /&gt;
        close.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
        close.className = &amp;quot;dt-filter-panel__close&amp;quot;;&lt;br /&gt;
        close.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Close filters&amp;quot;);&lt;br /&gt;
        close.innerHTML = &amp;quot;&amp;amp;times;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        body.className = &amp;quot;dt-filter-panel__body&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        header.append(title, close);&lt;br /&gt;
        body.appendChild(panes);&lt;br /&gt;
        panel.append(drawer, header, body);&lt;br /&gt;
&lt;br /&gt;
        setupFilterToolbar(wrapper, toggle);&lt;br /&gt;
        document.body.append(backdrop, panel);&lt;br /&gt;
&lt;br /&gt;
        function openPanel() {&lt;br /&gt;
            lastFocusedElement = document.activeElement;&lt;br /&gt;
            panel.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.add(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.add(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            close.focus();&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function closePanel() {&lt;br /&gt;
            panel.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            backdrop.classList.remove(&amp;quot;is-open&amp;quot;);&lt;br /&gt;
            document.body.classList.remove(&amp;quot;dt-filter-panel-open&amp;quot;);&lt;br /&gt;
            panel.setAttribute(&amp;quot;aria-hidden&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
            toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
            if (lastFocusedElement &amp;amp;&amp;amp; document.contains(lastFocusedElement)) {&lt;br /&gt;
                lastFocusedElement.focus();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            dataTable.columns.adjust();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        toggle.addEventListener(&amp;quot;click&amp;quot;, openPanel);&lt;br /&gt;
        close.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        drawer.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
        backdrop.addEventListener(&amp;quot;click&amp;quot;, closePanel);&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
            if (event.key === &amp;quot;Escape&amp;quot; &amp;amp;&amp;amp; panel.classList.contains(&amp;quot;is-open&amp;quot;)) {&lt;br /&gt;
                closePanel();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return panel;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $(&amp;quot;.dataTable&amp;quot;)&lt;br /&gt;
        .not(allSelectors.join(&amp;quot;,&amp;quot;))&lt;br /&gt;
        .each(function () {&lt;br /&gt;
            var table = this;&lt;br /&gt;
&lt;br /&gt;
            waitForTableToSettle(table, function () {&lt;br /&gt;
                if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                normaliseDataTableRows(table, getDataTableColumnCount(table));&lt;br /&gt;
&lt;br /&gt;
                $(table).DataTable({&lt;br /&gt;
                    language: {&lt;br /&gt;
                        search: &amp;quot;&amp;quot;,&lt;br /&gt;
                        searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            title: {&lt;br /&gt;
                                _: &#039;Filters: %d&#039;,&lt;br /&gt;
                                0: &#039;&#039;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    retrieve: true,&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    pageLength: 1000,&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
    $(seriesSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&amp;quot;Series&amp;quot;, &amp;quot;Games&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
            /*&lt;br /&gt;
            * The source table is emitted as Games, Series.&lt;br /&gt;
            * DataTables uses Series, Games, so Series is column 0.&lt;br /&gt;
            */&lt;br /&gt;
            var data = getTableData(table, titles.length).map(function (row) {&lt;br /&gt;
                return {&lt;br /&gt;
                    series: row[1],&lt;br /&gt;
                    games: row[0]&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            normaliseDataTableRows(table, titles.length);&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            try {&lt;br /&gt;
                var dataTable = new DataTable(table, {&lt;br /&gt;
                    data: data,&lt;br /&gt;
&lt;br /&gt;
                    columns: [&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;games&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Games&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Game&amp;quot;&lt;br /&gt;
                        },&lt;br /&gt;
                        {&lt;br /&gt;
                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                            name: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            title: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            visible: false,&lt;br /&gt;
                            searchable: true,&lt;br /&gt;
                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    ],&lt;br /&gt;
&lt;br /&gt;
                    layout: {&lt;br /&gt;
                        topStart: null,&lt;br /&gt;
                        topEnd: null,&lt;br /&gt;
                        top1: {&lt;br /&gt;
                            searchBuilder: {&lt;br /&gt;
                                columns: [1],&lt;br /&gt;
&lt;br /&gt;
                                preDefined: {&lt;br /&gt;
                                    logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                    criteria: [&lt;br /&gt;
                                        {&lt;br /&gt;
                                            data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                            condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                            type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                        }&lt;br /&gt;
                                    ]&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                        },&lt;br /&gt;
                        top2: {&lt;br /&gt;
&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    language: {&lt;br /&gt;
                        searchBuilder: {&lt;br /&gt;
                            data: &amp;quot;Series&amp;quot;,&lt;br /&gt;
                            value: &amp;quot;Select a series&amp;quot;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
&lt;br /&gt;
                    order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                    paging: false,&lt;br /&gt;
&lt;br /&gt;
                    initComplete: function () {&lt;br /&gt;
                        var api = this.api();&lt;br /&gt;
                        var container = $(api.table().container());&lt;br /&gt;
&lt;br /&gt;
                        function emptySeriesCriterion() {&lt;br /&gt;
                            return {&lt;br /&gt;
                                logic: &amp;quot;AND&amp;quot;,&lt;br /&gt;
                                criteria: [&lt;br /&gt;
                                    {&lt;br /&gt;
                                        data: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        origData: &amp;quot;series&amp;quot;,&lt;br /&gt;
                                        condition: &amp;quot;=&amp;quot;,&lt;br /&gt;
                                        type: &amp;quot;string&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                                ]&lt;br /&gt;
                            };&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        function enableAllSeriesOption() {&lt;br /&gt;
                            var valueSelect = container&lt;br /&gt;
                                .find(&amp;quot;.dtsb-value&amp;quot;)&lt;br /&gt;
                                .first();&lt;br /&gt;
                            var emptyOption = valueSelect&lt;br /&gt;
                                .find(&#039;option[value=&amp;quot;--valueTitle--&amp;quot;]&#039;)&lt;br /&gt;
                                .first();&lt;br /&gt;
&lt;br /&gt;
                            emptyOption&lt;br /&gt;
                                .prop(&amp;quot;disabled&amp;quot;, false)&lt;br /&gt;
                                .prop(&amp;quot;hidden&amp;quot;, false)&lt;br /&gt;
                                .text(&amp;quot;All series&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        container[0].addEventListener(&lt;br /&gt;
                            &amp;quot;change&amp;quot;,&lt;br /&gt;
                            function (event) {&lt;br /&gt;
                                var select = event.target;&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    !select.matches(&amp;quot;.dtsb-value&amp;quot;) ||&lt;br /&gt;
                                    select.value !== &amp;quot;--valueTitle--&amp;quot;&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    return;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                /*&lt;br /&gt;
                                 * The placeholder has no SearchBuilder value.&lt;br /&gt;
                                 * Stop its listener before it calls toString()&lt;br /&gt;
                                 * on undefined, then reset the criterion here.&lt;br /&gt;
                                 */&lt;br /&gt;
                                event.stopImmediatePropagation();&lt;br /&gt;
&lt;br /&gt;
                                api.searchBuilder.rebuild(&lt;br /&gt;
                                    emptySeriesCriterion(),&lt;br /&gt;
                                    false&lt;br /&gt;
                                );&lt;br /&gt;
                                api.draw(false);&lt;br /&gt;
                                setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                            },&lt;br /&gt;
                            true&lt;br /&gt;
                        );&lt;br /&gt;
&lt;br /&gt;
                        setTimeout(enableAllSeriesOption, 0);&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                dataTable.columns.adjust().draw(false);&lt;br /&gt;
            } catch (error) {&lt;br /&gt;
                mw.log.error(&lt;br /&gt;
                    &amp;quot;Could not initialise the Series DataTable:&amp;quot;,&lt;br /&gt;
                    error&lt;br /&gt;
                );&lt;br /&gt;
            } finally {&lt;br /&gt;
                $(table)&lt;br /&gt;
                    .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                    .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                    .show();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(assetSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                &amp;quot;Asset&amp;quot;, &amp;quot;Type&amp;quot;, &amp;quot;Subtype&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                &amp;quot;Released&amp;quot;, &amp;quot;Status&amp;quot;, &amp;quot;Description&amp;quot;, &amp;quot;Version&amp;quot;, &amp;quot;Files&amp;quot;, &amp;quot;Game&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            if (mw.config.get(&#039;wgPageName&#039;) === &#039;Mods&#039;) {&lt;br /&gt;
                paneIndexes = [10, 1, 2, 3, 4, 5, 6, 8];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumns = [2, 3, 5, 6, 7, 8, 10];&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: hiddenColumns.indexOf(index) === -1,&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if ([1, 2, 3, 4, 6, 8].indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                if (index === 4) {&lt;br /&gt;
                                    return (&lt;br /&gt;
                                        &#039;&amp;lt;span style=&amp;quot;white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                        getAcceptsValues(cellData).join(&amp;quot;, &amp;quot;) +&lt;br /&gt;
                                        &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                    );&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                return getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (index === 9) {&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type !== &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var wrapper = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                            wrapper.innerHTML = cellData;&lt;br /&gt;
&lt;br /&gt;
                            var links = Array.from(wrapper.querySelectorAll(&amp;quot;a&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
                            if (!links.length) {&lt;br /&gt;
                                return &amp;quot;&amp;quot;;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            var downloads = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                            links.forEach(function (sourceLink, linkIndex) {&lt;br /&gt;
                                var link = sourceLink.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
                                link.textContent = links.length === 1&lt;br /&gt;
                                    ? &amp;quot;Download&amp;quot;&lt;br /&gt;
                                    : &amp;quot;Download &amp;quot; + (linkIndex + 1);&lt;br /&gt;
                                link.target = &amp;quot;_blank&amp;quot;;&lt;br /&gt;
                                link.rel = &amp;quot;noopener noreferrer nofollow&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                                downloads.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
                                if (linkIndex &amp;lt; links.length - 1) {&lt;br /&gt;
                                    downloads.appendChild(document.createElement(&amp;quot;br&amp;quot;));&lt;br /&gt;
                                }&lt;br /&gt;
                            });&lt;br /&gt;
&lt;br /&gt;
                            return downloads.innerHTML;&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search assets&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(dataTable, table, titles, new Set());&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(playerSelectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var fallbackTitles = [&lt;br /&gt;
                &amp;quot;Player&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Clans&amp;quot;, &amp;quot;Roles&amp;quot;, &amp;quot;Clan (Role)&amp;quot;, &amp;quot;Status&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var headerCells = table.tHead &amp;amp;&amp;amp; table.tHead.rows.length&lt;br /&gt;
                ? Array.from(table.tHead.rows[table.tHead.rows.length - 1].cells)&lt;br /&gt;
                : [];&lt;br /&gt;
            var titles = fallbackTitles.map(function (fallbackTitle, index) {&lt;br /&gt;
                var title = headerCells[index]&lt;br /&gt;
                    ? headerCells[index].textContent.trim()&lt;br /&gt;
                    : &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
                return title || fallbackTitle;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var hiddenColumnIndexes = new Set([1, 2, 3, 5]);&lt;br /&gt;
            var paneIndexes = getPaneColumnIndexes(table, titles, [2, 3, 5]);&lt;br /&gt;
            var playerColorClasses = Array.from(&lt;br /&gt;
                table.tBodies[0] ? table.tBodies[0].rows : []&lt;br /&gt;
            )&lt;br /&gt;
                .filter(function (row) {&lt;br /&gt;
                    return !(row.cells.length === 1 &amp;amp;&amp;amp; row.cells[0].colSpan &amp;gt; 1);&lt;br /&gt;
                })&lt;br /&gt;
                .map(function (row) {&lt;br /&gt;
                    return row.cells[0]&lt;br /&gt;
                        ? row.cells[0].className&lt;br /&gt;
                        : &amp;quot;&amp;quot;;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: titles.map(function (title, index) {&lt;br /&gt;
                    var column = {&lt;br /&gt;
                        title: title,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(index),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: paneIndexes.indexOf(index) !== -1,&lt;br /&gt;
                        },&lt;br /&gt;
                    };&lt;br /&gt;
&lt;br /&gt;
                    if (index === 0) {&lt;br /&gt;
                        column.createdCell = function (cell, cellData, rowData, rowIndex) {&lt;br /&gt;
                            var colorClasses = playerColorClasses[rowIndex];&lt;br /&gt;
&lt;br /&gt;
                            if (!colorClasses) {&lt;br /&gt;
                                return;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            colorClasses.split(/\s+/).filter(Boolean).forEach(function (className) {&lt;br /&gt;
                                cell.classList.add(className);&lt;br /&gt;
                            });&lt;br /&gt;
                        };&lt;br /&gt;
                        column.render = function (cellData, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    cellData +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return cellData;&lt;br /&gt;
                        };&lt;br /&gt;
                    } else if (paneIndexes.indexOf(index) !== -1) {&lt;br /&gt;
                        column.render = {&lt;br /&gt;
                            display: function (cellData) {&lt;br /&gt;
                                return cellData;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (cellData) {&lt;br /&gt;
                                var container = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
                                var linkedValues;&lt;br /&gt;
                                var blockValues;&lt;br /&gt;
&lt;br /&gt;
                                container.innerHTML = cellData || &amp;quot;&amp;quot;;&lt;br /&gt;
                                linkedValues = Array.from(&lt;br /&gt;
                                    container.querySelectorAll(&amp;quot;a&amp;quot;),&lt;br /&gt;
                                    function (link) {&lt;br /&gt;
                                        return link.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                if (linkedValues.length) {&lt;br /&gt;
                                    return linkedValues;&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                blockValues = Array.from(&lt;br /&gt;
                                    container.children,&lt;br /&gt;
                                    function (element) {&lt;br /&gt;
                                        return element.textContent.trim();&lt;br /&gt;
                                    }&lt;br /&gt;
                                ).filter(Boolean);&lt;br /&gt;
&lt;br /&gt;
                                return blockValues.length&lt;br /&gt;
                                    ? blockValues&lt;br /&gt;
                                    : getAcceptsValues(cellData);&lt;br /&gt;
                            },&lt;br /&gt;
                        };&lt;br /&gt;
                        column.searchPanes.orthogonal = &amp;quot;sp&amp;quot;;&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    return column;&lt;br /&gt;
                }),&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search players&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &amp;quot;Filters: %d&amp;quot;,&lt;br /&gt;
                            0: &amp;quot;&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
&lt;br /&gt;
            var filterPanel = setupFilterOffCanvas(&lt;br /&gt;
                dataTable,&lt;br /&gt;
                table,&lt;br /&gt;
                titles,&lt;br /&gt;
                hiddenColumnIndexes&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    $(selectors.join(&amp;quot;,&amp;quot;)).each(function () {&lt;br /&gt;
        var table = this;&lt;br /&gt;
&lt;br /&gt;
        waitForTableToSettle(table, function () {&lt;br /&gt;
            if ($.fn.dataTable.isDataTable(table)) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            var titles = [&lt;br /&gt;
                getFirstColumnName(table), &amp;quot;Developer&amp;quot;, &amp;quot;Publisher&amp;quot;, &amp;quot;Genre&amp;quot;, &amp;quot;Platform&amp;quot;, &amp;quot;Mode&amp;quot;, &amp;quot;Released&amp;quot;, &amp;quot;Category&amp;quot;&lt;br /&gt;
            ];&lt;br /&gt;
            var hiddenColumnIndexes = getHiddenColumnIndexes(table, titles);&lt;br /&gt;
            var paneIndexes = [1, 2, 3, 4, 5, 7].filter(function (paneIndex) {&lt;br /&gt;
                return !hiddenColumnIndexes.has(paneIndex);&lt;br /&gt;
            });&lt;br /&gt;
            var data = getTableData(table, titles.length);&lt;br /&gt;
&lt;br /&gt;
            buildTableLayout(table, titles);&lt;br /&gt;
&lt;br /&gt;
            var dataTable = new DataTable(table, {&lt;br /&gt;
                columns: [&lt;br /&gt;
                    {&lt;br /&gt;
                        title: titles[0],&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(0),&lt;br /&gt;
                        render: function (data, type) {&lt;br /&gt;
                            if (type === &amp;quot;display&amp;quot;) {&lt;br /&gt;
                                return (&lt;br /&gt;
                                    &#039;&amp;lt;span style=&amp;quot;display: list-item; margin-left: 1.25rem; white-space: nowrap&amp;quot;&amp;gt;&#039; +&lt;br /&gt;
                                    data +&lt;br /&gt;
                                    &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
                                );&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            return data;&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: false,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Developer&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(1),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Publisher&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(2),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Genre&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(3),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Platform&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(4),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Mode&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return getGameModeDisplayValues(data).join(&amp;quot;, &amp;quot;);&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getGameModeValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(5),&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Released&amp;quot;,&lt;br /&gt;
                        visible: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: !hiddenColumnIndexes.has(6),&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    {&lt;br /&gt;
                        title: &amp;quot;Category&amp;quot;,&lt;br /&gt;
                        visible: false,&lt;br /&gt;
                        render: {&lt;br /&gt;
                            display: function (data) {&lt;br /&gt;
                                return data;&lt;br /&gt;
                            },&lt;br /&gt;
                            sp: function (data) {&lt;br /&gt;
                                return getAcceptsValues(data);&lt;br /&gt;
                            },&lt;br /&gt;
                        },&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            show: true,&lt;br /&gt;
                            orthogonal: &amp;quot;sp&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                ],&lt;br /&gt;
                layout: {&lt;br /&gt;
                    topStart: null,&lt;br /&gt;
                    topEnd: null,&lt;br /&gt;
                    top2: {&lt;br /&gt;
                        searchPanes: {&lt;br /&gt;
                            cascadePanes: true,&lt;br /&gt;
                            dtOpts: {&lt;br /&gt;
                                scroller: false,&lt;br /&gt;
                            },&lt;br /&gt;
                            initCollapsed: true,&lt;br /&gt;
                            layout: &amp;quot;columns-1&amp;quot;,&lt;br /&gt;
                            columns: paneIndexes,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                    top1: {&lt;br /&gt;
                        search: {&lt;br /&gt;
                            className: &amp;quot;mx-0 w-100&amp;quot;,&lt;br /&gt;
                        },&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                order: [[0, &amp;quot;asc&amp;quot;]],&lt;br /&gt;
                language: {&lt;br /&gt;
                    search: &amp;quot;&amp;quot;,&lt;br /&gt;
                    searchPlaceholder: &amp;quot;Search&amp;quot;,&lt;br /&gt;
                    searchPanes: {&lt;br /&gt;
                        title: {&lt;br /&gt;
                            _: &#039;Filters: %d&#039;,&lt;br /&gt;
                            0: &#039;&#039;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                paging: false,&lt;br /&gt;
                searchDelay: 400,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var lastGlobalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
            dataTable.on(&amp;quot;draw.dt&amp;quot;, function () {&lt;br /&gt;
                var globalSearch = dataTable.search();&lt;br /&gt;
&lt;br /&gt;
                openFellowshipLinksInNewTab(dataTable);&lt;br /&gt;
&lt;br /&gt;
                if (globalSearch === lastGlobalSearch) {&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                lastGlobalSearch = globalSearch;&lt;br /&gt;
&lt;br /&gt;
                paneIndexes.forEach(function (paneIndex) {&lt;br /&gt;
                    dataTable.searchPanes.rebuildPane(paneIndex, true);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var filterPanel;&lt;br /&gt;
&lt;br /&gt;
            dataTable.rows.add(data).draw();&lt;br /&gt;
            $(table)&lt;br /&gt;
                .removeClass(&amp;quot;dt-loading&amp;quot;)&lt;br /&gt;
                .removeAttr(&amp;quot;aria-busy&amp;quot;)&lt;br /&gt;
                .show();&lt;br /&gt;
            dataTable.searchPanes.rebuildPane();&lt;br /&gt;
            filterPanel = setupFilterOffCanvas(dataTable, table, titles, hiddenColumnIndexes);&lt;br /&gt;
            suppressSearchPaneBorders(filterPanel);&lt;br /&gt;
            dataTable.columns.adjust().draw(false);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
	<entry>
		<id>https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2722</id>
		<title>Module:Universe</title>
		<link rel="alternate" type="text/html" href="https://www.pcgamingshelter.eu/w/index.php?title=Module:Universe&amp;diff=2722"/>
		<updated>2026-08-06T10:12:05Z</updated>

		<summary type="html">&lt;p&gt;WikiVisor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function getCurrentGame()&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local game = title.rootText&lt;br /&gt;
	local resource = title.subpageText&lt;br /&gt;
	local data = {&lt;br /&gt;
		[&amp;quot;game&amp;quot;] = game,&lt;br /&gt;
		[&amp;quot;resource&amp;quot;] = resource,&lt;br /&gt;
	}&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function setDisplayTitle(frame, title)&lt;br /&gt;
	local displayTitle = frame:preprocess(string.format(&amp;quot;{{DISPLAYTITLE:%s|noreplace, noerror}}&amp;quot;, title))&lt;br /&gt;
	return displayTitle&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function escapePattern(value)&lt;br /&gt;
	return value:gsub(&amp;quot;([^%w])&amp;quot;, &amp;quot;%%%1&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeGameFromLabels(results, game)&lt;br /&gt;
	local gamePattern = escapePattern(game)&lt;br /&gt;
&lt;br /&gt;
	for index, link in ipairs(results) do&lt;br /&gt;
		results[index] = link:gsub(&amp;quot;|&amp;quot; .. gamePattern .. &amp;quot;%s+&amp;quot;, &amp;quot;|&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renameLabels(results)&lt;br /&gt;
	local labels = {&lt;br /&gt;
		Mods = &amp;quot;Mod Archive&amp;quot;,&lt;br /&gt;
		Players = &amp;quot;Player Roster&amp;quot;,&lt;br /&gt;
		Clans = &amp;quot;Clan History&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for i, link in ipairs(results) do&lt;br /&gt;
		results[i] = link:gsub(&amp;quot;|([^%]]+)%]%]&amp;quot;, function(label)&lt;br /&gt;
			return &amp;quot;|&amp;quot; .. (labels[label] or label) .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sortSubpages(results)&lt;br /&gt;
	local order = {&lt;br /&gt;
		Mods = 1,&lt;br /&gt;
		Players = 2,&lt;br /&gt;
		Clans = 3,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	table.sort(results, function(a, b)&lt;br /&gt;
		-- Extract the final subpage name from the link target.&lt;br /&gt;
		local targetA = a:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
		local targetB = b:match(&amp;quot;^%[%[:.-/([^/|%]]+)|&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		local rankA = order[targetA] or math.huge&lt;br /&gt;
		local rankB = order[targetB] or math.huge&lt;br /&gt;
&lt;br /&gt;
		if rankA ~= rankB then&lt;br /&gt;
			return rankA &amp;lt; rankB&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Keep all remaining subpages alphabetically ordered.&lt;br /&gt;
		return (targetA or a) &amp;lt; (targetB or b)&lt;br /&gt;
	end)&lt;br /&gt;
&lt;br /&gt;
	return results&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getSubpages(page)&lt;br /&gt;
	local subpages = mw.smw.ask({&lt;br /&gt;
		&amp;quot;[[Has parent page::&amp;quot; .. page .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
	}) or {}&lt;br /&gt;
&lt;br /&gt;
	local subpageTable = {}&lt;br /&gt;
&lt;br /&gt;
	for _, subpage in ipairs(subpages) do&lt;br /&gt;
		local link = subpage[1]&lt;br /&gt;
&lt;br /&gt;
		if link then&lt;br /&gt;
			table.insert(subpageTable, link)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local allGames = string.format(&amp;quot;[[%s|%s]]&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;All Games&amp;quot;)&lt;br /&gt;
	table.insert(subpageTable, allGames)&lt;br /&gt;
&lt;br /&gt;
	removeGameFromLabels(subpageTable, page)&lt;br /&gt;
	renameLabels(subpageTable)&lt;br /&gt;
	sortSubpages(subpageTable)&lt;br /&gt;
&lt;br /&gt;
	if #subpageTable == 0 then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
&lt;br /&gt;
	local universe = html:tag(&amp;quot;div&amp;quot;):attr(&amp;quot;id&amp;quot;, &amp;quot;universeMenu&amp;quot;):wikitext(&amp;quot; | &amp;quot; .. table.concat(subpageTable, &amp;quot; | &amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return tostring(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatCellValue(value)&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local values = {}&lt;br /&gt;
&lt;br /&gt;
		for _, item in ipairs(value) do&lt;br /&gt;
			table.insert(values, tostring(item))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return table.concat(values, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDownloadLinks(value)&lt;br /&gt;
	if type(value) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return formatCellValue(value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local links = {}&lt;br /&gt;
&lt;br /&gt;
	for _, link in ipairs(value) do&lt;br /&gt;
		local formattedLink = formatCellValue(link)&lt;br /&gt;
&lt;br /&gt;
		if formattedLink ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			table.insert(links, formattedLink)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(links, &amp;quot;&amp;lt;br&amp;gt;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderModTable(content)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;assets&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Category&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has map type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has skin type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has mod type&amp;quot;]),&lt;br /&gt;
			formatCellValue(row[&amp;quot;Has utility type&amp;quot;])&lt;br /&gt;
		)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has game mode&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has developer&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has release date&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has status&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Has short description&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Works on game version&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatDownloadLinks(row[&amp;quot;Download links&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Related game&amp;quot;]))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderPlayerTable(content, panes)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, panes)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
		local clanAndRoleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			-- SMW may return either one value or a table of values.&lt;br /&gt;
			local memberships = type(member) == &amp;quot;table&amp;quot; and member or { member }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
				local query = {&lt;br /&gt;
					&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
					&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
					mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				local results = mw.smw.ask(query)&lt;br /&gt;
				local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
				local function addRoles(value)&lt;br /&gt;
					if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
						local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
						if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
							table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
					local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
					if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
						for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
							addRoles(roleValue)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						addRoles(resultRoles)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				if #clanRoles &amp;gt; 0 then&lt;br /&gt;
					local roleDivs = &amp;quot;&amp;lt;div&amp;gt;&amp;quot; .. table.concat(clanRoles, &amp;quot;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;quot;) .. &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
					table.insert(roleValues, roleDivs)&lt;br /&gt;
&lt;br /&gt;
					table.insert(&lt;br /&gt;
						clanAndRoleValues,&lt;br /&gt;
						string.format(&amp;quot;&amp;lt;div&amp;gt;%s (%s)&amp;lt;/div&amp;gt;&amp;quot;, formattedClan, table.concat(clanRoles, &amp;quot;, &amp;quot;))&lt;br /&gt;
					)&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(roleValues, &amp;quot;&amp;lt;div&amp;gt;—&amp;lt;/div&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
					table.insert(clanAndRoleValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
		local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
		if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
			activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanAndRoleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
		tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderClanPlayerTable(content, clanname)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clanpage = clanname&lt;br /&gt;
&lt;br /&gt;
	local wrapper = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	wrapper:attr(&amp;quot;id&amp;quot;, &amp;quot;players&amp;quot;):attr(&amp;quot;data-pane-columns&amp;quot;, &amp;quot;3, 5&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local tableNode = wrapper:tag(&amp;quot;table&amp;quot;)&lt;br /&gt;
	tableNode:addClass(&amp;quot;smwtable-clean&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for _, row in ipairs(content or {}) do&lt;br /&gt;
		local clanValues = {}&lt;br /&gt;
		local roleValues = {}&lt;br /&gt;
&lt;br /&gt;
		local member = row[&amp;quot;Member of&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if member then&lt;br /&gt;
			local memberships = { clanpage }&lt;br /&gt;
&lt;br /&gt;
			for _, clan in ipairs(memberships) do&lt;br /&gt;
				local formattedClan = formatCellValue(clan)&lt;br /&gt;
&lt;br /&gt;
				if formattedClan == clanpage then&lt;br /&gt;
					table.insert(clanValues, string.format(&amp;quot;&amp;lt;div&amp;gt;%s&amp;lt;/div&amp;gt;&amp;quot;, formattedClan))&lt;br /&gt;
&lt;br /&gt;
					local query = {&lt;br /&gt;
						&amp;quot;[[-Has subobject::&amp;quot; .. row[1] .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
						&amp;quot;?Has role#-=role&amp;quot;,&lt;br /&gt;
						mainlabel = &amp;quot;-&amp;quot;,&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					local results = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
					local clanRoles = {}&lt;br /&gt;
&lt;br /&gt;
					local function addRoles(value)&lt;br /&gt;
						if value == nil or value == &amp;quot;&amp;quot; then&lt;br /&gt;
							return&lt;br /&gt;
						end&lt;br /&gt;
&lt;br /&gt;
						for role in mw.text.gsplit(tostring(value), &amp;quot;,&amp;quot;, true) do&lt;br /&gt;
							local normalizedRole = mw.text.trim(role)&lt;br /&gt;
&lt;br /&gt;
							if normalizedRole ~= &amp;quot;&amp;quot; then&lt;br /&gt;
								table.insert(clanRoles, formatCellValue(normalizedRole))&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					for _, resultRow in ipairs(results or {}) do&lt;br /&gt;
						local resultRoles = resultRow.role&lt;br /&gt;
&lt;br /&gt;
						if type(resultRoles) == &amp;quot;table&amp;quot; then&lt;br /&gt;
							for _, roleValue in ipairs(resultRoles) do&lt;br /&gt;
								addRoles(roleValue)&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							addRoles(resultRoles)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					if #clanRoles &amp;gt; 0 then&lt;br /&gt;
						local roleDivs = table.concat(clanRoles, &amp;quot;, &amp;quot;)&lt;br /&gt;
						table.insert(roleValues, roleDivs)&lt;br /&gt;
					else&lt;br /&gt;
						table.insert(roleValues, &amp;quot;—&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local hasStatus = row[&amp;quot;Has status&amp;quot;]&lt;br /&gt;
				local activeClass = &amp;quot;text-danger&amp;quot;&lt;br /&gt;
				if hasStatus == &amp;quot;Active&amp;quot; then&lt;br /&gt;
					activeClass = &amp;quot;text-success&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local tr = tableNode:tag(&amp;quot;tr&amp;quot;)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[1])):addClass(activeClass)&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(formatCellValue(row[&amp;quot;Plays game&amp;quot;]))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(clanValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(table.concat(roleValues, &amp;quot;&amp;quot;))&lt;br /&gt;
				tr:tag(&amp;quot;td&amp;quot;):wikitext(hasStatus)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Mods(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game or &amp;quot;+&amp;quot;&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Mod[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Mod&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderModTable(content))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allMods(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Mods||Maps||Skins||Utilities]][[Related game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Related game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Category&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has mod type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has map type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has skin type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has utility type&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has game mode&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has developer&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has release date#-F[Y]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has short description&amp;quot;,&lt;br /&gt;
		&amp;quot;?Works on game version&amp;quot;,&lt;br /&gt;
		&amp;quot;?Download links&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderModTable(content, true))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Players(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Player&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Player[Plays game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Player Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Players&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.allPlayers(frame)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Players]][[Plays game::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderPlayerTable(content, &amp;quot;1, 2, 3, 5&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.clanPlayers(frame)&lt;br /&gt;
	local title = mw.title.getCurrentTitle()&lt;br /&gt;
	local clan = title.fullText&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Member of::&amp;quot; .. clan .. &amp;quot;]][[Modification date::+]]&amp;quot;,&lt;br /&gt;
		&amp;quot;?Plays game&amp;quot;,&lt;br /&gt;
		&amp;quot;?Member of&amp;quot;,&lt;br /&gt;
		&amp;quot;?Has status&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:node(renderClanPlayerTable(content, clan))&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.Clans(frame)&lt;br /&gt;
	local data = getCurrentGame()&lt;br /&gt;
	local game = data.game&lt;br /&gt;
	local resource = data.resource&lt;br /&gt;
&lt;br /&gt;
	mw.smw.set({&lt;br /&gt;
		[&amp;quot;Has parent page&amp;quot;] = game,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;quot;[[Category:Communities]][[Related game::&amp;quot; .. game .. &amp;quot;]]&amp;quot;,&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local content = mw.smw.ask(query)&lt;br /&gt;
&lt;br /&gt;
	local forminput = frame:callParserFunction({&lt;br /&gt;
		name = &amp;quot;#forminput&amp;quot;,&lt;br /&gt;
		&amp;quot;&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			&amp;quot;form=Community&amp;quot;,&lt;br /&gt;
			&amp;quot;query string=Community[Related game]=&amp;quot; .. game,&lt;br /&gt;
			&amp;quot;button text=Create or Edit Community Entry&amp;quot;,&lt;br /&gt;
			&amp;quot;autocomplete on category=Communities&amp;quot;,&lt;br /&gt;
			&amp;quot;autofocus=no&amp;quot;,&lt;br /&gt;
		},&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	setDisplayTitle(frame, string.format(&amp;quot;%s %s&amp;quot;, game, resource))&lt;br /&gt;
&lt;br /&gt;
	local html = mw.html.create()&lt;br /&gt;
	html:wikitext(getSubpages(game))&lt;br /&gt;
	html:wikitext(forminput)&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>WikiVisor</name></author>
	</entry>
</feed>