diff --git a/devNotes/slaveListing.md b/devNotes/slaveListing.md
new file mode 100644
index 0000000000000000000000000000000000000000..d0b061580cc506feb47dda71f877a704b81e47da
--- /dev/null
+++ b/devNotes/slaveListing.md
@@ -0,0 +1,144 @@
+# Producing slave lists
+
+The namespace `App.UI.SlaveList` provides functions for displaying lists of slaves and interacting with the slaves in those lists. These functions supersede (and extend) the `Slave Summary` passage. They provide a way to display a list, select a slave from a list, generate standard lists for a facility or a leader selection, as well as provide a way to customize output and interaction.
+
+## General concept
+
+The core function is `App.UI.SlaveList.render()`. It renders the list, assembling it from four pieces. The function is declared as follows:
+
+```js
+/**
+ * @param {number[]} indices
+ * @param {Array.<{index: number, rejects: string[]}>} rejectedSlaves
+ * @param {slaveTextGenerator} interactionLink
+ * @param {slaveTextGenerator} [postNote]
+ * @returns {string}
+ */
+function (indices, rejectedSlaves, interactionLink, postNote)
+```
+
+and the type of the `slaveTextGenerator` callback is:
+
+```js
+/**
+ * @callback slaveTextGenerator
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+```
+
+To build the output, the `render()` function iterates over the `indices` array, which must contain indices from the `$slaves` array, and outputs each slave using the two callbacks. The first one (`interactionLink`) is used to generate the hyperlink for the slave name. Output from the second callback (if defined) will be printed after each slave summary. The array of rejected slaves is processed after that and its contents are printed out in a simple fashion. The function *does not sort* both arrays, neither `indices` nor `rejectedSlaves`; their elements are printed in the order, specified by the caller. The function' output has to be passed via the SugarCube wikifier, for example by printing in out using the `<<print>>` macro.
+
+Let's consider a few examples.
+
+## Implementation examples
+
+### Basic printing
+
+The most common behavior for the slave name links is to go to the `Slave Interact` passage after clicking its name. This is implemented by the `App.UI.SlaveList.SlaveInteract.stdInteract` function:
+
+```js
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.stdInteract = (slave, index) =>
+   App.UI.passageLink(SlaveFullName(slave), 'Slave Interact', `$activeSlave = $slaves[${index}]`);
+```
+
+The function gets both the slave object and its index in the `$slaves` array for convenience, and outputs a hyperlink in the HTML markup. which points to the `Slave Interact` passage and sets active slave to the slave with the given index, because `Slave Interact` operates with the current slave. In the SugarCube markup the function could look as follows:
+
+```js
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.stdInteract = (slave, index) =>
+  `<<link "${SlaveFullName(slave)}" "Slave Interact">><<set $activeSlave = $slaves[${index}]`;
+```
+Now we can print slave lists. Let's print first three from the `$slaves` array:
+
+```
+<<print App.UI.SlaveList.render(
+   [0, 1, 2], [].
+   App.UI.SlaveList.SlaveInteract.stdInteract
+)>>
+```
+
+Let's print them in the reverse order:
+
+```
+<<print App.UI.SlaveList.render(
+   [2, 1, 0], [].
+   App.UI.SlaveList.SlaveInteract.stdInteract
+)>>
+```
+
+and one more time omitting the second slave:
+
+```
+<<print App.UI.SlaveList.render(
+   [0, 2],
+   [{index: 1, rejects: ['Omitted for testing purposes']}].
+   App.UI.SlaveList.SlaveInteract.stdInteract
+)>>
+```
+
+### Post-notes
+
+The post notes are little text pieces, printed after each slave. They can contain simple text, for example to inform that particular slave is special in a way, or provide additional action hyperlinks. The most common type of the post notes is a hyperlink for assigning or retrieving s slave from a facility. Here are their implementations:
+
+```js
+(slave, index) => App.UI.passageLink(`Send ${slave.object} to ${facility.name}`, "Assign", `$i = ${index}`);
+
+(slave, index) => App.UI.passageLink(`Retrieve ${slave.object} from ${facility.name}`, "Retrieve", `$i = ${index}`);
+```
+
+With these blocks we can easily produce a list of slaves, working at a given facility `facility`.
+
+First, let's get the indices of the workers:
+
+```js
+let facilitySlaves = facility.job().employeesIndices();
+```
+
+The `App.Entity.Facilities.Facility.job()` call returns a named job if it was given an argument, or the default job when argument was omitted. Pretty much every facility except the penthouse provides only a single job and we can safely omit the job name here.
+
+Now just call the `render()` function:
+
+```js
+App.UI.SlaveList.render(facilitySlaves, [],
+	App.UI.SlaveList.SlaveInteract.stdInteract,
+   (slave, index) => App.UI.passageLink(`Retrieve ${slave.object} from ${facility.name}`, "Retrieve", `$i = ${index}`));
+```
+
+That's it, works with any facility.
+
+Here we omitted a few details, like setting the `$returnTo` bookmark for the `Assign` and `Retrieve` passages, sorting the slaves lists, and a few more.
+
+### Templates for common use cases
+
+There are functions in the `App.UI.SlaveList` namespace for a few typical use cases.
+
+Function | Purpose
+----- | ----
+`listSJFacilitySlaves()` | Creates a tabbed list for assigning and retrieving slaves t0/from a facility with a single job
+`displayManager()` | Displays a facility manager with a link to change it or a note with a link to assign a manager
+`stdFacilityPage()` | Combines the previous two functions to render the manager and employees
+`penthousePage()` | Displays tabs with workers for the penthouse
+`slaveSelectionList()` | Displays a list with filtering and sorting links for selecting a slave
+`facilityManagerSelection()` | Specialization of the `slaveSelectionList()` to select a manager for a facility, which implements position requirements tests and highlights experienced slaves
+
+### Fully custom lists
+
+There are use cases that stand apart from all other, and there is no point in providing a template for them. In that case you can generate a totally custom list. Here is an example:
+
+```
+<<print App.UI.SlaveList.slaveSelectionList(
+	s => !ruleSlaveExcluded(s, $currentRule),
+	(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Exclude Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+)>>
+```
diff --git a/devTools/sugarcube.d.ts b/devTools/sugarcube.d.ts
index eb6c41221c6189eed979215c160f377ba31ced22..ab02ab3683a558c1c23b60d8e8604270b04fe307 100644
--- a/devTools/sugarcube.d.ts
+++ b/devTools/sugarcube.d.ts
@@ -2034,6 +2034,12 @@ declare global {
 		 */
 		static trunc(num: number): number;
 	}
+
+	interface JQuery {
+		wikiWithOptions(options: any, ...sources): JQuery;
+		wiki(...sources): JQuery;
+	};
+
 }
 
 export { };
diff --git a/src/002-config/fc-js-init.js b/src/002-config/fc-js-init.js
index ac9952a0afb2abe8180f2640b8c77c2fafb91d9d..db6fa2d707a9b7db2146d4b5cd9f65e8c04a336b 100644
--- a/src/002-config/fc-js-init.js
+++ b/src/002-config/fc-js-init.js
@@ -4,8 +4,8 @@
 * does not work.
 */
 window.App = { };
-// the same declaration for code parsers that don't line the line above
-let App = window.App || {};
+// the same declaration for code parsers that don't like the line above
+var App = window.App || {};
 
 App.Data = {};
 App.Debug = {};
diff --git a/src/002-config/mousetrapConfig.js b/src/002-config/mousetrapConfig.js
index a2a99786b0c3ac330eaa2cbf5e30f16258ca5ec6..b9a4777df342dc25c94783024359336a9042b1f8 100644
--- a/src/002-config/mousetrapConfig.js
+++ b/src/002-config/mousetrapConfig.js
@@ -50,7 +50,7 @@ Mousetrap.bind("f", function() {
 	$("#walkpast a.macro-link").trigger("click");
 });
 Mousetrap.bind("h", function() {
-	$("#manageHG a.macro-link").trigger("click");
+	$("#manageHG a").trigger("click");
 });
 Mousetrap.bind("s", function() {
 	$("#buySlaves a.macro-link").trigger("click");
@@ -59,10 +59,10 @@ Mousetrap.bind("a", function() {
 	$("#managePA a.macro-link").trigger("click");
 });
 Mousetrap.bind("b", function() {
-	$("#manageBG a.macro-link").trigger("click");
+	$("#manageBG a").trigger("click");
 });
 Mousetrap.bind("u", function() {
-	$("#manageRecruiter a.macro-link").trigger("click");
+	$("#manageRecruiter a").trigger("click");
 });
 Mousetrap.bind("o", function() {
 	$("#story-caption #optionsButton a.macro-link").trigger("click");
diff --git a/src/004-base/facility.js b/src/004-base/facility.js
index daad5234e2973bf1f27c1501e7885de3a19c6351..13de061f875f89e92f7fda30b82d013aedb0a235 100644
--- a/src/004-base/facility.js
+++ b/src/004-base/facility.js
@@ -5,6 +5,7 @@ App.Data.JobDesc = class {
 		this.assignment = "";
 		this.publicSexUse = false;
 		this.fuckdollAccepted = false;
+		/** @type {boolean|undefined} */
 		this.broodmotherAccepted = false;
 	}
 };
@@ -96,7 +97,6 @@ App.Entity.Facilities.Job = class {
 	}
 
 	/**
-	 *
 	 * @callback linkCallback
 	 * @param {string} assignment new assignment
 	 * @returns {string} code to include into the <<link>><</link>>
@@ -116,6 +116,23 @@ App.Entity.Facilities.Job = class {
 		return `<<link "${linkText}"${passage !== undefined ? ' "' + passage + '"' : ''}>><<= assignJob(${App.Utils.slaveRefString(i)}, "${this.desc.assignment}")>>${linkAction}<</link>>`;
 	}
 
+	/**
+	 * all slaves that are employed at this job
+	 * @returns {App.Entity.SlaveState[]}
+	 */
+	employees() {
+		return State.variables.slaves.filter( s => s.assignment === this.desc.assignment);
+	}
+
+	/**
+	 * Indices in the slaves array for all slaves that are employed at this job
+	 * @returns {number[]}
+	 */
+	employeesIndices() {
+		return State.variables.slaves.reduce(
+			(acc, cur, idx) => { if (cur.assignment === this.desc.assignment) { acc.push(idx); } return acc; }, []);
+	}
+
 	/**
 	 * Tests if slave is broken enough
 	 * @protected
@@ -146,9 +163,7 @@ App.Entity.Facilities.Job = class {
 		return `${slave.slaveName} must be either more fearful of you or devoted to you.`;
 	}
 
-	/**
-	 * @private
-	 */
+	/** @private */
 	get _facilityHasFreeSpace() {
 		return this.facility.hasFreeSpace;
 	}
@@ -198,9 +213,13 @@ App.Entity.Facilities.ManagingJob = class extends App.Entity.Facilities.Job {
 			(typeof slave.career === 'string' && this.desc.careers.includes(slave.career));
 	}
 
-	/**
-	 * @private
-	 */
+	/** @returns {App.Entity.SlaveState} */
+	get currentEmployee() {
+		const obj = State.variables[capFirstChar(this.desc.position)];
+		return obj === undefined ? null : obj;
+	}
+
+	/** @private */
 	get _facilityHasFreeSpace() {
 		return true;
 	}
@@ -218,13 +237,11 @@ App.Entity.Facilities.Facility = class {
 		/** @private @type {Object.<string, App.Entity.Facilities.Job>} */
 		this._jobs = {};
 
-		// if this facility provides only a single job
-		const singleJobFacility = Object.keys(this.desc.jobs).length === 1;
 		for (const jn in this.desc.jobs) {
 			if (jobs[jn] !== undefined) {
 				this._jobs[jn] = jobs[jn];
 			} else {
-				this._jobs[jn] = singleJobFacility ? new App.Entity.Facilities.FacilitySingleJob() : new App.Entity.Facilities.Job();
+				this._jobs[jn] = this._createJob(jn);
 			}
 			this._jobs[jn].facility = this;
 			this._jobs[jn].desc = desc.jobs[jn];
@@ -264,11 +281,11 @@ App.Entity.Facilities.Facility = class {
 
 	/**
 	 * Returns job description
-	 * @param {string} name
+	 * @param {string} [name] job name; the default job will be used if omitted
 	 * @returns {App.Entity.Facilities.Job}
 	 */
 	job(name) {
-		return this._jobs[name];
+		return this._jobs[name || this.desc.defaultJob];
 	}
 
 	get manager() {
@@ -296,7 +313,6 @@ App.Entity.Facilities.Facility = class {
 	}
 
 	/**
-	 *
 	 * @param {string} name
 	 * @returns {number}
 	 */
@@ -305,7 +321,6 @@ App.Entity.Facilities.Facility = class {
 	}
 
 	/**
-	 *
 	 * @param {string} name
 	 * @returns {number}
 	 */
@@ -340,7 +355,7 @@ App.Entity.Facilities.Facility = class {
 	 */
 	isHosted(slave) {
 		for (const j in this._jobs) {
-			if (this._jobs[j].isEmployed(slave)) return true;
+			if (this._jobs[j].isEmployed(slave)) { return true; }
 		}
 
 		return false;
@@ -384,6 +399,48 @@ App.Entity.Facilities.Facility = class {
 		job = job || this.desc.defaultJob;
 		return this._jobs[job].assignmentLink(i, passage, callback, this.genericName);
 	}
+
+	/**
+	 * all slaves that are employed at this job
+	 * @returns {App.Entity.SlaveState[]}
+	 */
+	employees() {
+		if (Object.keys(this._jobs).length === 1) {
+			return this.job().employees();
+		}
+		/** @type {App.Entity.Facilities.Job[]} */
+		let jobArray = [];
+		for (const jn in this._jobs) {
+			jobArray.push(this._jobs[jn]);
+		}
+		return State.variables.slaves.filter(s => jobArray.some(j => j.isEmployed(s)));
+	}
+
+	/**
+	 * Indices in the slaves array for all slaves that are employed at this job
+	 * @returns {number[]}
+	 */
+	employeesIndices() {
+		if (Object.keys(this._jobs).length === 1) {
+			return this.job().employeesIndices();
+		}
+		/** @type {App.Entity.Facilities.Job[]} */
+		let jobArray = [];
+		for (const jn in this._jobs) {
+			jobArray.push(this._jobs[jn]);
+		}
+		return State.variables.slaves.reduce(
+			(acc, cur, idx) => { if (jobArray.some(j => j.isEmployed(cur))) { acc.push(idx); } }, []);
+	}
+
+	/**
+	 * @protected
+	 * @param {string} jobName
+	 * @returns {App.Entity.Facilities.Job}
+	 */
+	_createJob(jobName) { /* eslint-disable-line no-unused-vars*/
+		return new App.Entity.Facilities.Job();
+	}
 };
 
 /**
@@ -404,6 +461,37 @@ App.Entity.Facilities.FacilitySingleJob = class extends App.Entity.Facilities.Jo
 		const psg = passage === undefined ? '' : `, $returnTo = "${passage}"`;
 		return `<<link "${linkText}" "Assign">><<set $assignTo = "${this.facility.genericName}", $i = ${i}${psg}>>${linkAction}<</link>>`;
 	}
+
+	/** @returns {number[]} */
+	employeesIndices() {
+		const V = State.variables;
+		const si = V.slaveIndices;
+		const ids = V[this._employeeIDsVariableName]; // updated by assignJob()/removeJob()
+		return ids.map(id => si[id]);
+	}
+
+	/** @returns {App.Entity.SlaveState[]} */
+	employees() {
+		/** @type {App.Entity.SlaveState[]} */
+		const slaves = State.variables.slaves;
+		return this.employeesIndices().map(ind => slaves[ind]);
+	}
+
+	/** @private */
+	get _employeeIDsVariableName() {
+		return this.facility.genericName + "iIDs";
+	}
+};
+
+App.Entity.Facilities.SingleJobFacility = class extends App.Entity.Facilities.Facility {
+	/**
+	 * @override
+	 * @protected
+	 * @returns {App.Entity.Facilities.FacilitySingleJob}
+	 */
+	_createJob() {
+		return new App.Entity.Facilities.FacilitySingleJob();
+	}
 };
 
 /** Instances of all facility objects */
diff --git a/src/Mods/DinnerParty/dinnerPartyPreparations.tw b/src/Mods/DinnerParty/dinnerPartyPreparations.tw
index fd37212d85e2c3a018137e47eac4d6659ef87929..091bd34d39c71c5b79acb9540388eed509db9d65 100644
--- a/src/Mods/DinnerParty/dinnerPartyPreparations.tw
+++ b/src/Mods/DinnerParty/dinnerPartyPreparations.tw
@@ -29,9 +29,12 @@ Your assistant will take care of the invitations and all the arrangements; all y
 
 __Select Your Meat:__
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<= App.UI.SlaveList.slaveSelectionList(
+		s => s.assignmentVisible === 1 && s.fuckdoll === 0,
+		App.UI.SlaveList.SlaveInteract.stdInteract,
+		null,
+		(s, i) => {
+			const p = getPronouns(s);
+			return App.UI.passageLink(`Make ${p.her} the main course`, "Dinner Party Execution", `$activeSlave = $slaves[${i}]`)
+		}
+	)>>
diff --git a/src/facilities/arcade/arcadeFramework.js b/src/facilities/arcade/arcadeFramework.js
index 94a45cb9507cf7c2ba5be7ede767095e94d08d2d..1b171533a51691353348a57c554d82f4cd7ee2e8 100644
--- a/src/facilities/arcade/arcadeFramework.js
+++ b/src/facilities/arcade/arcadeFramework.js
@@ -28,7 +28,7 @@ App.Entity.Facilities.ArcadeJob = class extends App.Entity.Facilities.FacilitySi
 	}
 };
 
-App.Entity.facilities.arcade = new App.Entity.Facilities.Facility(
+App.Entity.facilities.arcade = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.arcade,
 	{
 		assignee: new App.Entity.Facilities.ArcadeJob()
diff --git a/src/facilities/armory/armoryFramework.js b/src/facilities/armory/armoryFramework.js
index a29228bbf9599e64ba131ebac90ee4636bfb22f2..a7ce091028e44c676b1103707404b889e520190e 100644
--- a/src/facilities/armory/armoryFramework.js
+++ b/src/facilities/armory/armoryFramework.js
@@ -20,6 +20,6 @@ App.Data.Facilities.armory = {
 	}
 };
 
-App.Entity.facilities.armory = new App.Entity.Facilities.Facility(
+App.Entity.facilities.armory = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.armory
 );
diff --git a/src/facilities/brothel/brothelFramework.js b/src/facilities/brothel/brothelFramework.js
index f473d68dfdb6e67e68adda358543d1f6f99b9e5a..1b36b3c1fd13492799ac7a68395b311632a5b3fb 100644
--- a/src/facilities/brothel/brothelFramework.js
+++ b/src/facilities/brothel/brothelFramework.js
@@ -29,6 +29,7 @@ App.Data.Facilities.brothel = {
 
 App.Entity.Facilities.BrothelJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
+	 * @override
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
@@ -41,6 +42,11 @@ App.Entity.Facilities.BrothelJob = class extends App.Entity.Facilities.FacilityS
 		}
 		return r;
 	}
+
+	/** @private @override */
+	get _employeeIDsVariableName() {
+		return "BrothiIDs";
+	}
 };
 
 App.Entity.Facilities.MadamJob = class extends App.Entity.Facilities.ManagingJob {
@@ -57,7 +63,7 @@ App.Entity.Facilities.MadamJob = class extends App.Entity.Facilities.ManagingJob
 	}
 };
 
-App.Entity.facilities.brothel = new App.Entity.Facilities.Facility(
+App.Entity.facilities.brothel = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.brothel,
 	{
 		assignee: new App.Entity.Facilities.BrothelJob()
diff --git a/src/facilities/cellblock/cellblockFramework.js b/src/facilities/cellblock/cellblockFramework.js
index e6842c356dac68e339eb9b5e9b6bf496695d5ed0..d046dd39b9b16c5282640702e6599957c5918764 100644
--- a/src/facilities/cellblock/cellblockFramework.js
+++ b/src/facilities/cellblock/cellblockFramework.js
@@ -42,9 +42,14 @@ App.Entity.Facilities.CellblockJob = class extends App.Entity.Facilities.Facilit
 
 		return r;
 	}
+
+	/** @private @override */
+	get _employeeIDsVariableName() {
+		return "CellBiIDs";
+	}
 };
 
-App.Entity.facilities.cellblock = new App.Entity.Facilities.Facility(
+App.Entity.facilities.cellblock = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.cellblock,
 	{
 		assignee: new App.Entity.Facilities.CellblockJob()
diff --git a/src/facilities/clinic/clinicFramework.js b/src/facilities/clinic/clinicFramework.js
index 8a434b156811e41d74ce17f1928c6459e907ac8a..676e9956afd0de0e7b63e247ef91acc32b689c78 100644
--- a/src/facilities/clinic/clinicFramework.js
+++ b/src/facilities/clinic/clinicFramework.js
@@ -47,7 +47,7 @@ App.Entity.Facilities.ClinicPatientJob = class extends App.Entity.Facilities.Fac
 	}
 };
 
-App.Entity.facilities.clinic = new App.Entity.Facilities.Facility(
+App.Entity.facilities.clinic = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.clinic,
 	{
 		patient: new App.Entity.Facilities.ClinicPatientJob()
diff --git a/src/facilities/club/clubFramework.js b/src/facilities/club/clubFramework.js
index f6ae8529c44c0b32305989bb2498c0f0a1ccf3a4..d797c0a2a3cafc087fa6a46178b6e1086c82263a 100644
--- a/src/facilities/club/clubFramework.js
+++ b/src/facilities/club/clubFramework.js
@@ -55,7 +55,7 @@ App.Entity.Facilities.ClubDJJob = class extends App.Entity.Facilities.ManagingJo
 	}
 };
 
-App.Entity.facilities.club = new App.Entity.Facilities.Facility(
+App.Entity.facilities.club = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.club,
 	{
 		slut: new App.Entity.Facilities.ClubSlutJob()
diff --git a/src/facilities/dairy/dairyFramework.js b/src/facilities/dairy/dairyFramework.js
index bc9610fba9387d227043668f8288ddecdd1b4035..0aaf95e3fa6459219f0717b9f5aafdaa5ded4a61 100644
--- a/src/facilities/dairy/dairyFramework.js
+++ b/src/facilities/dairy/dairyFramework.js
@@ -71,7 +71,7 @@ App.Entity.Facilities.DairyCowJob = class extends App.Entity.Facilities.Facility
 	}
 };
 
-App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.Facility {
+App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.SingleJobFacility {
 	constructor() {
 		super(App.Data.Facilities.dairy,
 			{
diff --git a/src/facilities/farmyard/farmerSelect.tw b/src/facilities/farmyard/farmerSelect.tw
index 13c285477727f7eb52709eab86b1b3ee31301f06..0ba102d974ca9897a6603d2920c634332c32698b 100644
--- a/src/facilities/farmyard/farmerSelect.tw
+++ b/src/facilities/farmyard/farmerSelect.tw
@@ -1,7 +1,6 @@
 :: Farmer Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Farmyard", $showEncyclopedia = 1, $encyclopedia = "Farmer">>
-<<showallAssignmentFilter>>
 <<if ($Farmer != 0)>>
 	<<set $Farmer = getSlave($Farmer.ID)>>
 	<<setLocalPronouns $Farmer>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Farmer from your obedient slaves:''
 <br><br>[[None|Farmer Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.farmyard)>>
diff --git a/src/facilities/farmyard/farmyard.tw b/src/facilities/farmyard/farmyard.tw
index 4fd08e8b134738d84c98fdb140e61b2a9ef0e60d..a731363f184b18d0dc96099b8448bfa1509020b6 100644
--- a/src/facilities/farmyard/farmyard.tw
+++ b/src/facilities/farmyard/farmyard.tw
@@ -11,7 +11,6 @@
 
 <<set _CL = $canines.length, _HL = $hooved.length, _FL = $felines.length>>
 
-<<farmyardAssignmentFilter>>
 $farmyardNameCaps is an oasis of growth in the midst of the jungle of steel and concrete that is $arcologies[0].name. Animals are kept in pens, tended to by your slaves, while <<if $farmyardUpgrade.hydroponics == 1>>rows of hydroponics equipment<<else>>makeshift fields<</if>> grow crops.
 <<switch $farmyardDecoration>>
 <<case "Roman Revivalist">>
@@ -462,52 +461,7 @@ $farmyardNameCaps is an oasis of growth in the midst of the jungle of steel and
 </span>
 
 <br><hr><br>
-<<if $Farmer != 0>>
-<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a Farmer. [[Appoint one|Farmer Select]]
-<</if>>
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($farmyard <= $farmyardSlaves)>>
-			''$farmyardNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $farmyardSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $farmyardSlaves > 0>>
-			<<farmyardAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$farmyardNameCaps is empty for the moment.//
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Farmyard == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
 
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.farmyard)>>
 
 <br><br>Rename $farmyardName: <<textbox "$farmyardName" $farmyardName "Farmyard">> //Use a noun or similar short phrase//
diff --git a/src/facilities/farmyard/farmyardFramework.js b/src/facilities/farmyard/farmyardFramework.js
index d5075570cdfb6dfcea0cac080d183bfa5560a482..3d7496571ae1ad1b7bbf4cd3c6f9ca2c11ba3386 100644
--- a/src/facilities/farmyard/farmyardFramework.js
+++ b/src/facilities/farmyard/farmyardFramework.js
@@ -27,6 +27,6 @@ App.Data.Facilities.farmyard = {
 	}
 };
 
-App.Entity.facilities.farmyard = new App.Entity.Facilities.Facility(
+App.Entity.facilities.farmyard = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.farmyard
 );
diff --git a/src/facilities/headGirlSuite/headGirlSuiteFramework.js b/src/facilities/headGirlSuite/headGirlSuiteFramework.js
index fc8270e292afa40613c3e4ffb858c75875d62fd0..7e1827b931885d821eb9be949e48ca53b30d9afd 100644
--- a/src/facilities/headGirlSuite/headGirlSuiteFramework.js
+++ b/src/facilities/headGirlSuite/headGirlSuiteFramework.js
@@ -27,6 +27,6 @@ App.Data.Facilities.headGirlSuite = {
 	}
 };
 
-App.Entity.facilities.headGirlSuite = new App.Entity.Facilities.Facility(
+App.Entity.facilities.headGirlSuite = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.headGirlSuite
 );
diff --git a/src/facilities/masterSuite/masterSuiteFramework.js b/src/facilities/masterSuite/masterSuiteFramework.js
index 640ea2361bc4e4302e961d0d5d2ef9732934610c..ccfaa1b637b79c131b3eb6d40dc05afa0b250cdd 100644
--- a/src/facilities/masterSuite/masterSuiteFramework.js
+++ b/src/facilities/masterSuite/masterSuiteFramework.js
@@ -52,7 +52,7 @@ App.Entity.Facilities.ConcubineJob = class extends App.Entity.Facilities.Managin
 	}
 };
 
-App.Entity.facilities.masterSuite = new App.Entity.Facilities.Facility(
+App.Entity.facilities.masterSuite = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.masterSuite,
 	{
 		fucktoy: new App.Entity.Facilities.MasterSuiteFuckToyJob()
diff --git a/src/facilities/nursery/matronSelect.tw b/src/facilities/nursery/matronSelect.tw
index a51bca44fa9ec762d41b38c9adaadc5312e6a208..a6d934a53ca0b954bf38d2b4bc03df3ff6241cb0 100644
--- a/src/facilities/nursery/matronSelect.tw
+++ b/src/facilities/nursery/matronSelect.tw
@@ -1,7 +1,6 @@
 :: Matron Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Nursery", $showEncyclopedia = 1, $encyclopedia = "Matron">>
-<<showallAssignmentFilter>>
 <<if ($Matron != 0)>>
 	<<set $Matron = getSlave($Matron.ID)>>
 	<<setLocalPronouns $Matron>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Matron from your devoted slaves:''
 <br><br>[[None|Matron Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.nursery)>>
diff --git a/src/facilities/nursery/nursery.tw b/src/facilities/nursery/nursery.tw
index 0336df455a88cee7233ef9663b7ef8a8a249e178..567bf19cda7aefd74a63b225e0c33650e093500b 100644
--- a/src/facilities/nursery/nursery.tw
+++ b/src/facilities/nursery/nursery.tw
@@ -1,6 +1,6 @@
 :: Nursery [nobr]
 
-<<set $nextButton = "Back to Main", $nextLink = "Main", $returnTo = "Nursery", $showEncyclopedia = 1, $encyclopedia = "Nursery", $nurserySlaves = $NurseryiIDs.length, $SlaveSummaryFiler = "assignable">>
+<<set $nextButton = "Back to Main", $nextLink = "Main", $returnTo = "Nursery", $showEncyclopedia = 1, $encyclopedia = "Nursery", $nurserySlaves = $NurseryiIDs.length>>
 <<set $targetAgeNursery = Number($targetAgeNursery) || $minimumSlaveAge>>
 <<set $targetAgeNursery = Math.clamp($targetAgeNursery, $minimumSlaveAge, 42)>>
 
@@ -10,7 +10,6 @@
 
 <<set $nurseryBabies = $cribs.length, $freeCribs = $nursery - $nurseryBabies, _SL = $slaves.length, _eligibility = 0, $reservedChildren = FetusGlobalReserveCount("incubator"), $reservedChildrenNursery = FetusGlobalReserveCount("nursery")>>
 
-<<nurseryAssignmentFilter>>
 $nurseryNameCaps
 <<switch $nurseryDecoration>>
 <<case "Roman Revivalist">>
@@ -117,52 +116,7 @@ $nurseryNameCaps
 <</if>>
 
 <br><br>
-<<if $Matron != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a Matron. [[Appoint one|Matron Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $nurserySlaves > 0>>
-			<<nurseryAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$nurseryNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($nurseryNannies <= $nurserySlaves)>>
-			''$nurseryNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $nurserySlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Nursery == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.nursery)>>
 
 <br><br>It can support $nursery child<<if $nursery != 1>>ren<</if>>. There <<if $nurseryBabies == 1>>is<<else>>are<</if>> currently $nurseryBabies room<<if $nurseryBabies != 1>>s<</if>> in use in $nurseryName.
 <<if $nursery < 50>>
@@ -487,8 +441,8 @@ Target age for release: <<textbox "$targetAgeNursery" $targetAgeNursery "Nursery
 	<body>
 
 	<div class="tab">
-		<button class="tablinks" onclick="opentab(event, 'resting')">Resting</button>
-		<button class="tablinks" onclick="opentab(event, 'all')" id="defaultButton">All</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'resting')">Resting</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'all')" id="defaultButton">All</button>
 	</div>
 
 	<div id="resting" class="tabcontent">
@@ -508,7 +462,7 @@ Target age for release: <<textbox "$targetAgeNursery" $targetAgeNursery "Nursery
 	</div>
 
 	<script>
-	function opentab(evt, tabName) {
+	function App.UI.tabbar.openTab(evt, tabName) {
 		var i, tabcontent, tablinks;
 		tabcontent = document.getElementsByClassName("tabcontent");
 		for (i = 0; i < tabcontent.length; i++) {
diff --git a/src/facilities/nursery/nurseryFramework.js b/src/facilities/nursery/nurseryFramework.js
index ec47485e7ac99e5180b424baf8a073caebb019eb..563c74245b26aa3bee87c3978ecd6e060c25f939 100644
--- a/src/facilities/nursery/nurseryFramework.js
+++ b/src/facilities/nursery/nurseryFramework.js
@@ -43,7 +43,7 @@ App.Entity.Facilities.NurseryNannyJob = class extends App.Entity.Facilities.Faci
 	}
 };
 
-App.Entity.facilities.nursery = new App.Entity.Facilities.Facility(
+App.Entity.facilities.nursery = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.nursery,
 	{
 		nanny: new App.Entity.Facilities.NurseryNannyJob()
diff --git a/src/facilities/penthouse/penthouseFramework.js b/src/facilities/penthouse/penthouseFramework.js
index 686669d7aed2528dcfeef7c603741c8061608908..0b4403e8d697b3361bbe922b3a6e8b776a07dd73 100644
--- a/src/facilities/penthouse/penthouseFramework.js
+++ b/src/facilities/penthouse/penthouseFramework.js
@@ -9,6 +9,12 @@ App.Data.Facilities.penthouse = {
 			publicSexUse: false,
 			fuckdollAccepted: false
 		},
+		chooseOwn: {
+			position: "Choose own",
+			assignment: "choose her own job",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
 		fucktoy: {
 			position: "Fucktoy",
 			assignment: "please you",
@@ -81,9 +87,25 @@ App.Data.Facilities.penthouse = {
 		requiredDevotion: 51
 	}
 };
-
 App.Entity.Facilities.PenthouseJob = class extends App.Entity.Facilities.Job {
+	/**
+	 * @override
+	 * @returns {number[]} */
+	employeesIndices() {
+		const employees = State.variables.JobIDArray[this.desc.assignment];
+		if (!employees) { return []; }
+		const si = State.variables.slaveIndices;
+		return employees.map(id => si[id]);
+	}
 
+	/**
+	 * @override
+	 * @returns {App.Entity.SlaveState[]}
+	 */
+	employees() {
+		const slaves = State.variables.slaves;
+		return this.employeesIndices().map(idx => slaves[idx]);
+	}
 };
 
 App.Entity.Facilities.PenthouseJobs = {
@@ -156,7 +178,7 @@ App.Entity.Facilities.Penthouse = class extends App.Entity.Facilities.Facility {
 			classes: new App.Entity.Facilities.PenthouseJobs.Classes(),
 			houseServant: new App.Entity.Facilities.PenthouseJobs.HouseServant(),
 			subordinateSlave: new App.Entity.Facilities.PenthouseJobs.SubordinateSlave(),
-			cow: new App.Entity.Facilities.PenthouseJobs.Cow()
+			cow: new App.Entity.Facilities.PenthouseJobs.Cow(),
 		});
 	}
 
@@ -171,6 +193,36 @@ App.Entity.Facilities.Penthouse = class extends App.Entity.Facilities.Facility {
 	get hostedSlaves() {
 		return State.variables.dormitoryPopulation;
 	}
+
+	/**
+	 *
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {boolean}
+	 */
+	isHosted(slave) {
+		return slave.assignmentVisible === 1;
+	}
+
+	/**
+	 * all slaves that are at the penthouse
+	 * @returns {App.Entity.SlaveState[]}
+	 */
+	employees() {
+		return State.variables.slaves.filter( s => s.assignmentVisible === 1);
+	}
+
+	/**
+	 * Indices in the slaves array for all slaves that are at the penthouse
+	 * @returns {number[]}
+	 */
+	employeesIndices() {
+		return State.variables.slaves.reduce(
+			(acc, cur, idx) => { if (cur.assignmentVisible === 1) { acc.push(idx); } return acc; }, []);
+	}
+
+	_createJob() {
+		return new App.Entity.Facilities.PenthouseJob();
+	}
 };
 
 App.Entity.facilities.penthouse = new App.Entity.Facilities.Penthouse();
diff --git a/src/facilities/pit/pitFramework.js b/src/facilities/pit/pitFramework.js
index cffe4e9e00ec770663e394fd135c2961d32ff518..42bec475f68033b5856c16efad19db8c024fc68e 100644
--- a/src/facilities/pit/pitFramework.js
+++ b/src/facilities/pit/pitFramework.js
@@ -35,9 +35,15 @@ App.Entity.Facilities.PitFighterJob = class extends App.Entity.Facilities.Facili
 	isEmployed(slave) {
 		return State.variables.fighterIDs.includes(slave.ID);
 	}
+
+	employeesIndices() {
+		const V = State.variables;
+		const si = V.slaveIndices;
+		return V.fighterIDs.map(id => si[id]);
+	}
 };
 
-App.Entity.Facilities.Pit = class extends App.Entity.Facilities.Facility {
+App.Entity.Facilities.Pit = class extends App.Entity.Facilities.SingleJobFacility {
 	constructor() {
 		super(App.Data.Facilities.pit,
 			{
@@ -45,8 +51,12 @@ App.Entity.Facilities.Pit = class extends App.Entity.Facilities.Facility {
 			});
 	}
 
+	get capacity() {
+		return State.variables[this.desc.baseName] > 0 ? Number.MAX_VALUE : 0;
+	}
+
 	get hostedSlaves() {
-		return 0; // does not host anyone
+		return State.variables.fighterIDs.length;
 	}
 };
 
diff --git a/src/facilities/schoolroom/schoolroomFramework.js b/src/facilities/schoolroom/schoolroomFramework.js
index 707d7989a66cc9a791206b7998310ac1683f7f90..da0a7493e7d4a6393a6b64668a1817b48847b1fa 100644
--- a/src/facilities/schoolroom/schoolroomFramework.js
+++ b/src/facilities/schoolroom/schoolroomFramework.js
@@ -52,9 +52,14 @@ App.Entity.Facilities.SchoolroomStudentJob = class extends App.Entity.Facilities
 
 		return r;
 	}
+
+	/** @private @override */
+	get _employeeIDsVariableName() {
+		return "SchlRiIDs";
+	}
 };
 
-App.Entity.facilities.schoolroom = new App.Entity.Facilities.Facility(
+App.Entity.facilities.schoolroom = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.schoolroom,
 	{
 		student: new App.Entity.Facilities.SchoolroomStudentJob()
diff --git a/src/facilities/servantsQuarters/servantsQuartersFramework.js b/src/facilities/servantsQuarters/servantsQuartersFramework.js
index af38738066e090a5de3bdd6ff10cb5aaf71b229c..0afe7f14167529063337e2f22178e71d2ce3cab2 100644
--- a/src/facilities/servantsQuarters/servantsQuartersFramework.js
+++ b/src/facilities/servantsQuarters/servantsQuartersFramework.js
@@ -46,6 +46,11 @@ App.Entity.Facilities.ServantsQuartersServantJob = class extends App.Entity.Faci
 		}
 		return r;
 	}
+
+	/** @private @override */
+	get _employeeIDsVariableName() {
+		return "ServQiIDs";
+	}
 };
 
 App.Entity.Facilities.ServantsQuartersStewardessJob = class extends App.Entity.Facilities.ManagingJob {
@@ -62,7 +67,7 @@ App.Entity.Facilities.ServantsQuartersStewardessJob = class extends App.Entity.F
 	}
 };
 
-App.Entity.facilities.servantsQuarters = new App.Entity.Facilities.Facility(
+App.Entity.facilities.servantsQuarters = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.servantsQuarters,
 	{
 		servant: new App.Entity.Facilities.ServantsQuartersServantJob()
diff --git a/src/facilities/spa/spaFramework.js b/src/facilities/spa/spaFramework.js
index 45f7049be1653aed2430ff16901b10b2a3152037..c9210b976ca51cb6e93fc485040d7f61fa223d8f 100644
--- a/src/facilities/spa/spaFramework.js
+++ b/src/facilities/spa/spaFramework.js
@@ -43,7 +43,7 @@ App.Entity.Facilities.SpaAssigneeJob = class extends App.Entity.Facilities.Facil
 	}
 };
 
-App.Entity.facilities.spa = new App.Entity.Facilities.Facility(
+App.Entity.facilities.spa = new App.Entity.Facilities.SingleJobFacility(
 	App.Data.Facilities.spa,
 	{
 		assignee: new App.Entity.Facilities.SpaAssigneeJob()
diff --git a/src/js/assignJS.js b/src/js/assignJS.js
index 5062946543e1038306b3abb3a9de40552a59ecee..90124832f8816dc0ae48e623f9b9535240829155 100644
--- a/src/js/assignJS.js
+++ b/src/js/assignJS.js
@@ -617,8 +617,6 @@ App.UI.jobLinks = function() {
 
 App.UI.SlaveInteract = {
 	fucktoyPref: function() {
-		let elem = jQuery('#fucktoypref');
-		elem.empty();
 		let res = "";
 		/** @type {App.Entity.SlaveState} */
 		const slave = State.variables.activeSlave;
@@ -646,9 +644,7 @@ App.UI.SlaveInteract = {
 			links.push(`<<link "No Preference">><<set $activeSlave.toyHole = "all ${slave.possessive} holes">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>`);
 			res += links.join('&thinsp;|&thinsp;') + '<br>';
 		}
-		let ins = jQuery(document.createDocumentFragment());
-		ins.wiki(res);
-		elem.append(ins);
+		App.UI.replace('#fucktoypref', res);
 	},
 
 	assignmentBlock: function(blockId) {
diff --git a/src/js/slaveListing.js b/src/js/slaveListing.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b97e20f5f8f393af42e132535223c155b4b1f90
--- /dev/null
+++ b/src/js/slaveListing.js
@@ -0,0 +1,916 @@
+/**
+ * @file Functions for rendering lists of slave summaries for various purposes. This includes
+ * lists for the penthouse/facilities, selecting a slaves, facility leaders.
+ *
+ * For documentation see devNotes/slaveListing.md
+ */
+
+App.UI.SlaveList = {};
+
+/**
+ * @callback slaveTextGenerator
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.render = function() {
+	'use strict';
+	let V;
+	/** @type {string} */
+	let passageName;
+	/** @type {App.Entity.SlaveState[]} */
+	let slaves;
+	/** @type {boolean} */
+	let slaveImagePrinted;
+
+	return renderList;
+
+	/**
+	 * @param {number[]} indices
+	 * @param {Array.<{index: number, rejects: string[]}>} rejectedSlaves
+	 * @param {slaveTextGenerator} interactionLink
+	 * @param {slaveTextGenerator} [postNote]
+	 * @returns {string}
+	 */
+	function renderList(indices, rejectedSlaves, interactionLink, postNote) {
+		V = State.variables;
+		passageName = passage();
+		slaves = V.slaves;
+		V.assignTo = passageName; // would be passed to the "Assign" passage
+		slaveImagePrinted = (V.seeImages === 1) && (V.seeSummaryImages === 1);
+
+		let res = [];
+		if (V.useSlaveListInPageJSNavigation === 1) {
+			res.push(createQuickList(indices));
+		}
+
+		const fcs = App.Entity.facilities;
+
+		// can't simply loop over fcs attributes, as there is the penthouse among them, which always exists
+		const anyFacilityExists = fcs.brothel.established || fcs.club.established || fcs.dairy.established || fcs.farmyard.established || fcs.servantsQuarters.established || fcs.masterSuite.established || fcs.spa.established || fcs.clinic + fcs.schoolroom.established || fcs.cellblock.established || fcs.arcade.established || fcs.headGirlSuite.established;
+
+		let showTransfers = false;
+		if (anyFacilityExists) {
+			if (passageName === "Main" || passageName === "Head Girl Suite" || passageName === "Spa" || passageName === "Brothel" || passageName === "Club" || passageName === "Arcade" || passageName === "Clinic" || passageName === "Schoolroom" || passageName === "Dairy" || passageName === "Farmyard" || passageName === "Servants' Quarters" || passageName === "Master Suite" || passageName === "Cellblock") {
+				V.returnTo = passageName;
+				showTransfers = true;
+			}
+		}
+
+		for (const _si of indices) {
+			let ss = renderSlave(_si, interactionLink, showTransfers, postNote);
+			res.push(`<div id="slave_${slaves[_si].ID}" style="clear:both">${ss}</div>`);
+		}
+
+		for (const rs of rejectedSlaves) {
+			const slave = slaves[rs.index];
+			const rejects = rs.rejects;
+			const slaveName = SlaveFullName(slave);
+			let rejectString = rejects.length === 1 ?
+				rejects[0] :
+				`${slaveName}: <ul>${rejects.map(e => `<li>${e}</li>`).join('')}</ul>`;
+			res.push(`<div id="slave_${slave.ID}" style="clear:both">${rejectString}</div>`);
+		}
+
+		$(document).one(':passagedisplay', function() {
+			$("[data-quick-index]").click(function() {
+				let which = this.attributes["data-quick-index"].value;
+				let quick = $("div#list_index" + which);
+				quick.toggleClass("hidden");
+			});
+			quickListBuildLinks();
+		});
+
+		return res.join("");
+	}
+
+
+	/**
+	 * @param {number} index
+	 * @param {slaveTextGenerator} interactionLink
+	 * @param {boolean} showTransfers
+	 * @param {slaveTextGenerator} [postNote]
+	 * @returns {string}
+	 */
+	function renderSlave(index, interactionLink, showTransfers, postNote) {
+		let res = [];
+		const slave = slaves[index];
+
+		res.push(dividerAndImage(slave));
+		res.push(interactionLink(slave, index));
+
+		if ((slave.choosesOwnClothes === 1) && (slave.clothes === "choosing her own clothes")) {
+			const _oldDevotion = slave.devotion;
+			saChoosesOwnClothes(slave);
+			slave.devotion = _oldDevotion; /* restore devotion value so repeatedly changing clothes isn't an exploit */
+		}
+
+		SlaveStatClamp(slave);
+		slave.trust = Math.trunc(slave.trust);
+		slave.devotion = Math.trunc(slave.devotion);
+		slave.health = Math.trunc(slave.health);
+		res.push(' will ');
+		if ((slave.assignment === "rest") && (slave.health >= -20)) {
+			res.push(`<strong><u><span class="lawngreen">rest</span></u></strong>`);
+		} else if ((slave.assignment === "stay confined") && ((slave.devotion > 20) || ((slave.trust < -20) && (slave.devotion >= -20)) || ((slave.trust < -50) && (slave.devotion >= -50)))) {
+			res.push(`<strong><u><span class="lawngreen">stay confined.</span></u></strong>`);
+			if (slave.sentence > 0) {
+				res.push(` (${slave.sentence} weeks)`);
+			}
+		} else if (slave.choosesOwnAssignment === 1) {
+			res.push('choose her own job');
+		} else {
+			res.push(slave.assignment);
+			if (slave.sentence > 0) {
+				res.push(` ${slave.sentence} weeks`);
+			}
+		}
+		res.push('. ');
+
+		if ((V.displayAssignments === 1) && (passageName === "Main") && (slave.ID !== V.HeadGirl.ID) && (slave.ID !== V.Recruiter.ID) && (slave.ID !== V.Bodyguard.ID)) {
+			res.push(App.UI.jobLinks.assignments(index, "Main"));
+		}
+		if (showTransfers) {
+			res.push('<br>Transfer to: ' + App.UI.jobLinks.transfers(index));
+		}
+		res.push('<br/>');
+
+		if (slaveImagePrinted) {
+			res.push('&nbsp;&nbsp;&nbsp;&nbsp;');
+		}
+
+		clearSummaryCache();
+		res.push(SlaveSummary(slave));
+
+		if (postNote !== undefined) {
+			res.push('<br>');
+			res.push(postNote(slave, index));
+		}
+
+		return res.join('');
+	}
+
+	/**
+	 * @param {number[]} indices
+	 * @return {string}
+	*/
+	function createQuickList(indices) {
+		let res = "";
+		let _tableCount = 0;
+
+		/* Useful for finding weird combinations — usages of this passage that don't yet generate the quick index.
+		*	<<print 'pass/count/indexed/flag::[' + passageName + '/' + _Count + '/' + _indexed + '/' + $SlaveSummaryFiler + ']'>>
+		*/
+
+		if (((indices.length > 1) && ((passageName === "Main") && ((V.useSlaveSummaryTabs === 0) || (V.slaveAssignmentTab === "all"))))) {
+			const _buttons = [];
+			let _offset = -50;
+			if (/Select/i.test(passageName)) {
+				_offset = -25;
+			}
+			res += "<br />";
+			_tableCount++;
+			/*
+			 * we want <button data-quick-index="<<= _tableCount>>">...
+			 */
+			const _buttonAttributes = {
+				'data-quick-index': _tableCount
+			};
+			res += App.UI.htag("Quick Index", _buttonAttributes, 'button');
+			/*
+			 * we want <div id="list_index3" class=" hidden">...
+			 */
+			let listIndexContent = "";
+
+			for (const _ssii of indices) {
+				const _IndexSlave = slaves[_ssii];
+				const _indexSlaveName = SlaveFullName(_IndexSlave);
+				const _devotionClass = getSlaveDevotionClass(_IndexSlave);
+				const _trustClass = getSlaveTrustClass(_IndexSlave);
+				_buttons.push({
+					"data-name": _indexSlaveName,
+					"data-scroll-to": `#slave-${_IndexSlave.ID}`,
+					"data-scroll-offset": _offset,
+					"data-devotion": _IndexSlave.devotion,
+					"data-trust": _IndexSlave.trust,
+					"class": `${_devotionClass} ${_trustClass}`
+				});
+			}
+			if (_buttons.length > 0) {
+				V.sortQuickList = V.sortQuickList || 'Devotion';
+				listIndexContent += `//Sorting:// ''<span id="qlSort">$sortQuickList</span>.'' `;
+				listIndexContent += '<<link "Sort by Devotion">>' +
+					'<<set $sortQuickList = "Devotion" >>' +
+					'<<replace "#qlSort">> $sortQuickList <</replace>>' +
+					'<<run' + '$("#qlWrapper").removeClass("trust").addClass("devotion");' + 'sortButtonsByDevotion();' + '>>' +
+					'<</link>> | ' +
+					'<<link "Sort by Trust">>' +
+					'<<set $sortQuickList = "Trust">>' +
+					'<<replace "#qlSort">> $sortQuickList <</replace>>' +
+					'<<run' + '$("#qlWrapper").removeClass("devotion").addClass("trust");' + 'sortButtonsByTrust();' + '>>' +
+					'<</link>>' +
+					'<br/>';
+				listIndexContent += '<div id="qlWrapper" class="quicklist devotion">';
+				for (const _button of _buttons) {
+					const _buttonSlaveName = _button['data-name'];
+					listIndexContent += App.UI.htag(_buttonSlaveName, _button, 'button');
+				}
+				listIndexContent += '</div>';
+			}
+			res += App.UI.htag(listIndexContent, {
+				id: `list_index${_tableCount}`,
+				class: 'hidden'
+			});
+		}
+		return res;
+	}
+
+	function SlaveArt(slave, option) {
+		return `<<SlaveArtById ${slave.ID} ${option}>>`;
+	}
+
+	function slaveImage(s) {
+		return `<div class="imageRef smlImg">${SlaveArt(s, 1)}</div>`;
+	}
+
+	function dividerAndImage(s, showImage) {
+		showImage = showImage || true;
+		const r = [V.lineSeparations === 0 ? "<br>" : "<hr style=\"margin:0\">"];
+		if (showImage && (V.seeImages === 1) && (V.seeSummaryImages === 1)) {
+			r.push(slaveImage(s));
+		}
+		return r.join("");
+	}
+}();
+
+App.UI.SlaveList.Decoration = {};
+/**
+ * returns "HG", "BG", "PA", and "RC" prefixes
+ * @param {App.Entity.SlaveState} slave
+ * @returns {string}
+ */
+App.UI.SlaveList.Decoration.penthousePositions = (slave) => {
+	if (App.Data.Facilities.headGirlSuite.manager.assignment === slave.assignment) {
+		return '<strong><span class="lightcoral">HG</span></strong>';
+	}
+	if (App.Data.Facilities.penthouse.manager.assignment === slave.assignment) {
+		return '<strong><span class="lightcoral">RC</span></strong>';
+	}
+	if (App.Data.Facilities.armory.manager.assignment === slave.assignment) {
+		return '<strong><span class="lightcoral">BG</span></strong>';
+	}
+	if (Array.isArray(State.variables.personalAttention) && State.variables.personalAttention.findIndex(s => s.ID === slave.ID) !== -1) {
+		return '<strong><span class="lightcoral">PA</span></strong>';
+	}
+	return '';
+};
+
+App.UI.SlaveList.SlaveInteract = {};
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.stdInteract = (slave, index) =>
+	App.UI.passageLink(SlaveFullName(slave), 'Slave Interact', `$activeSlave = $slaves[${index}]`);
+
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.penthouseInteract = (slave, index) => {
+	return App.UI.SlaveList.Decoration.penthousePositions(slave) + ' ' + App.UI.SlaveList.SlaveInteract.stdInteract(slave, index);
+};
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.personalAttention = (slave) =>
+	App.UI.passageLink(SlaveFullName(slave), undefined, `App.UI.selectSlaveForPersonalAttention(${slave.ID});`);
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.subordinateTarget = (slave, index) =>
+	App.UI.passageLink(SlaveFullName(slave), "Subordinate Targeting", `$activeSlave.subTarget = $slaves[${index}].ID`);
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.assign = (slave, index) =>
+	App.UI.passageLink(SlaveFullName(slave), "Assign", `$i = ${index}`);
+
+/**
+ * @param {App.Entity.SlaveState} slave
+ * @param {number} index
+ * @return {string}
+ */
+App.UI.SlaveList.SlaveInteract.retrieve = (slave, index) =>
+	App.UI.passageLink(SlaveFullName(slave), "Retrieve", `$i = ${index}`);
+
+/**
+ * Adds/removes a slave with the given id to/from the personal attention array
+ * @param {number} id slave id
+ */
+App.UI.selectSlaveForPersonalAttention = function(id) {
+	const V = State.variables;
+
+	if (!Array.isArray(V.personalAttention)) {
+		/* first PA target */
+		V.personalAttention = [{
+			ID: id,
+			trainingRegimen: "undecided"
+		}];
+	} else {
+		const _pai = V.personalAttention.findIndex(function(s) {
+			return s.ID === id;
+		});
+		if (_pai === -1) {
+			/* not already a PA target; add */
+			V.activeSlave = getSlave(id);
+			V.personalAttention.push({
+				ID: id,
+				trainingRegimen: "undecided"
+			});
+		} else {
+			/* already a PA target; remove */
+			V.personalAttention.deleteAt(_pai);
+			if (V.personalAttention.length === 0) {
+				V.personalAttention = "sex";
+			}
+		}
+	}
+	SugarCube.Engine.play("Personal Attention Select");
+};
+
+/**
+ * Generates fragment with sorting options, that link to the given pasage
+ * @param {string} passage The passage to link to
+ * @returns {string}
+ */
+App.UI.SlaveList.sortingLinks = function (passage) {
+	const V = State.variables;
+	let r = '&nbsp;&nbsp;&nbsp;&nbsp;Sort by: ';
+	r += ["devotion", "name", "assignment", "seniority", "actualAge", "visualAge", "physicalAge"]
+		.map(so => V.sortSlavesBy !== so ?
+			App.UI.passageLink(capFirstChar(so.replace(/([A-Z])/g, " $1")), passage, `$sortSlavesBy = "${so}"`) : capFirstChar(so))
+		.join("&thinsp;|&thinsp;");
+
+	r += '&nbsp;&nbsp;&nbsp;&nbsp;Sort: ';
+	r += ["descending", "ascending"].map(so => V.sortSlavesOrder !== so ?
+		App.UI.passageLink(capFirstChar(so), passage, `$sortSlavesOrder = "${so}"`) : capFirstChar(so))
+		.join("&thinsp;|&thinsp;");
+	return r;
+};
+
+/**
+ * Standard tabs for a facility with a single job (SJ)
+ * @param {App.Entity.Facilities.Facility} facility
+ * @param {string} facilityPassage
+ * @param {boolean} [showTransfersTab=false]
+ * @param {{assign: string, remove: string, transfer: (string| undefined)}} [tabCaptions]
+ * @returns {string}
+ */
+App.UI.SlaveList.listSJFacilitySlaves = function (facility, facilityPassage, showTransfersTab = false, tabCaptions = undefined) {
+	const V = State.variables;
+	tabCaptions = tabCaptions || {
+		assign: 'Assign a slave',
+		remove: 'Remove a slave',
+		transfer: 'Transfer from Facility'
+	};
+	let r = '';
+	if (V.sortSlavesMain) {
+		r += this.sortingLinks(facilityPassage) + '<br>';
+	}
+	r += '<div class="tab">' +
+		App.UI.tabbar.tabButton('assign',  tabCaptions.assign) +
+		App.UI.tabbar.tabButton('remove', tabCaptions.remove) +
+		(showTransfersTab ? App.UI.tabbar.tabButton('transfer', tabCaptions.transfer) : '')+
+	'</div>';
+
+	if (facility.hostedSlaves > 0) {
+		let facilitySlaves = facility.job().employeesIndices();
+		SlaveSort.indices(facilitySlaves);
+		r += App.UI.tabbar.makeTab("remove", App.UI.SlaveList.render(facilitySlaves, [],
+			App.UI.SlaveList.SlaveInteract.stdInteract,
+			(slave, index) => App.UI.passageLink(`Retrieve ${slave.object} from ${facility.name}`, "Retrieve", `$i = ${index}`)));
+	} else {
+		r += App.UI.tabbar.makeTab("remove", `<em>${capFirstChar(facility.name)} is empty for the moment</em>`);
+	}
+
+	/**
+	 * @param {number[]} slaveIdxs
+	 * @returns {string}
+	 */
+	function assignableTabContent(slaveIdxs) {
+		SlaveSort.indices(slaveIdxs);
+		const slaves = V.slaves;
+		let rejectedSlaves = [];
+		let passedSlaves = [];
+		slaveIdxs.forEach((idx) => {
+			const rejects = facility.canHostSlave(slaves[idx]);
+			if (rejects.length > 0) {
+				rejectedSlaves.push({index: idx, rejects: rejects});
+			} else {
+				passedSlaves.push(idx);
+			}
+		}, []);
+		return App.UI.SlaveList.render(passedSlaves, rejectedSlaves,
+			App.UI.SlaveList.SlaveInteract.stdInteract,
+			(slave, index) => App.UI.passageLink(`Send ${slave.object} to ${facility.name}`, "Assign", `$i = ${index}`));
+	}
+	if (facility.hasFreeSpace) {
+		// slaves from the penthouse can be transferred here
+		r += App.UI.tabbar.makeTab("assign", assignableTabContent(App.Entity.facilities.penthouse.employeesIndices()));
+	} else {
+		r += App.UI.tabbar.makeTab("assign", `<strong>${capFirstChar(facility.name)} is full and cannot hold any more slaves</strong>`);
+	}
+
+	if (showTransfersTab) {
+		if (facility.hasFreeSpace) {
+			// slaves from other facilities can be transferred here
+			const transferableIndices = V.slaves.reduce((acc, slave, ind) => {
+				if (slave.assignmentVisible === 0 && !facility.isHosted(slave)) {
+					acc.push(ind);
+				}
+				return acc;
+			}, []);
+			r += App.UI.tabbar.makeTab("transfer", assignableTabContent(transferableIndices));
+		} else {
+			r += App.UI.tabbar.makeTab("transfer", `<strong>${capFirstChar(facility.name)} is full and cannot hold any more slaves</strong>`);
+		}
+	}
+	App.UI.tabbar.handlePreSelectedTab();
+
+	return r;
+};
+
+/**
+ * @returns {string}
+ */
+App.UI.SlaveList.listNGPSlaves = function () {
+	const V = State.variables;
+	const thisPassage = 'New Game Plus';
+	let r = this.sortingLinks(thisPassage) + '<br>';
+
+	r += '<div class="tab">' +
+		App.UI.tabbar.tabButton('assign', 'Import a slave') +
+		App.UI.tabbar.tabButton('remove', 'Remove from impor') +
+	'</div>';
+
+	const NGPassignment = "be imported";
+	/** @type {App.Entity.SlaveState[]} */
+	const slaves = V.slaves;
+
+	if (V.slavesToImport > 0) {
+		const importedSlavesIndices = slaves.reduce((acc, s, i) => { if (s.assignment === NGPassignment) { acc.push(i); } return acc; }, []);
+		SlaveSort.indices(importedSlavesIndices);
+		r += App.UI.tabbar.makeTab("remove", App.UI.SlaveList.render(importedSlavesIndices, [],
+			(s) => `<u><strong><span class="pink">${SlaveFullName(s)}</span></strong></u>`,
+			(s) => App.UI.passageLink('Remove from import list', thisPassage, `$slavesToImport -= 1, removeJob(${s}, "${NGPassignment}")`)));
+	} else {
+		r += App.UI.tabbar.makeTab("remove", `<em>No slaves will go with you to the new game</em>`);
+	}
+
+	if (V.slavesToImport < V.slavesToImportMax) {
+		const slavesToImportIndices = slaves.reduce((acc, s, i) => { if (s.assignment !== NGPassignment) { acc.push(i); } return acc; }, []);
+		SlaveSort.indices(slavesToImportIndices);
+		r += App.UI.tabbar.makeTab("assign", App.UI.SlaveList.render(slavesToImportIndices, [],
+			(s) => `<u><strong><span class="pink">${SlaveFullName(s)}</span></strong></u>`,
+			(s) => App.UI.passageLink('Add to import list', thisPassage, `$slavesToImport += 1, assignJob(${s}, "${NGPassignment}")`)));
+	} else {
+		r += App.UI.tabbar.makeTab("assign", `<strong>Slave import limit reached</strong>`);
+	}
+
+	App.UI.tabbar.handlePreSelectedTab();
+	return r;
+};
+
+/**
+ * Renders facility manager summary or a note with a link to select one
+ * @param {App.Entity.Facilities.Facility} facility
+ * @param {string} [selectionPassage] passage name for manager selection. "${Manager} Select" if omitted
+ * @returns {string}
+ */
+App.UI.SlaveList.displayManager = function (facility, selectionPassage) {
+	const managerCapName = capFirstChar(facility.desc.manager.position);
+	selectionPassage = selectionPassage || `${managerCapName} Select`;
+	const manager = facility.manager.currentEmployee;
+	if (manager) {
+		return this.render([App.Utils.slaveIndexForId(manager.ID)], [],
+			App.UI.SlaveList.SlaveInteract.stdInteract,
+			() => App.UI.passageLink(`Change or remove ${managerCapName}`, selectionPassage, ""));
+	} else {
+		return `You do not have a slave serving as a ${managerCapName}. ${App.UI.passageLink(`Appoint one`, selectionPassage, "")}`;
+	}
+};
+
+/**
+ * Displays standard facility page with manager and list of workers
+ * @param {App.Entity.Facilities.Facility} facility
+ * @param {boolean} [showTransfersPage]
+ * @returns {string}
+ */
+App.UI.SlaveList.stdFacilityPage = function (facility, showTransfersPage) {
+	return this.displayManager(facility) + '<br><br>' + this.listSJFacilitySlaves(facility, passage(), showTransfersPage);
+};
+
+App.UI.SlaveList.penthousePage = function () {
+	const V = State.variables;
+	const ph = App.Entity.facilities.penthouse;
+	const listElementId = 'summarylist'; // for the untabbed mode only
+
+	function span(text, cls, id) {
+		return `<span${cls ? ` class="${cls}"` : ''}${id ? ` id="${id}"` : ''}>${text}</span>`;
+	}
+
+	function overviewTabContent() {
+		let r = '';
+		const thisArcology = V.arcologies[0];
+
+		/** @type {App.Entity.SlaveState} */
+		const HG = V.HeadGirl;
+		if (HG) {
+			r += `<strong><u>${span(SlaveFullName(HG), "pink")}</u></strong> is serving as your Head Girl`;
+			if (thisArcology.FSEgyptianRevivalistLaw === 1) {
+				r += ' and Consort';
+			}
+			r += `. <strong> ${span(App.UI.passageLink("Manage Head Girl", "HG Select"), null, "manageHG")}</strong>  ${span("[H]", "cyan")}`;
+			r += App.UI.SlaveList.render([App.Utils.slaveIndexForId(HG.ID)], [],
+				App.UI.SlaveList.SlaveInteract.penthouseInteract);
+		} else {
+			if (V.slaves.length > 1) {
+				r += `You have ${span("not", "red")} selected a Head Girl`;
+				if (thisArcology.FSEgyptianRevivalistLaw === 1) {
+					r += ' and Consort';
+				}
+				r += `. <strong>${span(App.UI.passageLink("Select One", "HG Select"), null, "manageHG")}</strong> ${span("[H]", "cyan")}`;
+			} else {
+				r += '<em>You do not have enough slaves to keep a Head Girl</em>';
+			}
+		}
+		r += '<br>';
+
+		/** @type {App.Entity.SlaveState} */
+		const RC = V.Recruiter;
+		if (RC) {
+			const p = getPronouns(RC);
+			r += `<strong><u>${span(SlaveFullName(RC), "pink")}</u></strong> is working `;
+			if (V.recruiterTarget !== "other arcologies") {
+				r += 'to recruit girls.';
+			} else {
+				r += 'as a Sexual Ambassador';
+				if (thisArcology.influenceTarget === -1) {
+					r += ', but ' + span(p.object + ' has no target to influence', "red");
+				} else {
+					const targetName = V.arcologies.find(a => a.direction === thisArcology.influenceTarget).name;
+					r += ' to ' + targetName + '.';
+				}
+			}
+			r += `${span('<strong>' + App.UI.passageLink("Manage Recruiter", "Recruiter Select") + '</strong>', null, "manageRecruiter")} ${span("[U]", "cyan")}`;
+			r += App.UI.SlaveList.render([App.Utils.slaveIndexForId(RC.ID)], [],
+				App.UI.SlaveList.SlaveInteract.penthouseInteract);
+		} else {
+			r += `You have ${span("not", "red")} selected a Recruiter. `;
+			r += `${span('<strong>' + App.UI.passageLink("Select one", "Recruiter Select") + '</strong>', null, "manageRecruiter")} ${span("[U]", "cyan")}`;
+		}
+
+		if (V.dojo) {
+			r += '<br>';
+			/** @type {App.Entity.SlaveState} */
+			const BG = V.Bodyguard;
+			if (BG) {
+				r += `<strong><u>${span(SlaveFullName(RC), "pink")}</u></strong> is serving as your bodyguard. `;
+				r += span(`<strong>${App.UI.passageLink("Manage Bodyguard", "BG Select")}</strong>`, null, "manageBG") +
+					span("[B]", "cyan");
+				r += App.UI.SlaveList.render([App.Utils.slaveIndexForId(BG.ID)], [],
+					App.UI.SlaveList.SlaveInteract.penthouseInteract);
+			} else {
+				r += `You have ${span("not", "red")} selected a Bodyguard. `;
+				r += span(`<strong>${App.UI.passageLink("Select one", "BG Select")}</strong>`, null, "manageBG") +
+					span("[B]", "cyan");
+			}
+
+			/* Start Italic event text */
+			if (BG && BG.assignment === "guard you") {
+				const p = getPronouns(BG);
+				V.i = App.Utils.slaveIndexForId(BG.ID);
+				const interactLinkSetters = `$activeSlave = $slaves[${V.i}], $nextButton = "Back", $nextLink = "AS Dump", $returnTo = "Main"`;
+				r += '<br>';
+				// <<= App.Interact.UseGuard($slaves[$i])>>//
+				let useHimLinks = [];
+				useHimLinks.push(App.UI.passageLink(`Use ${p.his} mouth`, "Flips", interactLinkSetters));
+				useHimLinks.push(App.UI.passageLink(`Play with ${p.his} tits`, "FBoobs", interactLinkSetters));
+				if (canDoVaginal(BG)) {
+					useHimLinks.push(App.UI.passageLink(`Fuck ${p.him}`, "FVagina", interactLinkSetters));
+					if (canDoAnal(BG)) {
+						useHimLinks.push(App.UI.passageLink(`Use ${p.his} holes`, "FButt", interactLinkSetters));
+					}
+					if (BG.belly >= 300000) {
+						useHimLinks.push(App.UI.passageLink(`Fuck ${p.him} over ${p.his} belly`, "FBellyFuck", interactLinkSetters));
+					}
+				}
+				/* check */
+				if (canPenetrate(BG)) {
+					useHimLinks.push(App.UI.passageLink(`Ride ${p.him}`, "FDick", interactLinkSetters));
+				}
+				if (canDoAnal(BG)) {
+					useHimLinks.push(App.UI.passageLink(`Fuck ${p.his} ass`, "FAnus", interactLinkSetters));
+				}
+				useHimLinks.push(App.UI.passageLink(`Abuse ${p.him}`, "Gameover", '$gameover ="idiot ball"'));
+
+				r += `<br>&nbsp;&nbsp;&nbsp;&nbsp;${useHimLinks.join('&thinsp;|&thinsp;')}`;
+				/* End Italic event text */
+			}
+			r += "<br/>";
+		}
+		return r;
+	}
+
+	/**
+	 * @param {string} job
+	 * @returns {{n: number, text: string}}
+	 */
+	function _slavesForJob(job) {
+		const employeesIndices = job === 'all' ? ph.employeesIndices() : ph.job(job).employeesIndices();
+		if (employeesIndices.length === 0) { return {n: 0, text: ''}; }
+
+		SlaveSort.indices(employeesIndices);
+		return {
+			n: employeesIndices.length,
+			text: App.UI.SlaveList.render(employeesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract)
+		};
+	}
+
+	/**
+	 * Displays job filter links, whose action are generated by the callback
+	 * @param {assignmentFilterGenerateCallback} callback
+	 * @returns {string}
+	 */
+	function _jobFilter(callback) {
+		const jd = App.Data.Facilities.penthouse.jobs;
+		let links = [];
+		links.push(`<<link "All">>${callback('all')}<</link>>`);
+		// seems like SC2 does not process data-setter when data-passage is not set
+		for (const jn in jd) {
+			links.push(`<<link "${capFirstChar(jd[jn].position)}">>${callback(jn)}<</link>>`);
+		}
+
+		return links.join('&thinsp;|&thinsp;');
+	}
+
+	function _updateList(job) {
+		State.temporary.mainPageUpdate.job = job;
+		App.UI.replace('#' + listElementId, _slavesForJob(job).text);
+	}
+
+	/**
+	 * @typedef tabDesc
+	 * @property {string} tabName
+	 * @property {string} caption
+	 * @property {string} content
+	 */
+
+	/**
+	 * @param {string} tabName
+	 * @param {string} caption
+	 * @param {string} content
+	 * @returns {tabDesc}
+	 */
+	function makeTabDesc(tabName, caption, content) {
+		return {
+			tabName: tabName,
+			caption: caption,
+			content: content
+		};
+	}
+
+	let r = '';
+
+	if (V.positionMainLinks >= 0) {
+		r += '<center>' + App.UI.View.MainLinks() + '</center><br>';
+	}
+
+	if (V.sortSlavesMain) {
+		r += '<br>' + this.sortingLinks("Main") + '<br>';
+	}
+
+	if (V.useSlaveSummaryTabs) {
+		/** @type {tabDesc[]} */
+		let tabs = [];
+
+		if (V.useSlaveSummaryOverviewTab) {
+			tabs.push(makeTabDesc('overview', 'Overview', overviewTabContent()));
+		}
+
+		for (const jn of ph.jobsNames) {
+			const slaves = _slavesForJob(jn);
+			if (slaves.n > 0) {
+				tabs.push(makeTabDesc(jn, `${ph.desc.jobs[jn].position} (${slaves.n})`, slaves.text));
+			}
+		}
+
+		// now generate the "All" tab
+		const penthouseSlavesIndices = ph.employeesIndices();
+		SlaveSort.indices(penthouseSlavesIndices);
+		tabs.push(makeTabDesc('all', `All (${penthouseSlavesIndices.length})`,
+			this.render(penthouseSlavesIndices, [], App.UI.SlaveList.SlaveInteract.penthouseInteract)));
+
+
+		r += '<div class="tab">';
+		for (const tab of tabs) {
+			r += App.UI.tabbar.tabButton(tab.tabName, tab.caption);
+		}
+		r += '</div>';
+
+		for (const tab of tabs) {
+			r += App.UI.tabbar.makeTab(tab.tabName, tab.content);
+		}
+	} else {
+		State.temporary.mainPageUpdate = {
+			job: State.temporary.mainPageUpdate ? State.temporary.mainPageUpdate.job : 'all',
+			update: _updateList
+		};
+
+		$(document).one(':passagedisplay', () => { _updateList(State.temporary.mainPageUpdate.job); });
+		r += `<div>${_jobFilter(s => `<<run _mainPageUpdate.update("${s}")>>`)} <div id=${listElementId}></div></div>`;
+	}
+
+	if (V.positionMainLinks <= 0) {
+		r += '<br><center>' + App.UI.View.MainLinks() + '</center>';
+	}
+
+	App.UI.tabbar.handlePreSelectedTab();
+	return r;
+};
+
+/**
+ * @callback assignmentFilterGenerateCallback
+ * @param {string} value
+ * @returns {string}
+ */
+
+/**
+ * @callback slaveFilterCallbackReasoned
+ * @param {App.Entity.SlaveState} slave
+ * @returns {string[]}
+ */
+
+ /**
+ * @callback slaveFilterCallbackSimple
+ * @param {App.Entity.SlaveState} slave
+ * @returns {boolean}
+ */
+
+ /**
+ * @callback slaveTestCallback
+ * @param {App.Entity.SlaveState} slave
+ * @returns {boolean}
+ */
+
+App.UI.SlaveList.slaveSelectionList = function () {
+	const selectionElementId = "slaveSelectionList";
+
+	return selection;
+
+	/**
+	 * @typedef ListOptions
+	 * @property {slaveFilterCallbackReasoned|slaveFilterCallbackSimple} filter
+	 * @property {slaveTestCallback} [expCheck]
+	 * @property {slaveTextGenerator} interactionLink
+	 * @property {slaveTextGenerator} [postNote]
+	 */
+
+	/**
+	 * @param {slaveFilterCallbackReasoned|slaveFilterCallbackSimple} filter
+	 * @param {slaveTextGenerator} interactionLink
+	 * @param {slaveTestCallback} [experianceChecker]
+	 * @param {slaveTextGenerator} [postNote]
+	 * @returns {string}
+	*/
+	function selection(filter, interactionLink, experianceChecker, postNote) {
+		if (experianceChecker === null) { experianceChecker = undefined; }
+		State.temporary.slaveSelection = {
+			filter: filter,
+			expCheck: experianceChecker,
+			interactionLink: interactionLink,
+			postNote: postNote,
+			update: _updateList
+		};
+
+		$(document).one(':passagedisplay', () => { _updateList('all'); });
+		return `<div>${_assignmentFilter(s => `<<run _slaveSelection.update('${s}')>>`, experianceChecker !== undefined)} <div id=${selectionElementId}></div></div>`;
+	}
+
+	function _updateList(assignment) {
+		App.UI.replace('#' + selectionElementId, _listSlaves(assignment, State.temporary.slaveSelection));
+	}
+	/**
+	 * Displays assignment filter links, whose action are generated by the callback
+	 * @param {assignmentFilterGenerateCallback} callback
+	 * @param {boolean} includeExperianced
+	 * @returns {string}
+	 */
+	function _assignmentFilter(callback, includeExperianced) {
+		let filters = {
+			all: "All"
+		};
+		let fNames = Object.keys(App.Entity.facilities);
+		fNames.sort();
+		for (const fn of fNames) {
+			/** @type {App.Entity.Facilities.Facility} */
+			const f = App.Entity.facilities[fn];
+			if (f.established && f.hostedSlaves > 0) {
+				filters[fn] = f.name;
+			}
+		}
+		let links = [];
+		/* seems like SC2 does not process data-setter when data-passage is not set
+		for (const f in filters) {
+			links.push(App.UI.passageLink(filters[f], passage, callback(f)));
+		}
+		if (includeExperianced) {
+			links.push(`<span class="lime">${App.UI.passageLink('Experianced', passage, callback('experianced'))}</span>`);
+		}*/
+		for (const f in filters) {
+			links.push(`<<link "${filters[f]}">>${callback(f)}<</link>>`);
+		}
+		if (includeExperianced) {
+			links.push(`<span class="lime"><<link "Experianced">>${callback('experianced')}<</link>></span>`);
+		}
+
+		return links.join('&thinsp;|&thinsp;');
+	}
+
+	/**
+	 *
+	 * @param {string} assignmentStr
+	 * @param {ListOptions} options
+	 * @returns {string}
+	 */
+	function _listSlaves(assignmentStr, options) {
+		/** @type {App.Entity.SlaveState[]} */
+		const slaves = State.variables.slaves;
+		let unfilteredIndices = [];
+		switch (assignmentStr) {
+			case 'all':
+				unfilteredIndices = Array.from({length: slaves.length}, (v, i) => i);
+				break;
+			case 'experianced':
+				unfilteredIndices = slaves.reduce((acc, s, idx) => {
+					if (options.expCheck(s)) {
+						acc.push(idx);
+					}
+					return acc;
+				}, []);
+				break;
+			default:
+				unfilteredIndices = App.Entity.facilities[assignmentStr].employeesIndices();
+				break;
+		}
+		SlaveSort.indices(unfilteredIndices);
+		let passingIndices = [];
+		let rejects = [];
+
+		unfilteredIndices.forEach(idx => {
+			const fr = options.filter(slaves[idx]);
+			if (fr === true || (Array.isArray(fr) && fr.length === 0)) {
+				passingIndices.push(idx);
+			} else {
+				if (Array.isArray(fr)) { rejects.push({index: idx, rejects: fr}); }
+			}
+		});
+
+		// clamsi fragment to create a function which combines results of two optional tests
+		// done this way to test for tests presense only once
+		const listPostNote = options.expCheck ?
+			(options.postNote ?
+				(s, i) => options.expCheck(s) ? '<span class="lime">Has applicable career experience.</span><br>' : '' + options.postNote(s, i) :
+				(s) => options.expCheck(s) ? '<span class="lime">Has applicable career experience.</span>' : '') :
+			options.postNote ?
+				(s, i) => options.postNote(s, i) :
+				() => '';
+
+		return App.UI.SlaveList.render(passingIndices, rejects, options.interactionLink, listPostNote);
+	}
+}();
+
+/**
+ * @param {App.Entity.Facilities.Facility} facility
+ * @param {string} [passage] one of the *Workaround passages. Will be composed from the position name if omitted
+ * @returns {string}
+ */
+App.UI.SlaveList.facilityManagerSelection = function (facility, passage) {
+	passage = passage || capFirstChar(facility.manager.desc.position) + " Workaround";
+	return this.slaveSelectionList(slave => facility.manager.canEmploy(slave),
+		(slave, index) => App.UI.passageLink(SlaveFullName(slave), passage, `$i = ${index}`),
+		slave => facility.manager.slaveHasExperience(slave));
+};
diff --git a/src/js/slaveSummaryWidgets.js b/src/js/slaveSummaryWidgets.js
index 80b68ee363befa96a1b860a7d0eafdc9f1782237..36078ce9ff62c2f5788b9c2f514e9ff48d054511 100644
--- a/src/js/slaveSummaryWidgets.js
+++ b/src/js/slaveSummaryWidgets.js
@@ -4979,7 +4979,7 @@ window.SlaveSummaryUncached = (function() {
 		if (slave.useRulesAssistant === 0) {
 			r += `<span class="lightgreen">RA-Exempt</span> `;
 		} else if (V.abbreviateRulesets === 2 && (slave.currentRules !== undefined) && (slave.currentRules.length > 0)) {
-			r += `Rules: ${V.defaultRules.filter(x => ruleApplied(slave, x)).map(x => x.name).join(", ") }`;
+			r += `Rules: ${V.defaultRules.filter(x => ruleApplied(slave, x)).map(x => x.name).join(", ")}`;
 		}
 	}
 
@@ -4996,603 +4996,3 @@ window.SlaveSummaryUncached = (function() {
 
 	return SlaveSummaryUncached;
 })();
-
-App.UI.PassageSlaveFilers = {
-	"Main": s => (s.assignmentVisible === 1),
-	"Personal Attention Select": s => (s.assignmentVisible === 1 && s.fuckdoll <= 0),
-	"Agent Select": s => ((s.fuckdoll === 0 && s.devotion > 20 && s.intelligence + s.intelligenceImplant > 15 && s.intelligenceImplant >= 15 && canWalk(s) && canSee(s) && canHear(s) && canTalk(s) && s.broodmother < 2 && (s.breedingMark !== 1 || State.variables.propOutcome === 0)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.arcologyAgent.manager.slaveHasExperience(s)))),
-	"BG Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.assignment !== "guard you" && canWalk(s) && canSee(s) && canHear(s) && (s.breedingMark !== 1 || State.variables.propOutcome === 0)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.armory.manager.slaveHasExperience(s)))),
-	"Recruiter Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.assignment !== "recruit girls" && canWalk(s) && canSee(s) && canTalk(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.penthouse.manager.slaveHasExperience(s)))),
-	"HG Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.assignment !== "be your Head Girl" && canWalk(s) && canHear(s) && canSee(s) && canTalk(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.headGirlSuite.manager.slaveHasExperience(s)))),
-	"Head Girl Suite": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "be your Head Girl" && s.indentureRestrictions <= 0 && (s.breedingMark !== 1 || State.variables.propOutcome === 0) && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler !== "assignable" && s.assignment === "live with your Head Girl")),
-	"Subordinate Targeting": s => (s.devotion >= -20 && s.fuckdoll === 0 && State.variables.activeSlave.ID !== s.ID && (State.variables.activeSlave.amp !== 1 || s.amp !== 1)),
-	"Spa": s => (
-		(s.fuckdoll <= 0 && s.assignment !== "rest in the spa" && (
-			(s.assignmentVisible === 1 && State.variables.SlaveSummaryFiler === "assignable") ||
-			(s.assignmentVisible === 0 && State.variables.SlaveSummaryFiler === "transferable"))
-		) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "rest in the spa") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Attendant.ID)),
-	"Attendant Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canWalk(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.spa.manager.slaveHasExperience(s)))),
-	"Nursery": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "work as a nanny" && s.assignmentVisible === 1 && s.fuckdoll <= 0 && (s.devotion > 20 || s.trust > 20)) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "work as a nanny") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Matron.ID)),
-	"Matron Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canWalk(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.nursery.manager.slaveHasExperience(s)))),
-	"Brothel": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "work in the brothel" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "work in the brothel") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Madam.ID)),
-	"Madam Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.intelligence + s.intelligenceImplant >= -50 && canWalk(s) && canSee(s) && canHear(s) && (s.breedingMark !== 1 || State.variables.propOutcome === 0)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.brothel.manager.slaveHasExperience(s)))),
-	"Club": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "serve in the club" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "serve in the club") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.DJ.ID)),
-	"DJ Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.intelligence + s.intelligenceImplant >= -50 && canTalk(s) && canHear(s) && canWalk(s) && (s.breedingMark !== 1 || State.variables.propOutcome === 0)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.club.manager.slaveHasExperience(s)))),
-	"Clinic": s => (
-		(s.fuckdoll <= 0 && s.assignment !== "get treatment in the clinic" && (
-			(s.assignmentVisible === 1 && State.variables.SlaveSummaryFiler === "assignable") ||
-			(s.assignmentVisible === 0 && State.variables.SlaveSummaryFiler === "transferable"))
-		) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "get treatment in the clinic") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Nurse.ID)),
-	"Nurse Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canWalk(s) && canSee(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.clinic.manager.slaveHasExperience(s)))),
-	"Schoolroom": s => (
-		((s.fuckdoll <= 0 && s.fetish !== "mindbroken" && s.assignment !== "learn in the schoolroom") &&
-			(s.assignmentVisible === 1 && State.variables.SlaveSummaryFiler === "assignable") ||
-			(s.assignmentVisible === 0 && State.variables.SlaveSummaryFiler === "transferable")
-		) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "learn in the schoolroom") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Schoolteacher.ID)),
-	"Schoolteacher Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canTalk(s) && canHear(s) && canSee(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.schoolroom.manager.slaveHasExperience(s)))),
-	"Dairy": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "work in the dairy" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "work in the dairy") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Milkmaid.ID)),
-	"Milkmaid Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 20 && canWalk(s) && canSee(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.dairy.manager.slaveHasExperience(s)))),
-	"Farmyard": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "work as a farmhand" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "work as a farmhand") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Farmer.ID)),
-	"Farmer Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canWalk(s) && canSee(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.farm.manager.slaveHasExperience(s)))),
-	"Servants' Quarters": s =>  (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "work as a servant" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "work as a servant") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Stewardess.ID)),
-	"Stewardess Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.intelligence + s.intelligenceImplant >= -50 && canWalk(s) && canSee(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.servantsQuarters.manager.slaveHasExperience(s)))),
-	"Master Suite": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "serve in the master suite" && s.assignmentVisible === 1 && s.fuckdoll <= 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "serve in the master suite") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Concubine.ID)),
-	"Concubine Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && s.amp !== 1) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.masterSuite.manager.slaveHasExperience(s)))),
-	"Cellblock": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "be confined in the cellblock" && s.assignmentVisible === 1 && s.fuckdoll <= 0 && s.fetish !== "mindbroken") ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "be confined in the cellblock") ||
-		(State.variables.SlaveSummaryFiler === "leading" && s.ID === State.variables.Wardeness.ID)),
-	"Wardeness Select": s => ((s.assignmentVisible === 1 && s.fuckdoll === 0 && s.devotion > 50 && canWalk(s) && canSee(s) && canHear(s)) &&
-		((State.variables.SlaveSummaryFiler !== "experienced") ||
-		(State.variables.SlaveSummaryFiler === "experienced" && App.Entity.facilities.cellblock.manager.slaveHasExperience(s)))),
-	"Arcade": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "be confined in the arcade" && s.assignmentVisible === 1 && (State.variables.arcade >= State.variables.arcadeSlaves || State.variables.arcadeUpgradeFuckdolls === 1)) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "be confined in the arcade")),
-	"Pit": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && !State.variables.fighterIDs.includes(s.ID) && canWalk(s) && (s.assignment !== "guard you") && (s.assignment !== "work in the dairy" || State.variables.dairyRestraintsSetting < 2) && (s.assignmentVisible === 1 && s.fuckdoll === 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && State.variables.fighterIDs.includes(s.ID)))),
-	"Coursing Association": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && canWalk(s) && State.variables.Lurcher.ID !== s.ID && (s.assignmentVisible === 1 && s.fuckdoll === 0) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && State.variables.Lurcher.ID === s.ID))),
-	"New Game Plus": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && s.assignment !== "be imported") ||
-		(State.variables.SlaveSummaryFiler === "occupying" && s.assignment === "be imported")),
-	"Rules Slave Select": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && !ruleSlaveSelected(s, State.variables.currentRule)) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && ruleSlaveSelected(s, State.variables.currentRule))),
-	"Rules Slave Exclude": s => (
-		(State.variables.SlaveSummaryFiler === "assignable" && !ruleSlaveExcluded(s, State.variables.currentRule)) ||
-		(State.variables.SlaveSummaryFiler === "occupying" && ruleSlaveExcluded(s, State.variables.currentRule))),
-	"Matchmaking": s => (s.devotion >= 100 && s.relationship === State.variables.activeSlave.relationship && s.ID !== State.variables.activeSlave.ID),
-	"Dinner Party Preparations": s => (s.assignmentVisible === 1 && s.fuckdoll === 0),
-};
-
-/**
- * Slave filtering predicate
- *
- * @callback slaveFilter
- * @param {App.Entity.SlaveState} slave
- * @returns {boolean}
- */
-/**
- * @param {string} passageName
- * @returns {string}
- */
-App.UI.slaveSummaryList = function(passageName) {
-	'use strict';
-	const V = State.variables;
-
-	const _indexed = 0;
-	/**
-	 * @type {App.Entity.SlaveState[]}
-	 */
-	const slaves = V.slaves;
-
-	V.assignTo = passageName; // would be passed to the "Assign" passage
-
-	/**
-	 * @param {App.Entity.SlaveState} s
-	 * @returns {boolean}
-	 */
-	function _passagePreFilter(s) {
-		return s.assignment !== "be your agent" && s.assignment !== "live with your agent" &&
-			(!App.UI.PassageSlaveFilers.hasOwnProperty(passageName) || App.UI.PassageSlaveFilers[passageName](s));
-	}
-
-	/**
-	 * A simple macro which allows to create wrapping html elements with dynamic IDs.
-	 *
-	 * idea blatantly robbed from the spanMacroJS.tw but expanded to a more generic case, allowing <div>,
-	 * <button> or whatever you want elements, default is for the div though.
-	 * In addition, you can pass an object in as the first argument instead of an id, and each of the
-	 * object's attributes will become attributes of the generate tag.
-	 *
-	 * Usage: << htag id >> ... << /htag>>
-	 * Usage: << htag id tag >> ... << /htag>>
-	 * Usage: << htag attributes >> ... << /htag>>
-	 * Usage: << htag attributes tag >> ... << /htag>>
-	 * @param {string} text
-	 * @param {object} attributes
-	 * @param {string} tag
-	 * @returns {string}
-	 */
-	function htag(text, attributes, tag) {
-		const payload = text.replace(/(^\n+|\n+$)/, "");
-		const htag = tag || "div";
-
-		if ("object" === typeof attributes) {
-			attributes = $.map(attributes, (val, key) => `${key }="${ val }"`).join(" ");
-		} else {
-			attributes = `id="${ String(this.args[0]).trim() }"`;
-		}
-
-		return `<${ htag } ${ attributes }>${ payload }</${ htag }>`;
-	}
-
-	function SlaveArt(slave, option) {
-		return `<<SlaveArtById ${ slave.ID } ${ option }>>`;
-	}
-
-	function slaveImage(s) {
-		return `<div class="imageRef smlImg">${ SlaveArt(s, 1) }</div>`;
-	}
-
-	function dividerAndImage(s, showImage) {
-		showImage = showImage || true;
-		const r = [V.lineSeparations === 0 ? "<br>" : "<hr style=\"margin:0\">"];
-		if (showImage && (V.seeImages === 1) && (V.seeSummaryImages === 1)) {
-			r.push(slaveImage(s));
-		}
-		return r.join("");
-	}
-
-	const _filteredSlaveIdxs = slaves.map(function(slave, idx) {
-		return _passagePreFilter(slave) ? idx : null;
-	}).filter(function(idx) {
-		return idx !== null;
-	});
-
-	const _indexSlavesIdxs = slaves.map(function(slave, idx) {
-		return _passagePreFilter(slave) ? idx : null;
-	}).filter(function(idx) {
-		return idx !== null;
-	});
-
-	const res = [];
-	const tabName = V.slaveAssignmentTab;
-
-	let _tableCount = 0;
-	if (V.useSlaveListInPageJSNavigation === 1) {
-		const _Count = _indexSlavesIdxs.length;
-		/* Useful for finding weird combinations — usages of this passage that don't yet generate the quick index.
-		 *	<<print 'pass/count/indexed/flag::[' + passageName + '/' + _Count + '/' + _indexed + '/' + $SlaveSummaryFiler + ']'>>
-		 */
-
-		if (((_Count > 1) && (_indexed === 0) && (((passageName === "Main") && (V.SlaveSummaryFiler === undefined) && ((V.useSlaveSummaryTabs === 0) || (V.slaveAssignmentTab === "all"))) || (V.SlaveSummaryFiler === "occupying")))) {
-			const _buttons = [];
-			let _offset = -50;
-			if (/Select/i.test(passageName)) {
-				_offset = -25;
-			}
-			res.push("<br />");
-			_tableCount++;
-			/*
-			 * we want <button data-quick-index="<<= _tableCount>>">...
-			 */
-			const _buttonAttributes = {
-				'data-quick-index': _tableCount
-			};
-			res.push(htag("Quick Index", _buttonAttributes, 'button'));
-			/*
-			 * we want <div id="list_index3" class=" hidden">...
-			 */
-			let listIndexContent = "";
-
-			for (const _ssii of _indexSlavesIdxs) {
-				const _IndexSlave = slaves[_ssii];
-				const _indexSlaveName = SlaveFullName(_IndexSlave);
-				const _devotionClass = getSlaveDevotionClass(_IndexSlave);
-				const _trustClass = getSlaveTrustClass(_IndexSlave);
-				_buttons.push({
-					"data-name": _indexSlaveName,
-					"data-scroll-to": `#slave-${ _IndexSlave.ID}`,
-					"data-scroll-offset": _offset,
-					"data-devotion": _IndexSlave.devotion,
-					"data-trust": _IndexSlave.trust,
-					"class": `${_devotionClass } ${ _trustClass}`
-				});
-			}
-			if (_buttons.length > 0) {
-				V.sortQuickList = V.sortQuickList || 'Devotion';
-				listIndexContent += `//Sorting:// ''<span id="qlSort">$sortQuickList</span>.'' `;
-				listIndexContent += '<<link "Sort by Devotion">>' +
-					'<<set $sortQuickList = "Devotion" >>' +
-					'<<replace "#qlSort">> $sortQuickList <</replace>>' +
-					'<<run' + '$("#qlWrapper").removeClass("trust").addClass("devotion");' + 'sortButtonsByDevotion();' + '>>' +
-					'<</link>> | ' +
-					'<<link "Sort by Trust">>' +
-					'<<set $sortQuickList = "Trust">>' +
-					'<<replace "#qlSort">> $sortQuickList <</replace>>' +
-					'<<run' + '$("#qlWrapper").removeClass("devotion").addClass("trust");' + 'sortButtonsByTrust();' + '>>' +
-					'<</link>>' +
-					'<br/>';
-				listIndexContent += '<div id="qlWrapper" class="quicklist devotion">';
-				for (const _button of _buttons) {
-					const _buttonSlaveName = _button['data-name'];
-					listIndexContent += htag(_buttonSlaveName, _button, 'button');
-				}
-				listIndexContent += '</div>';
-			}
-			res.push(htag(listIndexContent, {
-				id: `list_index${ _tableCount}`,
-				class: 'hidden'
-			}));
-		}
-	}
-
-	const passageToFacilityMap = {
-		"Arcade": App.Entity.facilities.arcade,
-		"Brothel": App.Entity.facilities.brothel,
-		"Cellblock": App.Entity.facilities.cellblock,
-		"Clinic": App.Entity.facilities.clinic,
-		"Club": App.Entity.facilities.club,
-		"Dairy": App.Entity.facilities.dairy,
-		"Farmyard": App.Entity.facilities.farmyard,
-		"Head Girl Suite": App.Entity.facilities.headGirlSuite,
-		"Master Suite": App.Entity.facilities.masterSuite,
-		"Nursery": App.Entity.facilities.nursery,
-		"Pit": App.Entity.facilities.pit,
-		"Schoolroom": App.Entity.facilities.schoolroom,
-		"Servants' Quarters": App.Entity.facilities.servantsQuarters,
-		"Spa": App.Entity.facilities.spa
-	};
-
-	function makeSelectionPassageInfo(f, wp) {
-		return {
-			facility: f,
-			passage: wp
-		};
-	}
-
-	const selectionPassageToFacilityMap = {
-		"HG Select": makeSelectionPassageInfo(App.Entity.facilities.headGirlSuite, "HG Workaround"),
-		"BG Select": makeSelectionPassageInfo(App.Entity.facilities.armory, "Bodyguard Workaround"),
-		"Attendant Select": makeSelectionPassageInfo(App.Entity.facilities.spa, "Attendant Workaround"),
-		"Concubine Select": makeSelectionPassageInfo(App.Entity.facilities.masterSuite, "Concubine Workaround"),
-		"Matron Select": makeSelectionPassageInfo(App.Entity.facilities.nursery, "Matron Workaround"),
-		"Madam Select": makeSelectionPassageInfo(App.Entity.facilities.brothel, "Madam Workaround"),
-		"Milkmaid Select": makeSelectionPassageInfo(App.Entity.facilities.dairy, "Milkmaid Workaround"),
-		"Nurse Select": makeSelectionPassageInfo(App.Entity.facilities.clinic, "Nurse Workaround"),
-		"DJ Select": makeSelectionPassageInfo(App.Entity.facilities.club, "DJ Workaround"),
-		"Farmer Select": makeSelectionPassageInfo(App.Entity.facilities.farmyard, "Farmer Workaround"),
-		"Stewardess Select": makeSelectionPassageInfo(App.Entity.facilities.servantsQuarters, "Stewardess Workaround"),
-		"Schoolteacher Select": makeSelectionPassageInfo(App.Entity.facilities.schoolroom, "Schoolteacher Workaround"),
-		"Wardeness Select": makeSelectionPassageInfo(App.Entity.facilities.cellblock, "Wardeness Workaround"),
-		"Agent Select": makeSelectionPassageInfo(App.Entity.facilities.arcologyAgent, "Agent Workaround"),
-		"Recruiter Select": makeSelectionPassageInfo(App.Entity.facilities.penthouse, "Recruiter Workaround")
-	};
-
-	/** @type {App.Entity.Facilities.Facility} */
-	const passageFacility = passageToFacilityMap[passageName];
-	/** @type {{facility: App.Entity.Facilities.Facility, passage: string}} */
-	const slaveSelect = passageFacility === undefined ? selectionPassageToFacilityMap[passageName] : undefined;
-
-	for (const _ssi of _filteredSlaveIdxs) {
-		let _Slave = slaves[_ssi];
-
-		if (passageName === "Main" && V.useSlaveSummaryTabs === 1) {
-			if (tabName === "overview") {
-				if (V.showOneSlave === "Head Girl" && _Slave.assignment !== App.Data.Facilities.headGirlSuite.manager.assignment) continue;
-				if (V.showOneSlave === "recruit girls" && _Slave.assignment !== App.Data.Facilities.penthouse.manager.assignment) continue;
-				if (V.showOneSlave === "guard you" && _Slave.assignment !== App.Data.Facilities.armory.manager.assignment) continue;
-			} else {
-				if (tabName === "resting") {
-					if (_Slave.assignment !== "rest") continue;
-				} else {
-					if (tabName !== "all" && _Slave.assignment !== tabName) continue;
-				}
-			}
-		}
-
-		const _slaveName = SlaveFullName(_Slave);
-
-		// const _tableCount = 0;
-		let slaveImagePrinted = (V.seeImages === 1) && (V.seeSummaryImages === 1);
-
-		res.push(`<div id="slave_${ _Slave.ID }" style="clear:both">`);
-
-		if (passageFacility !== undefined) {
-			if (V.SlaveSummaryFiler === "assignable" || V.SlaveSummaryFiler === "transferable") {
-				if (!passageFacility.hasFreeSpace) {
-					res.pop();
-					continue;
-				}
-				const rejects = passageFacility.canHostSlave(_Slave);
-				if (rejects.length > 0) {
-					let rejectString = rejects.length === 1 ?
-						rejects[0]:
-						`${_slaveName}: <ul>${rejects.map(e => `<li>${e}</li>`).join('')}</ul>`;
-					res.push(`${rejectString}</div>`);
-					continue;
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-			} else if (V.SlaveSummaryFiler === "occupying") {
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-			} else {
-				if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) res.push(slaveImage(_Slave));
-				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-			}
-		} else if (slaveSelect !== undefined && slaveSelect.passage !== "") {
-			res.push(dividerAndImage(_Slave));
-			res.push(`[[${_slaveName}|${slaveSelect.passage}][$i = ${_ssi}]]`);
-		}
-		switch (passageName) {
-			case "Main":
-				if ((_Slave.choosesOwnClothes === 1) && (_Slave.clothes === "choosing her own clothes")) {
-					const _oldDevotion = _Slave.devotion;
-					saChoosesOwnClothes(_Slave);
-					slaves[_ssi].devotion = _oldDevotion;
-					_Slave = slaves[_ssi]; /* restore devotion value so repeatedly changing clothes isn't an exploit */
-				}
-				res.push(dividerAndImage(_Slave));
-				if (App.Data.Facilities.headGirlSuite.manager.assignment === _Slave.assignment) res.push('<strong><span class="lightcoral">HG</span></strong> ');
-				else if (App.Data.Facilities.penthouse.manager.assignment === _Slave.assignment) res.push('<strong><span class="lightcoral">RC</span></strong> ');
-				else if (App.Data.Facilities.armory.manager.assignment === _Slave.assignment) res.push('<strong><span class="lightcoral">BG</span></strong> ');
-
-				if (Array.isArray(V.personalAttention) && V.personalAttention.findIndex(s => s.ID === _Slave.ID) !== -1) {
-					res.push('<strong><span class="lightcoral"> PA</span></strong> ');
-				}
-				res.push(this.passageLink(_slaveName, 'Slave Interact', `$activeSlave = $slaves[${_ssi}]`)); /* lists their names */
-				break;
-
-			case "Personal Attention Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`<<link "${_slaveName}">> <<run App.UI.selectSlaveForPersonalAttention(${_Slave.ID})>><</link>>`);
-				break;
-			case "Subordinate Targeting":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Subordinate Targeting][$activeSlave.subTarget = $slaves[${_ssi}].ID]]`);
-				break;
-			case "Coursing Association":
-				if (V.SlaveSummaryFiler === "assignable") {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Assign][$i = ${_ssi}]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Retrieve][$i = ${_ssi}]]`);
-				}
-				break;
-			case "New Game Plus":
-				res.push(dividerAndImage(_Slave));
-				if (V.SlaveSummaryFiler === "assignable") {
-					res.push(`__''<span class="pink">${_Slave.slaveName}</span>''__`);
-				} else {
-					res.push(`__''<span class="pink">${_Slave.slaveName}</span>''__`);
-				}
-				break;
-			case "Rules Slave Select":
-				slaveImagePrinted = false;
-				if (V.SlaveSummaryFiler === "assignable") {
-					res.push(`__''[[${_slaveName}|Rules Slave Select Workaround][$activeSlave = $slaves[${_ssi}]]]''__`);
-				} else {
-					res.push(`__''[[${_slaveName}|Rules Slave Deselect Workaround][$activeSlave = $slaves[${_ssi}]]]''__`);
-				}
-				break;
-			case "Rules Slave Exclude":
-				slaveImagePrinted = false;
-				if (V.SlaveSummaryFiler === "assignable") {
-					res.push(`__''[[${_slaveName}|Rules Slave Exclude Workaround][$activeSlave = $slaves[${_ssi}]]]''__`);
-				} else {
-					res.push(`__''[[${_slaveName}|Rules Slave NoExclude Workaround][$activeSlave = $slaves[${_ssi}]]]''__`);
-				}
-				break;
-			case "Matchmaking":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				break;
-			case "Dinner Party Preparations":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				break;
-		}
-
-		SlaveStatClamp(_Slave);
-		_Slave.trust = Math.trunc(_Slave.trust);
-		_Slave.devotion = Math.trunc(_Slave.devotion);
-		_Slave.health = Math.trunc(_Slave.health);
-		V.slaves[_ssi] = _Slave;
-
-		res.push(' will ');
-		if ((_Slave.assignment === "rest") && (_Slave.health >= -20)) {
-			res.push(`<strong><u><span class="lawngreen">rest</span></u></strong>`);
-		} else if ((_Slave.assignment === "stay confined") && ((_Slave.devotion > 20) || ((_Slave.trust < -20) && (_Slave.devotion >= -20)) || ((_Slave.trust < -50) && (_Slave.devotion >= -50)))) {
-			res.push(`<strong><u><span class="lawngreen">stay confined.</span></u></strong>`);
-			if (_Slave.sentence > 0) {
-				res.push(` (${_Slave.sentence} weeks)`);
-			}
-		} else if (_Slave.choosesOwnAssignment === 1) {
-			res.push('choose her own job');
-		} else {
-			res.push(_Slave.assignment);
-			if (_Slave.sentence > 0) res.push(` ${_Slave.sentence} weeks`);
-		}
-		res.push('. ');
-
-		if ((V.displayAssignments === 1) && (passageName === "Main") && (_Slave.ID !== V.HeadGirl.ID) && (_Slave.ID !== V.Recruiter.ID) && (_Slave.ID !== V.Bodyguard.ID)) {
-			res.push(App.UI.jobLinks.assignments(_ssi, "Main"));
-		}
-
-		const _numFacilities = V.brothel + V.club + V.dairy + V.farmyard + V.servantsQuarters + V.masterSuite + V.spa + V.clinic + V.schoolroom + V.cellblock + V.arcade + V.HGSuite;
-
-		if (_numFacilities > 0) {
-			if (passageName === "Main" || passageName === "Head Girl Suite" || passageName === "Spa" || passageName === "Brothel" || passageName === "Club" || passageName === "Arcade" || passageName === "Clinic" || passageName === "Schoolroom" || passageName === "Dairy" || passageName === "Farmyard" || passageName === "Servants' Quarters" || passageName === "Master Suite" || passageName === "Cellblock") {
-				V.returnTo = passageName;
-
-				res.push('<br>Transfer to: ');
-				res.push(App.UI.jobLinks.transfers(_ssi));
-			}
-		} /* closes _numFacilities */
-
-		if ((passageName !== 'Main') || (V.SlaveSummaryFiler !== undefined) || (V.useSlaveSummaryTabs === 0) || (tabName === "all")) {
-			res.push(`<span id="slave-${slaves[_ssi].ID}">&nbsp;</span>`);
-		}
-		res.push('<br/>');
-
-		if (slaveImagePrinted) {
-			res.push('&nbsp;&nbsp;&nbsp;&nbsp;');
-		}
-
-		clearSummaryCache();
-		res.push(SlaveSummary(_Slave));
-
-		V.slaves[_ssi] = _Slave;
-		res.push('</div>');
-
-		if (passageFacility !== undefined) {
-			res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-			if (V.SlaveSummaryFiler === "assignable") {
-				res.push(`<<link "Send ${_Slave.object} to ${passageFacility.name}" "Assign">><<set $i = ${_ssi}>><</link>>`);
-			} else if (V.SlaveSummaryFiler === "transferable") {
-				res.push(`<<link "Send ${_Slave.object} to ${passageFacility.name}" "Assign">><<set $i = ${_ssi}>><</link>>`);
-			} else if (V.SlaveSummaryFiler === "occupying") {
-				res.push(`<<link "Remove ${_Slave.object} from ${passageFacility.name}" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-			} else if (passageFacility.desc.manager !== null) {
-				const managerCapName = capFirstChar(passageFacility.desc.manager.position);
-				res.push(`[[Change or remove ${managerCapName}|${managerCapName} Select]]`);
-			}
-		} else if (slaveSelect !== undefined) {
-			if (slaveSelect.facility.manager.slaveHasExperience(_Slave)) {
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				res.push('<span class="lime">Has applicable career experience.</span>');
-			}
-		}
-		switch (passageName) {
-			case "Main":
-				continue;
-			case "Recruiter Select":
-				if (setup.recruiterCareers.includes(_Slave.career) || (_Slave.skill.recruiter >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('<span class="lime">Has applicable career experience.</span>');
-				}
-				break;
-			case "New Game Plus":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.SlaveSummaryFiler === "assignable") {
-					res.push(`<<link "Add to import list" "New Game Plus">>
-							<<set $slavesToImport += 1,$SlaveSummaryFiler = "occupying">>
-							<<= assignJob($slaves[${_ssi}], "be imported")>>
-						<</link>>`);
-				} else {
-					res.push(`<<link "Remove from import list" "New Game Plus">>
-							<<set $slavesToImport -= 1,$SlaveSummaryFiler = "assignable">>
-							<<= removeJob($slaves[${_ssi}], $slaves[${_ssi}].assignment)>>
-						<</link>>`);
-				}
-				break;
-			case "Matchmaking":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				res.push(`[[Match them|Matchmaking][$subSlave = $slaves[${_ssi}]]]`);
-				break;
-			case "Dinner Party Preparations":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				res.push(`[[Make her the main course|Dinner Party Execution][$activeSlave = $slaves[${_ssi}]]]`);
-				break;
-		}
-	}
-	return res.join("");
-};
-
-/**
- * Adds/removes a slave with the given id to/from the personal attention array
- * @param {number} id slave id
- */
-App.UI.selectSlaveForPersonalAttention = function(id) {
-	const V = State.variables;
-
-	if (!Array.isArray(V.personalAttention)) {
-		/* first PA target */
-		V.personalAttention = [{
-			ID: id,
-			trainingRegimen: "undecided"
-		}];
-	} else {
-		const _pai = V.personalAttention.findIndex(function(s) {
-			return s.ID === id;
-		});
-		if (_pai === -1) {
-			/* not already a PA target; add */
-			V.activeSlave = getSlave(id);
-			V.personalAttention.push({
-				ID: id,
-				trainingRegimen: "undecided"
-			});
-		} else {
-			/* already a PA target; remove */
-			V.personalAttention.deleteAt(_pai);
-			if (V.personalAttention.length === 0) {
-				V.personalAttention = "sex";
-			}
-		}
-	}
-	SugarCube.Engine.play("Personal Attention Select");
-};
diff --git a/src/js/utilJS.js b/src/js/utilJS.js
index df867e13be04289ab90aa87ece3ab6ba22ddc6ad..3ef0515773ed268729ff3b0ec6104585737dac9f 100644
--- a/src/js/utilJS.js
+++ b/src/js/utilJS.js
@@ -1785,20 +1785,80 @@ window.HackingSkillMultiplier = function() {
 	}
 };
 
-window.opentab = function(evt, tabName) {
-	const V = State.variables;
-	/* var passage = passage().trim().replace(/ /g,"+");*/
-	const tabcontent = document.getElementsByClassName("tabcontent");
-	for (let i = 0; i < tabcontent.length; i++) {
-		tabcontent[i].style.display = "none";
+App.UI.tabbar = function() {
+	return {
+		openTab: openTab,
+		tabButton: tabButton,
+		makeTab: makeTab,
+		handlePreSelectedTab: handlePreSelectedTab
+	};
+
+	function openTab(evt, tabName) {
+		const V = State.variables;
+		/* var passage = passage().trim().replace(/ /g,"+");*/
+		const tabcontent = document.getElementsByClassName("tabcontent");
+		for (let i = 0; i < tabcontent.length; i++) {
+			tabcontent[i].style.display = "none";
+		}
+		const tablinks = document.getElementsByClassName("tablinks");
+		for (let i = 0; i < tablinks.length; i++) {
+			tablinks[i].className = tablinks[i].className.replace(" active", "");
+		}
+		V.tabChoice[_tabChoiceVarName()] = tabName; /* The regex strips spaces and " ' " from passage names, making "Servants' Quarters" into "ServantsQuarters" and allowing it to be used as a label in this object. */
+		document.getElementById(tabName).style.display = "block";
+		evt.currentTarget.className += " active";
+	}
+
+	/**
+	 * @param {string} name
+	 * @param {string} text
+	 * @returns {string}
+	 */
+	function tabButton(name, text) {
+		return `<button class="tablinks" onclick="App.UI.tabbar.openTab(event, '${name}')" id="tab ${name}">${text}</button>`;
+	}
+
+	/**
+	 * @param {string} name
+	 * @param {string} content
+	 * @returns {string}
+	 */
+	function makeTab(name, content) {
+		return `<div id="${name}" class="tabcontent"><div class="content">` + content + '</div></div>';
+	}
+
+	function handlePreSelectedTab() {
+		let selectedTab = State.variables.tabChoice[_tabChoiceVarName()];
+		if (!selectedTab) { selectedTab = "assign"; }
+		$(document).one(':passagedisplay', function () {
+			let tabBtn = document.getElementById(`tab ${selectedTab}`);
+			if (!tabBtn) {
+				tabBtn = document.getElementsByClassName('tablinks').item(0);
+			}
+			if (tabBtn) { tabBtn.click(); }
+		});
 	}
-	const tablinks = document.getElementsByClassName("tablinks");
-	for (let i = 0; i < tablinks.length; i++) {
-		tablinks[i].className = tablinks[i].className.replace(" active", "");
+
+	function _tabChoiceVarName() {
+		return passage().trim().replace(/ |'/g, '');
 	}
-	V.tabChoice[passage().trim().replace(/ |'/g, "")] = tabName; /* The regex strips spaces and " ' " from passage names, making "Servants' Quarters" into "ServantsQuarters" and allowing it to be used as a label in this object. */
-	document.getElementById(tabName).style.display = "block";
-	evt.currentTarget.className += " active";
+}();
+
+
+/**
+ * replaces special HTML charachters with their '&xxx' forms
+ * @param {string} text
+ * @returns {string}
+ */
+App.Utils.escapeHtml = function(text) {
+	const map = {
+		'&': '&amp;',
+		'<': '&lt;',
+		'>': '&gt;',
+		'"': '&quot;',
+		"'": '&#039;'
+	};
+	return text.replace(/[&<>"']/g, m => map[m]);
 };
 
 /**
@@ -1817,17 +1877,59 @@ window.opentab = function(evt, tabName) {
 * // equal to [[Go to town|Town]]
 * App.UI.passageLink("Go to town", "Town")
 */
-App.UI.passageLink = function(linkText, passage, setter, elementType) {
-	if (!elementType) elementType = "a";
-
+App.UI.passageLink = function(linkText, passage, setter, elementType = 'a') {
 	let res = `<${elementType} data-passage="${passage}"`;
 	if (setter) {
-		res += ` data-setter="${setter}"`;
+		res += ` data-setter="${App.Utils.escapeHtml(setter)}"`;
 	}
 	res += `>${linkText}</${elementType}>`;
 	return res;
 };
 
+/**
+ * Replaces contents of the element, identified by the given selector, with wiki'ed new content
+ *
+ * The function is an analogue to the SugarCube <<replace>> macro (and is a simplified version of it)
+ * @param {string} selector
+ * @param {string} newContent
+ */
+App.UI.replace = function (selector, newContent) {
+	let ins = jQuery(document.createDocumentFragment());
+	ins.wiki(newContent);
+	const target = $(selector);
+	target.empty();
+	target.append(ins);
+};
+
+/**
+ * A simple macro which allows to create wrapping html elements with dynamic IDs.
+ *
+ * idea blatantly robbed from the spanMacroJS.tw but expanded to a more generic case, allowing <div>,
+ * <button> or whatever you want elements, default is for the div though.
+ * In addition, you can pass an object in as the first argument instead of an id, and each of the
+ * object's attributes will become attributes of the generate tag.
+ *
+ * @example
+ * htag('test', "red") // <div id="red">test</div>
+ * htag('test', {class: red}); // <div class="red">test</div>
+ * htag('test', {class: red, id: green}); // <div class="red" id="green">test</div>
+ * @param {string} text
+ * @param {string|object} attributes
+ * @param {string} [tag='div']
+ * @returns {string}
+ */
+App.UI.htag = function (text, attributes, tag = 'div') {
+	const payload = text.replace(/(^\n+|\n+$)/, "");
+
+	if ("object" === typeof attributes) {
+		attributes = $.map(attributes, (val, key) => `${key}="${val}"`).join(" ");
+	} else {
+		attributes = `id="${attributes.trim()}"`;
+	}
+
+	return `<${tag}${attributes}>${payload}</${tag}>`;
+};
+
 window.SkillIncrease = (function() {
 	return {
 		Oral: OralSkillIncrease,
@@ -2103,7 +2205,7 @@ window.jsDef = function(input) {
 	}
 };
 
-/** 
+/**
  * Return a career at random that would be suitable for the given slave.
  * Currently only considers their age
  * @param {App.Entity.SlaveState} slave
@@ -2338,7 +2440,7 @@ window.skinToneLevel = function(skinTone) {
  * @param {number} value
  * @returns {string}
  */
- 
+
 window.changeSkinTone = function(skin, value) {
 	if (!setup.naturalSkins.includes(skin)) {
 		return skin;
@@ -2424,3 +2526,12 @@ App.Utils.setActiveSlaveByIndex = function(index) {
 		State.variables.activeSlave = State.variables.slaves[index];
 	}
 };
+
+/**
+ * Returns index in the slave array for the given ID
+ * @param {number} id slave ID
+ * @returns {number}
+ */
+App.Utils.slaveIndexForId = function (id) {
+	return State.variables.slaveIndices[id];
+};
diff --git a/src/npc/agent/agentSelect.tw b/src/npc/agent/agentSelect.tw
index 85b4792f88b08ab34bf35add786ec5ce2fee4991..cbf4d513f7618cd35c6f9add72293838ea1939c1 100644
--- a/src/npc/agent/agentSelect.tw
+++ b/src/npc/agent/agentSelect.tw
@@ -2,4 +2,9 @@
 
 <<set $nextButton = "Back", $nextLink = "Neighbor Interact", $showEncyclopedia = 1, $encyclopedia = "Agents">>
 ''Appoint an Agent from your devoted slaves:''
-<<include "Slave Summary">>
+
+<<= App.UI.SlaveList.slaveSelectionList(
+		s => (s.fuckdoll === 0 && s.devotion > 20 && s.intelligence + s.intelligenceImplant > 15 && s.intelligenceImplant >= 15 && canWalk(s) && canSee(s) && canHear(s) && canTalk(s) && s.broodmother < 2 && (s.breedingMark !== 1 || State.variables.propOutcome === 0)),
+		(slave, index) => App.UI.passageLink(SlaveFullName(slave), 'Agent Workaround', `$i = ${index}`),
+		s => App.Entity.facilities.arcologyAgent.manager.slaveHasExperience(s)
+	)>>
diff --git a/src/pregmod/widgets/assignmentFilterWidget.tw b/src/pregmod/widgets/assignmentFilterWidget.tw
deleted file mode 100644
index c37b3fbf0914fe9e7b5a3ff5b31a77fc9fd2be95..0000000000000000000000000000000000000000
--- a/src/pregmod/widgets/assignmentFilterWidget.tw
+++ /dev/null
@@ -1,121 +0,0 @@
-:: assignment-filter widget [widget nobr]
-
-/*
-* filters the list according to the selected Facility
-* function(y) is a loop through $slaves to set assignmentVisible to 1 and returns a new array
-* function(x) filters the slaves with the given condition ( here its the assignment )
-* so basically function(x) finds the slaves that are selected and function(y) sets them to be visible
-*/
-
-/*
-* These widgets set the visibilities for the different Facilities
-*/
-
-<<widget "resetAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 1})>><<set $slaves.filter(function(x){return x.assignment.includes("in the") || x.assignment.includes("be the") || x.assignment.includes("live with") || (x.assignment.includes("be your") && x.assignment != "be your Head Girl") || x.assignment.includes("work as a ")}).map(function(y){y.assignmentVisible = 0})>>
-<</widget>>
-
-<<widget "showallAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 1})>><<set $slaves.filter(function(x){return x.assignment.includes("agent")}).map(function(y){y.assignmentVisible = 0})>>
-<</widget>>
-
-<<widget "arcadeAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "be confined in the arcade"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "brothelAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "work in the brothel" || x.assignment == "be the Madam"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "cellblockAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "be confined in the cellblock" || x.assignment == "be the Wardeness"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "clinicAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "get treatment in the clinic" || x.assignment == "be the Nurse"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "clubAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "serve in the club" || x.assignment == "be the DJ"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "dairyAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "work in the dairy" || x.assignment == "be the Milkmaid"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "farmyardAssignmentFilter">>
-		<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "work as a farmhand" || x.assignment == "be the Farmer"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "headgirlSuiteAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "live with your Head Girl"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "penthouseAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "rest" || x.assignment == "be a subordinate slave" || x.assignment == "whore" || x.assignment == "serve the public" || x.assignment == "work a glory hole" || x.assignment == "get milked" || x.assignment == "be a servant" || x.assignment == "please you"|| x.assignment == "stay confined" || x.assignment == "take classes" || x.assignment == "choose her own job" || x.assignment == "live with your Head Girl"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "schoolAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "learn in the schoolroom" || x.assignment == "be the Schoolteacher"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "spaAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "rest in the spa" || x.assignment == "be the Attendant"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "nurseryAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "work as a nanny" || x.assignment == "be the Matron"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "suiteAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "serve in the master suite" || x.assignment == "be your Concubine"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-<<widget "quartersAssignmentFilter">>
-	<<set $slaves.map(function(y){y.assignmentVisible = 0})>><<set $slaves.filter(function(x){return x.assignment == "work as a servant" || x.assignment == "be the Stewardess"}).map(function(y){y.assignmentVisible = 1})>>
-<</widget>>
-
-/*
- * Checks from which Facility its get called and removes it from the list
- * this is the Main Filter widget used on all Passages atm
- * sets SlaveSummaryFiler = "assignable" so slave summary provides send-to-facility links
-*/
-<<widget "assignmentFilter">>
-	<<link All>><<showallAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>>
-	<<if passage() != "Arcade">><<print " | ">><<link Arcade>><<arcadeAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Brothel">><<print " | ">><<link Brothel>><<brothelAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Cellblock">><<print " | ">><<link Cellblock>><<cellblockAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Clinic">><<print " | ">><<link Clinic>><<clinicAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Club">><<print " | ">><<link Club>><<clubAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Dairy">><<print " | ">><<link Dairy>><<dairyAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Farmyard">><<print " | ">><<link Farmyard>><<farmyardAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<print " | ">><<link Penthouse>><<penthouseAssignmentFilter>><<replace #ComingGoing>><<include 'Slave Summary'>><<set $SlaveSummaryFiler = "assignable">><<resetAssignmentFilter>><</replace>><</link>>
-	<<if passage() != "Schoolroom">><<print " | ">><<link Schoolroom>><<schoolAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Spa">><<print " | ">><<link Spa>><<spaAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Nursery">><<print " | ">><<link Nursery>><<nurseryAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Master Suite">><<print " | ">><<link Suite>><<suiteAssignmentFilter>><<replace #ComingGoing>><<set $SlaveSummaryFiler = "assignable">><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<if passage() != "Servants' Quarters">><<print " | ">><<link Quarters>><<quartersAssignmentFilter>><<set $SlaveSummaryFiler = "assignable">><<replace #ComingGoing>><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><</link>><</if>>
-	<<print " | ">><<link @@.lime;Experienced@@>><<showallAssignmentFilter>><<set $SlaveSummaryFiler = "experienced">><<replace #ComingGoing>><<include 'Slave Summary'>><<resetAssignmentFilter>><</replace>><<set $SlaveSummaryFiler = "">><</link>>
-<</widget>>
-
-/*
-* undefinedAssignmentFilter serves no purpose atm
-* might use it for RA Slave filter and Matchmaking
-*/
-<<widget "undefinedAssignmentFilter">>
-	<<link All>><<showallAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Arcade>><<arcadeAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Brothel>><<brothelAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Cellblock>><<cellblockAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Clinic>><<clinicAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Club>><<clubAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Dairy>><<dairyAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Farmyard>><<farmyardAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Penthouse>><<penthouseAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Schoolroom>><<schoolAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Spa>><<spaAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Nursery>><<nurseryAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Suite>><<suiteAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>><<print " | ">>
-	<<link Quarters>><<quartersAssignmentFilter>><<replace $args.full>><<include 'Slave Summary'>><</replace>><</link>>
-	<<resetAssignmentFilter>>
-<</widget>>
\ No newline at end of file
diff --git a/src/uncategorized/BackwardsCompatibility.tw b/src/uncategorized/BackwardsCompatibility.tw
index 5d8726a4b9e6ae1d48e88218f3da6d1ab7169f4c..e9526a8d4db17ebb360fa8779f279bda104a662f 100644
--- a/src/uncategorized/BackwardsCompatibility.tw
+++ b/src/uncategorized/BackwardsCompatibility.tw
@@ -3683,6 +3683,9 @@ Done!
 	<</for>>
 <</if>>
 
+<<unset $showOneSlave>>
+<<unset $SlaveSummaryFiler>>
+
 <<if $releaseID < 1044>>
 	<<set $releaseID = 1044>>
 <</if>>
diff --git a/src/uncategorized/arcade.tw b/src/uncategorized/arcade.tw
index 690eb1335dfb15dc1a900c70184408491e3d9b46..b7688d666ae33c69af7a24237a43f9602e85127e 100644
--- a/src/uncategorized/arcade.tw
+++ b/src/uncategorized/arcade.tw
@@ -5,7 +5,6 @@
 <<if $arcadeName != "the Arcade">>
 	<<set $arcadeNameCaps = $arcadeName.replace("the ", "The ")>>
 <</if>>
-<<arcadeAssignmentFilter>>
 $arcadeNameCaps
 <<switch $arcadeDecoration>>
 <<case "Roman Revivalist">>
@@ -138,44 +137,6 @@ $arcadeNameCaps
 
 <br><br>
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $arcadeSlaves > 0>>
-			<<arcadeAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$arcadeNameCaps is empty for the moment.<br> //
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($arcade <= $arcadeSlaves) && $arcadeUpgradeFuckdolls == 0>>
-			''$arcadeNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $arcadeSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Arcade == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.listSJFacilitySlaves(App.Entity.facilities.arcade, passage())>>
 
 <br><br>Rename $arcadeName: <<textbox "$arcadeName" $arcadeName "Arcade">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/attendantSelect.tw b/src/uncategorized/attendantSelect.tw
index 18e7dd6c10afe581edda308b5f3a01b0d27ae9ec..e9c6661f6128d969d89a1c0b2ce203ca06bc30c5 100644
--- a/src/uncategorized/attendantSelect.tw
+++ b/src/uncategorized/attendantSelect.tw
@@ -1,7 +1,6 @@
 :: Attendant Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Spa", $showEncyclopedia = 1, $encyclopedia = "Attendant">>
-<<showallAssignmentFilter>>
 <<if ($Attendant != 0)>>
 	<<set $Attendant = getSlave($Attendant.ID)>>
 	<<setLocalPronouns $Attendant>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint an Attendant from your devoted slaves:''
 <br><br>[[None|Attendant Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.spa)>>
diff --git a/src/uncategorized/bgSelect.tw b/src/uncategorized/bgSelect.tw
index dca3c18ad31bd7c2750199aeb389177e4f3372a8..f892a8721469061dd5cbb5e131595c1846bdb482 100644
--- a/src/uncategorized/bgSelect.tw
+++ b/src/uncategorized/bgSelect.tw
@@ -1,7 +1,6 @@
 :: BG Select [nobr]
 
 <<set $nextButton = "Back to Main", $nextLink = "Main", $showEncyclopedia = 1, $encyclopedia = "Bodyguard">>
-<<showallAssignmentFilter>>
 <<if ($Bodyguard != 0)>>
 	<<set $Bodyguard = getSlave($Bodyguard.ID)>>
 	<<setLocalPronouns $Bodyguard>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a bodyguard from your devoted slaves:''
 <br><br>[[None|Bodyguard Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.armory, "BG Workaround")>>
diff --git a/src/uncategorized/brothel.tw b/src/uncategorized/brothel.tw
index bb80d9b4f8f0b3b9f8e83dbaf4ea8d5add533c24..5dd2b021612a63395837a60ab941b651785ad08c 100644
--- a/src/uncategorized/brothel.tw
+++ b/src/uncategorized/brothel.tw
@@ -1,11 +1,10 @@
 :: Brothel [nobr]
 
-<<set $nextButton = "Back to Main", $nextLink = "Main", $returnTo = "Brothel", $showEncyclopedia = 1, $encyclopedia = "Brothel", $brothelSlaves = $BrothiIDs.length, $SlaveSummaryFiler = "assignable">>
+<<set $nextButton = "Back to Main", $nextLink = "Main", $returnTo = "Brothel", $showEncyclopedia = 1, $encyclopedia = "Brothel", $brothelSlaves = $BrothiIDs.length>>
 
 <<if $brothelName != "the Brothel">>
 	<<set $brothelNameCaps = $brothelName.replace("the ", "The ")>>
 <</if>>
-<<brothelAssignmentFilter>>
 $brothelNameCaps
 <<switch $brothelDecoration>>
 <<case "Roman Revivalist">>
@@ -206,53 +205,6 @@ Last week this
 <<BrothelStatistics 1>>
 
 <br><br>
-<<if $Madam != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a Madam. [[Appoint one|Madam Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $brothelSlaves > 0>>
-			<<brothelAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$brothelNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($brothel <= $brothelSlaves)>>
-			''$brothelNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $brothelSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Brothel == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.brothel)>>
 
 <br><br>Rename $brothelName: <<textbox "$brothelName" $brothelName "Brothel">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/cellblock.tw b/src/uncategorized/cellblock.tw
index 424333eabcf931fea40b22aa14857c8f3b70860e..11897c9de6c846c26126fa65507dc7dac0e693eb 100644
--- a/src/uncategorized/cellblock.tw
+++ b/src/uncategorized/cellblock.tw
@@ -5,7 +5,6 @@
 <<if $cellblockName != "the Cellblock">>
 	<<set $cellblockNameCaps = $cellblockName.replace("the ", "The ")>>
 <</if>>
-<<cellblockAssignmentFilter>>
 $cellblockNameCaps
 <<switch $cellblockDecoration>>
 <<case "Roman Revivalist">>
@@ -111,53 +110,6 @@ $cellblockNameCaps
 <</if>>
 
 <br><br>
-<<if $Wardeness != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a Wardeness. [[Appoint one|Wardeness Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-	<<if $cellblockSlaves > 0>>
-		<<cellblockAssignmentFilter>>
-		<<set $SlaveSummaryFiler = "occupying">>
-		<<include "Slave Summary">>
-		<<resetAssignmentFilter>>
-	<<else>>
-		<br><br>//$cellblockNameCaps is empty for the moment.<br>//
-	<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($cellblock <= $cellblockSlaves)>>
-			''$cellblockNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $cellblockSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Cellblock == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.cellblock)>>
 
 <br><br>Rename $cellblockName: <<textbox "$cellblockName" $cellblockName "Cellblock">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/clinic.tw b/src/uncategorized/clinic.tw
index a7ba5923f44e830088050518c1e6ab29c9f3b72d..a4ca2c6402832211b9e886b1d13142b828cd66be 100644
--- a/src/uncategorized/clinic.tw
+++ b/src/uncategorized/clinic.tw
@@ -5,7 +5,6 @@
 <<if $clinicName != "the Clinic">>
 	<<set $clinicNameCaps = $clinicName.replace("the ", "The ")>>
 <</if>>
-<<clinicAssignmentFilter>>
 $clinicNameCaps
 <<switch $clinicDecoration>>
 <<case "Roman Revivalist">>
@@ -140,68 +139,6 @@ $clinicNameCaps
 <</if>>
 
 <br><br>
-<<if $Nurse != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a clinical Nurse. [[Appoint one|Nurse Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'transfer')" id="tab transfer">Transfer from Facility</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $clinicSlaves > 0>>
-			<<clinicAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$clinicNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($clinic <= $clinicSlaves)>>
-			''$clinicNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $clinicSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<div id="transfer" class="tabcontent">
-	<div class="content">
-		<<if ($clinic <= $clinicSlaves)>>
-			''$clinicNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $clinicSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "transferable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Clinic == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<elseif ($tabChoice.Clinic == "remove")>>
-	<script>document.getElementById("tab remove").click();</script>
-<<elseif ($tabChoice.Clinic == "transfer")>>
-	<script>document.getElementById("tab transfer").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.clinic, true)>>
 
 <br><br>Rename $clinicName: <<textbox "$clinicName" $clinicName "Clinic">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/club.tw b/src/uncategorized/club.tw
index 2e69d4f5c9f95385189cbbb697e6f5329c0dde19..30ef287ee0ae59dc6feb16777975a22f3c35a517 100644
--- a/src/uncategorized/club.tw
+++ b/src/uncategorized/club.tw
@@ -5,7 +5,6 @@
 <<if $clubName != "the Club">>
 	<<set $clubNameCaps = $clubName.replace("the ", "The ")>>
 <</if>>
-<<clubAssignmentFilter>>
 $clubNameCaps
 <<switch $clubDecoration>>
 <<case "Roman Revivalist">>
@@ -250,53 +249,6 @@ $clubNameCaps
 <<ClubStatistics 1>>
 
 <br><br>
-<<if $DJ != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a DJ. [[Appoint one|DJ Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $clubSlaves > 0>>
-			<<clubAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$clubNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($club <= $clubSlaves)>>
-			''$clubNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $clubSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Club == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.club)>>
 
 <br><br>Rename $clubName: <<textbox "$clubName" $clubName "Club">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/concubineSelect.tw b/src/uncategorized/concubineSelect.tw
index b4242ad2b21d37ecee7a40e5c5b7616bf1d00d03..5bc559bd4337a06dd66880b0aa6be1758875a1ae 100644
--- a/src/uncategorized/concubineSelect.tw
+++ b/src/uncategorized/concubineSelect.tw
@@ -1,7 +1,6 @@
 :: Concubine Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Master Suite", $showEncyclopedia = 1, $encyclopedia = "Concubine">>
-<<showallAssignmentFilter>>
 <<if ($Concubine != 0)>>
 	<<set $Concubine = getSlave($Concubine.ID)>>
 	<<setLocalPronouns $Concubine>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Concubine from your devoted slaves:''
 <br><br>[[None|Concubine Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.masterSuite)>>
diff --git a/src/uncategorized/coursingAssociation.tw b/src/uncategorized/coursingAssociation.tw
index e774b3188ffc25a08a3afa395a058ac16ddeecc1..03276693f817dfb1893463bcd208c156c21ea3bc 100644
--- a/src/uncategorized/coursingAssociation.tw
+++ b/src/uncategorized/coursingAssociation.tw
@@ -3,13 +3,11 @@
 <<set $nextButton = "Back to Main">>
 <<set $nextLink = "Main">>
 <<set $returnTo = "Coursing Association">>
-<<showallAssignmentFilter>>
 
 You are a member of $arcologies[0].name's Coursing Association. Coursing is a Free Cities revival of the old sport of hunting rabbits and hares with sighthounds, with the typically Free Cities amendments that the hares are replaced by newly enslaved people, the sighthounds are replaced by trained slaves, and the killing of the hare is replaced by rape. Truly, a sport of gentlemen.
 <br><br>
 The chasing slaves are known as lurchers, the term once used for the sighthounds. They require speed most of all, but must also be able to tackle their quarry; lurchers with the ability and willingness to make a spectacle of molesting the hares can improve their owners' reputations.
 
-<<showallAssignmentFilter>>
 <<if $Lurcher != 0>>
 	<<= SlaveFullName($Lurcher)>> is assigned to compete as your lurcher.
 <<else>>
@@ -20,16 +18,13 @@ The chasing slaves are known as lurchers, the term once used for the sighthounds
 
 <<if $Lurcher != 0>>
 	<br><br>''Fire your Lurcher:''
-	<<set $SlaveSummaryFiler = "occupying">>
-	<<include "Slave Summary">>
+	<<= App.UI.SlaveList.render([App.Utils.slaveIndexForId($Lurcher.ID)], [],
+		(slave, index) => App.UI.passageLink(SlaveFullName(slave), 'Retrieve', `$i = ${App.Utils.slaveIndexForId($Lurcher.ID)}`))>>
 <</if>>
 
 <br><br>''Select a slave to course as a Lurcher:''
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<set $SlaveSummaryFiler = "assignable">>
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
+<<= App.UI.SlaveList.slaveSelectionList(
+		s => $Lurcher.ID !== s.ID && canWalk(s) && (s.assignmentVisible === 1 && s.fuckdoll === 0),
+		(slave, index) => App.UI.passageLink(SlaveFullName(slave), 'Assign', `$i = ${index}`)
+	)>>
diff --git a/src/uncategorized/dairy.tw b/src/uncategorized/dairy.tw
index 5032ffbcf13584e0ed5f7e416711a718d643cd02..dbab451e0032464f0a2c6393fcc7d56413b732d3 100644
--- a/src/uncategorized/dairy.tw
+++ b/src/uncategorized/dairy.tw
@@ -4,7 +4,6 @@
 
 <<SlaveIDSort $DairyiIDs>>
 <<set _DL = $DairyiIDs.length, $dairySlaves = _DL>>
-<<dairyAssignmentFilter>>
 <<if $dairyName != "the Dairy">>
 	<<set $dairyNameCaps = $dairyName.replace("the ", "The ")>>
 <</if>>
@@ -500,9 +499,9 @@ $dairyNameCaps
 <<DairyStatistics 1>>
 
 <br><br>
+<<set _facility = App.Entity.facilities.dairy>>
 <<if ($Milkmaid != 0)>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.displayManager(_facility)>>
 	<<if canAchieveErection($Milkmaid) && $Milkmaid.pubertyXY == 1>>
 		<<setLocalPronouns $Milkmaid>>
 		<br>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -528,44 +527,6 @@ $dairyNameCaps
 <</if>>
 <br><br>
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $dairySlaves > 0>>
-			<<dairyAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$dairyNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($dairy <= $dairySlaves+_seed)>>
-			''$dairyNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $dairySlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Dairy == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.listSJFacilitySlaves(_facility, passage())>>
 
 <br><br>Rename $dairyName: <<textbox "$dairyName" $dairyName "Dairy">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/djSelect.tw b/src/uncategorized/djSelect.tw
index f4a6bf3cfcce042d96fa172fda860d559f846c6a..e84f616be37a1f4d1b6071633a89c4dd743d5b9a 100644
--- a/src/uncategorized/djSelect.tw
+++ b/src/uncategorized/djSelect.tw
@@ -1,7 +1,6 @@
 :: DJ Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Club", $showEncyclopedia = 1>><<set $encyclopedia = "DJ">>
-<<showallAssignmentFilter>>
 <<if ($DJ != 0)>>
 	<<set $DJ = getSlave($DJ.ID)>>
 	<<setLocalPronouns $DJ>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a DJ from your devoted slaves:''
 <br><br>[[None|DJ Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.club)>>
diff --git a/src/uncategorized/economics.tw b/src/uncategorized/economics.tw
index d4cad0118a67f176cf76ea6006b5f88c8d3841ba..17a8703cfde0b40470facd63936f9b4de5c748fc 100644
--- a/src/uncategorized/economics.tw
+++ b/src/uncategorized/economics.tw
@@ -56,22 +56,22 @@
 <body>
 
 <div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'Arcologies')" id="defaultOpen">Arcologies</button>
-	<button class="tablinks" onclick="opentab(event, 'Management')">Arcology Management</button>
+	<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Arcologies')" id="defaultOpen">Arcologies</button>
+	<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Management')">Arcology Management</button>
 	<<if $FSAnnounced > 0>>
-		<button class="tablinks" onclick="opentab(event, 'Societies')">Society Development</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Societies')">Society Development</button>
 	<</if>>
 	<<if $corpIncorporated == 1>>
-		<button class="tablinks" onclick="opentab(event, 'Corporation')">Corporation Developments</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Corporation')">Corporation Developments</button>
 	<</if>>
 	<<if $secExp == 1>>
-		<button class="tablinks" onclick="opentab(event, 'Authority')">Authority</button>
-		<button class="tablinks" onclick="opentab(event, 'securityReport')">Security</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Authority')">Authority</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'securityReport')">Security</button>
 	<</if>>
-	<button class="tablinks" onclick="opentab(event, 'Reputation')">Reputation</button>
-	<button class="tablinks" onclick="opentab(event, 'Business')">Personal Business</button>
+	<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Reputation')">Reputation</button>
+	<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Business')">Personal Business</button>
 	<<if ($PC.boobs == 1 && $PC.boobsBonus > 0) || $PC.pregKnown == 1 || $playerAging != 0>>
-		<button class="tablinks" onclick="opentab(event, 'Personal')">Personal Notes</button>
+		<button class="tablinks" onclick="App.UI.tabbar.openTab(event, 'Personal')">Personal Notes</button>
 	<</if>>
 </div>
 
diff --git a/src/uncategorized/headGirlSuite.tw b/src/uncategorized/headGirlSuite.tw
index 8a42b0aac0057103c5a91c9d9fe6502d1343a9c4..00868d6255150c8203caa5dec28af7d26be1846b 100644
--- a/src/uncategorized/headGirlSuite.tw
+++ b/src/uncategorized/headGirlSuite.tw
@@ -5,7 +5,6 @@
 <<if $HGSuiteName != "the Head Girl Suite">>
 	<<set $HGSuiteNameCaps = $HGSuiteName.replace("the ", "The ")>>
 <</if>>
-<<headgirlSuiteAssignmentFilter>>
 <<set _i = $slaves.findIndex(function(s) { return s.assignment == "live with your Head Girl"; })>>
 
 <<if $HeadGirl == 0>>
@@ -46,43 +45,6 @@
 <</if>>
 <br><br>
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave to the Head Girl</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Bring the Head Girl's girl out of $HGSuiteName</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $HGSuiteSlaves > 0>>
-			<<headgirlSuiteAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($slaves.length > $HGSuiteSlaves) && ($HGSuiteSlaves < 1)>>
-			<<assignmentFilter>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<<else>>
-			''Head Girl already has a girl.''
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.HeadGirlSuite == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.listSJFacilitySlaves(App.Entity.facilities.headGirlSuite)>>
 
 <br><br>Rename $HGSuiteName: <<textbox "$HGSuiteName" $HGSuiteName "Head Girl Suite">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/hgSelect.tw b/src/uncategorized/hgSelect.tw
index 86cd389140391f0d6a426310efb82285aa40204b..98113a7d0fd141e97fec1f68db408e3c31c9fc64 100644
--- a/src/uncategorized/hgSelect.tw
+++ b/src/uncategorized/hgSelect.tw
@@ -1,7 +1,6 @@
 :: HG Select [nobr]
 
 <<set $nextButton = "Back to Main", $nextLink = "Main", $showEncyclopedia = 1, $encyclopedia = "Head Girl">>
-<<showallAssignmentFilter>>
 
 <h1>Head Girl Management</h1>
 
@@ -89,9 +88,4 @@ _HGName
 <br><br>''Appoint a Head Girl from among your devoted slaves:''
 <br><br>[[None|HG Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.headGirlSuite, "HG Select")>>
diff --git a/src/uncategorized/madamSelect.tw b/src/uncategorized/madamSelect.tw
index 2e541d6d7468bdc17895d49d2087d75e29049a24..85f07ad835122415b43b8bb14d877b54a616a1e2 100644
--- a/src/uncategorized/madamSelect.tw
+++ b/src/uncategorized/madamSelect.tw
@@ -1,7 +1,6 @@
 :: Madam Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Brothel", $showEncyclopedia = 1, $encyclopedia = "Madam">>
-<<showallAssignmentFilter>>
 <<if ($Madam != 0)>>
 	<<set $Madam = getSlave($Madam.ID)>>
 	<<setLocalPronouns $Madam>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Madam from your devoted slaves:''
 <br><br>[[None|Madam Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.brothel)>>
diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw
index 40702a3a48979d8b6d9e1470751735ac33f85e56..28935922ea8fdf877f238432e92ca9dbe47191f9 100644
--- a/src/uncategorized/main.tw
+++ b/src/uncategorized/main.tw
@@ -1,7 +1,5 @@
 :: Main [nobr]
 
-<<unset $SlaveSummaryFiler>>
-<<resetAssignmentFilter>>
 <<if $releaseID >= 1000 || $ver.includes("0.9") || $ver.includes("0.8") || $ver.includes("0.7") || $ver.includes("0.6")>>
 	<<if $releaseID >= 1031>>
 	<<elseif $releaseID < 1031>>
@@ -114,469 +112,9 @@ __''MAIN MENU''__&nbsp;&nbsp;&nbsp;&nbsp;//[[Summary Options]]//
 	| //<<if $rulesError>>@@.yellow; WARNING: some custom rules will change slave variables @@<</if>><<link "Re-apply Rules Assistant now (this will only check slaves in the Penthouse)" "Main">><<for _i = 0;_i < _SL;_i++>><<if $slaves[_i].assignmentVisible == 1 && $slaves[_i].useRulesAssistant == 1>><<= DefaultRules($slaves[_i])>><</if>><</for>><</link>>//
 <</if>>
 
-<<if $useSlaveSummaryTabs == 1>>
-	<<if $positionMainLinks >= 0>>
-		<center>
-		<<= App.UI.View.MainLinks()>>
-		</center>
-		<br>
-	<</if>>
-	<<set _j = "Back", _k = "AS Dump", _l = "Main">>
-
-	<body>
-
-	<div class="tab">
-		<<set _penthouseSlaves = 0>>
-		<<run Object.keys($JobIDArray).forEach((job) => _penthouseSlaves += $JobIDArray[job].length)>>
-		<<if $useSlaveSummaryOverviewTab == 1>>
-		<button class="tablinks" onclick="opentab(event, 'overview')" id="tab overview">Overview</button>
-		<</if>>
-		<button class="tablinks" onclick="opentab(event, 'resting')" id="tab resting"> /*leaving resting always on as it changes a lot from week to week. */
-			Resting
-			<<if $JobIDArray['rest'].length > 0>>
-				($JobIDArray['rest'].length)
-			<</if>>
-		</button>
-		<<if $JobIDArray['stay confined'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'stay confined')" id="tab stay confined">
-				Confined
-				($JobIDArray['stay confined'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['take classes'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'take classes')" id="tab take classes">
-				Students
-				($JobIDArray['take classes'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['please you'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'please you')" id="tab please you">
-				Fucktoys
-				($JobIDArray['please you'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['whore'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'whore')" id="tab whore">
-				Whores
-				($JobIDArray['whore'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['serve the public'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'serve the public')" id="tab serve the public">
-				Public Servants
-				($JobIDArray['serve the public'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['be a servant'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'be a servant')" id="tab be a servant">
-				Servants
-				($JobIDArray['be a servant'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['get milked'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'get milked')" id="tab milked">
-				Cows
-				($JobIDArray['get milked'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['work a glory hole'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'work a glory hole')" id="tab work a glory hole">
-				Gloryhole
-				($JobIDArray['work a glory hole'].length)
-			</button>
-		<</if>>
-		<<if $JobIDArray['be a subordinate slave'].length > 0>>
-			<button class="tablinks" onclick="opentab(event, 'be a subordinate slave')" id="tab be a subordinate slave">
-				Subordinate slaves
-				($JobIDArray['be a subordinate slave'].length)
-			</button>
-		<</if>>
-
-		<button class="tablinks" onclick="opentab(event, 'all')" id="tab all">
-			All
-			<<if _penthouseSlaves > 0>>
-				<<if $HeadGirl != 0>>
-					<<set _penthouseSlaves++>>
-				<</if>>
-				<<if $Recruiter != 0>>
-					<<set _penthouseSlaves++>>
-				<</if>>
-				<<if $Bodyguard != 0>>
-					<<set _penthouseSlaves++>>
-				<</if>>
-				(_penthouseSlaves)
-			<</if>>
-		</button>
-	</div>
-
-	<div id="overview" class="tabcontent">
-		<div class="content">
-			<<set $slaveAssignmentTab = "overview">>
-			<<if def _HG>>
-				''__@@.pink;<<= SlaveFullName($HeadGirl)>>@@__'' is serving as your Head Girl<<if $arcologies[0].FSEgyptianRevivalistLaw == 1>> and Consort<</if>>.
-				<span id="manageHG"><strong><<link "Manage Head Girl" "HG Select">><</link>></strong></span> @@.cyan;[H]@@
-				<<set $showOneSlave = "Head Girl">>
-				<<include "Slave Summary">>
-			<<elseif (ndef _HG) && ($slaves.length > 1)>>
-				You have @@.red;not@@ selected a Head Girl<<if $arcologies[0].FSEgyptianRevivalistLaw == 1>> and Consort<</if>>. <span id="manageHG"><strong><<link "Select one" "HG Select">><</link>></strong></span> @@.cyan;[H]@@
-			<<elseif (ndef _HG)>>
-				//You do not have enough slaves to keep a Head Girl//
-			<</if>>
-			<br>
-			<<if def _RC>>
-				<<setLocalPronouns $slaves[_RC]>>
-				''__@@.pink;<<= SlaveFullName($Recruiter)>>@@__'' is working
-				<<if $recruiterTarget != "other arcologies">>
-					to recruit girls.
-				<<else>>
-					as a Sexual
-					<<if $arcologies[0].influenceTarget == -1>>
-						Ambassador, but @@.red;$he has no target to influence.@@
-					<<else>>
-						Ambassador to <<for $i = 0; $i < $arcologies.length; $i++>><<if $arcologies[$i].direction == $arcologies[0].influenceTarget>>$arcologies[$i].name<<break>><</if>><</for>>.
-					<</if>>
-				<</if>>
-				<span id="manageRecruiter"><strong><<link "Manage Recruiter" "Recruiter Select">><</link>></strong></span> @@.cyan;[U]@@
-				<<set $showOneSlave = "recruit girls">>
-				<<include "Slave Summary">>
-			<<else>>
-				You have @@.red;not@@ selected a Recruiter.
-				<span id="manageRecruiter"><strong><<link "Select one" "Recruiter Select">><</link>></strong></span> @@.cyan;[U]@@
-			<</if>>
-			<<if ($dojo != 0)>>
-				<br>
-				<<if def _BG>>
-					''__@@.pink;<<= SlaveFullName($Bodyguard)>>@@__'' is serving as your bodyguard. <span id="manageBG"><strong><<link "Manage Bodyguard" "BG Select">><</link>></strong></span> @@.cyan;[B]@@
-					<<set $showOneSlave = "guard you">>
-					<<include "Slave Summary">>
-				<<else>>
-					You have @@.red;not@@ selected a Bodyguard. <span id="manageBG"><strong><<link "Select one" "BG Select">><</link>></strong></span> @@.cyan;[B]@@
-				<</if>>
-
-				/* Start Italic event text */
-				<<if (def _BG) && ($slaves[_BG].assignment == "guard you")>>
-					<<setLocalPronouns $slaves[_BG]>>
-					<<set $i = _BG>>
-					<<set _GO = "idiot ball">>
-					<br>
-					//<<= App.Interact.UseGuard($slaves[$i])>>//
-					<br>&nbsp;&nbsp;&nbsp;&nbsp;[["Use "+$his+" mouth"|FLips][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-					| [["Play with "+$his+" tits"|FBoobs][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-					<<if canDoVaginal($slaves[_BG])>>
-						| [["Fuck "+$him|FVagina][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-						<<if canDoAnal($slaves[_BG])>>
-							| [["Use "+$his+" holes"|FButt][$activeSlave = $slaves[_BG],$nextButton = _j, $nextLink = _k, $returnTo = _l]]
-						<</if>>
-						<<if $slaves[_BG].belly >= 300000>>
-							| [["Fuck "+$him+" over "+$his+" belly"|FBellyFuck][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-						<</if>>
-					<</if>>
-					/*check*/
-					<<if canPenetrate($slaves[_BG])>>
-						| [["Ride "+$him|FDick][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-					<</if>>
-					<<if canDoAnal($slaves[_BG])>>
-						| [["Fuck "+$his+" ass"|FAnus][$activeSlave = $slaves[_BG], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-					<</if>>
-					| [["Abuse "+$him|Gameover][$gameover = _GO]]
-				<</if>>
-				/* End Italic event text */
-
-			<</if>>
-		</div>
-	</div>
-
-	<div id="resting" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryRest>>
-				Associated facilities:
-				<<if $spa>>[[Spa]],<<else>>Spa,<</if>>
-				<<if $clinic>>[[Clinic]]<<else>>Clinic<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "resting">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="stay confined" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryConfinement>>
-				Associated facility: <<if $cellblock>>[[Cellblock]]<<else>>Cellblock<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "stay confined">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="take classes" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryAttendingClasses>>
-				Associated facility: <<if $schoolroom>>[[Schoolroom]]<<else>>Schoolroom<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "take classes">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="please you" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryFucktoy>>
-				Associated facility: <<if $masterSuite>>[[Master Suite]]<<else>>Master Suite<</if>> //
-			<</if>>
-			<br>
-			/* Start Italic event text */
-			<<for $i = 0; $i < _SL; $i++>>
-				<<capture $i>>
-				<<setLocalPronouns $slaves[$i]>>
-				<<if ($slaves[$i].assignment == "please you")>>
-					<br>
-					//<<= App.Interact.ToyChest($slaves[$i])>>//
-					//In the coming week you plan to concentrate on
-					<<if $slaves[$i].fuckdoll == 0>>
-						<<if $slaves[$i].toyHole != "all her holes">>
-							$his $slaves[$i].toyHole, but for now://
-						<<else>>
-							all of $his holes equally, but for now://
-						<</if>>
-						<br>&nbsp;&nbsp;&nbsp;&nbsp;[["Use "+$his+" mouth"|FLips][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]] | [["Play with "+$his+" tits"|FBoobs][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-						<<if canDoVaginal($slaves[$i])>>
-							| [["Fuck "+$him|FVagina][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-							<<if canDoAnal($slaves[$i])>>
-								| [["Use "+$his+" holes"|FButt][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-							<</if>>
-						<</if>>
-						<<if canDoAnal($slaves[$i])>>
-							| [["Fuck "+$his+" ass"|FAnus][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-						<</if>>
-						<<if canDoVaginal($slaves[$i]) || canDoAnal($slaves[$i])>>
-							<<if $slaves[$i].belly >= 300000>>
-								| [["Fuck "+$him+" over "+$his+" belly"|FBellyFuck][$activeSlave = $slaves[$i], $nextButton = _j, $nextLink = _k, $returnTo = _l]]
-							<</if>>
-						<</if>>
-						/*check*/
-						<<if canPenetrate($slaves[$i])>>
-							| [["Ride "+$him|FDick][$activeSlave = $slaves[$i],$nextButton = _j,$nextLink = _k,$returnTo = _l]]
-						<</if>>
-						| [["Abuse "+$him|FAbuse][$activeSlave = $slaves[$i],$nextButton = _j,$nextLink = _k,$returnTo = _l]]
-					<<else>>
-						<<if $slaves[$i].toyHole != "all her holes">>
-							$his $slaves[$i].toyHole.
-						<<else>>
-							all of $his holes.
-						<</if>>
-					<</if>>
-				<</if>>
-				<</capture>>
-			<</for>>
-			/* End Italic event text */
-			<br>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "please you">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="whore" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryWhoring>>
-				Associated facility: <<if $brothel>>[[Brothel]]<<else>>Brothel<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "whore">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="serve the public" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryPublicService>>
-				Associated facility: <<if $club>>[[Club]]<<else>>Club<</if>> //
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "serve the public">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="be a servant" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryServitude>>
-				Associated facility: <<if $servantsQuarters>>[[Servants' Quarters]]<<else>>Servant's Quarters<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "be a servant">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="get milked" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryMilking>>
-				Associated facility: <<if $dairy>>[[Dairy]]<<else>>Dairy<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "get milked">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="work as a farmhand" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryFarming>>
-				Associated facility: <<if $farmyard>>[[Farmyard]]<<else>>Farmyard<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "work as a farmhand">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="work a glory hole" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntryGloryHole>>
-				Associated facility: <<if $arcade>>[[Arcade]]<<else>>Arcade<</if>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "work a glory hole">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
-
-	<div id="be a subordinate slave" class="tabcontent">
-		<div class="content">
-			<<if $showTipsFromEncy != 0>>
-				//<<encyclopediaEntrySexualServitude>>//
-			<</if>>
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "be a subordinate slave">>
-			<<include "Slave Summary">>
-		</div>
-	</div>
+<<print App.UI.SlaveList.penthousePage()>>
 
-	<div id="all" class="tabcontent">
-		<div class="content">
-			//<<OptionsSortAsAppearsOnMain>>//
-			<<set $slaveAssignmentTab = "all">>
-			<<include "Slave Summary">>
-		</div>
-		<br>
-		<div class="content">
-			<<if (ndef _HG) && ($slaves.length > 1)>>
-				You have @@.red;not@@ selected a Head Girl<<if $arcologies[0].FSEgyptianRevivalistLaw == 1>> and Consort<</if>>. <span id="manageHG"><strong><<link "Select one" "HG Select">><</link>></strong></span> @@.cyan;[H]@@
-			<<elseif (ndef _HG)>>
-				//You do not have enough slaves to keep a Head Girl//
-			<</if>>
-			<br>
-			<<if ndef _RC>>
-				You have @@.red;not@@ selected a Recruiter.
-				<span id="manageRecruiter"><strong><<link "Select one" "Recruiter Select">><</link>></strong></span> @@.cyan;[U]@@
-			<</if>>
-			<<if ($dojo != 0)>>
-				<br>
-				<<if ndef _BG>>
-					You have @@.red;not@@ selected a Bodyguard. <span id="manageBG"><strong><<link "Select one" "BG Select">><</link>></strong></span> @@.cyan;[B]@@
-				<</if>>
-			<</if>>
-		</div>
-	</div>
-
-	<<if ($tabChoice.Main == "overview")>>
-		<script>document.getElementById("tab overview").click();</script>
-	<<elseif ($tabChoice.Main == "resting")>>
-		<script>document.getElementById("tab resting").click();</script>
-	<<elseif ($tabChoice.Main == "stay confined" && $JobIDArray['stay confined'].length)>>
-		<script>document.getElementById("tab stay confined").click();</script>
-	<<elseif ($tabChoice.Main == "take classes") && $JobIDArray['take classes'].length>>
-		<script>document.getElementById("tab take classes").click();</script>
-	<<elseif ($tabChoice.Main == "please you") && $JobIDArray['please you'].length>>
-		<script>document.getElementById("tab please you").click();</script>
-	<<elseif ($tabChoice.Main == "whore" && $JobIDArray['whore'].length)>>
-		<script>document.getElementById("tab whore").click();</script>
-	<<elseif ($tabChoice.Main == "serve the public") && $JobIDArray['serve the public'].length>>
-		<script>document.getElementById("tab serve the public").click();</script>
-	<<elseif ($tabChoice.Main == "be a servant") && $JobIDArray['be a servant'].length>>
-		<script>document.getElementById("tab be a servant").click();</script>
-	<<elseif ($tabChoice.Main == "get milked") && $JobIDArray['get milked'].length>>
-		<script>document.getElementById("tab get milked").click();</script>
-	<<elseif ($tabChoice.Main == "work a glory hole") && $JobIDArray['work a glory hole'].length>>
-		<script>document.getElementById("tab work a glory hole").click();</script>
-	<<elseif ($tabChoice.Main == "be a subordinate slave") && $JobIDArray['be a subordinate slave'].length>>
-		<script>document.getElementById("tab be a subordinate slave").click();</script>
-	<<elseif ($tabChoice.Main == "all")>>
-		<script>document.getElementById("tab all").click();</script>
-	<<else>>
-		<script>document.getElementById("tab all").click();</script>
-	<</if>>
-
-	</body>
-	<<if $positionMainLinks <= 0>>
-		<br><center>
-		<<= App.UI.View.MainLinks()>>
-		</center>
-	<</if>>
-
-<<else>>  /*Display traditionally, without tabs*/
-
-//<<if $sortSlavesMain != 0>>
-	<br>&nbsp;&nbsp;&nbsp;&nbsp;
-	Sort by:
-	<<if $sortSlavesBy != "devotion">>[[Devotion|Main][$sortSlavesBy = "devotion"]]<<else>>Devotion<</if>> |
-	<<if $sortSlavesBy != "name">>[[Name|Main][$sortSlavesBy = "name"]]<<else>>Name<</if>> |
-	<<if $sortSlavesBy != "assignment">>[[Assignment|Main][$sortSlavesBy = "assignment"]]<<else>>Assignment<</if>> |
-	<<if $sortSlavesBy != "seniority">>[[Seniority purchased|Main][$sortSlavesBy = "seniority"]]<<else>>Seniority<</if>> |
-	<<if $sortSlavesBy != "actualAge">>[[Age|Main][$sortSlavesBy = "actualAge"]]<<else>>Age<</if>> |
-	<<if $sortSlavesBy != "visualAge">>[[Apparent Age|Main][$sortSlavesBy = "visualAge"]]<<else>>Apparent Age<</if>> |
-	<<if $sortSlavesBy != "physicalAge">>[[Bodily Age|Main][$sortSlavesBy = "physicalAge"]]<<else>>Bodily Age<</if>>
-	&nbsp;&nbsp;&nbsp;&nbsp;
-	Sort: <<if $sortSlavesOrder != "descending">>[[Descending|Main][$sortSlavesOrder = "descending"]]<<else>>Descending<</if>> |
-	<<if $sortSlavesOrder != "ascending">>[[Ascending|Main][$sortSlavesOrder = "ascending"]]<<else>>Ascending<</if>>
-<</if>>//
-
-<<if $positionMainLinks >= 0>>
-	<center>
-	<<= App.UI.View.MainLinks()>>
-	</center>
-<</if>>
-
-/* TASK ARRAY */
-<<set $jobTypes = [{title: "Rest", asgn: "rest"}, {title: "Subordinate", asgn: "be a subordinate slave"}, {title: "Whore", asgn: "whore"}, {title: "Public Servant", asgn: "serve the public"}, {title: "Hole", asgn: "work a glory hole"}, {title: "Milking", asgn: "get milked"}, {title: "House Servant", asgn: "be a servant"}, {title: "Fucktoy", asgn: "please you"}, {title: "Confinement", asgn: "stay confined"}, {title: "Classes", asgn: "take classes"}, {title: "Choose own", asgn: "choose her own job"}]>>
-<br>
-<<link Reset>><<resetAssignmentFilter>><<replace '#summarylist'>><<include "Slave Summary">><</replace>><</link>>
-Filter by assignment: |
-<<for _i = 0; _i < $jobTypes.length; _i++>>
-	<<set _title = $jobTypes[_i].title>>
-	<<if $slaves.filter(function(x){return x.assignment == ($jobTypes[_i].asgn)}).length > 0>>
-		<<print "
-			<<link _title>>
-				<<set $slaves.filter(function(x){return x.assignment == ($jobTypes[" + _i + "].asgn)}).map(function(y){y.assignmentVisible = 1})>>
-				<<set $slaves.filter(function(x){return x.assignment != ($jobTypes[" + _i + "].asgn)}).map(function(y){y.assignmentVisible = 0})>>
-				<<replace '#summarylist'>><<include 'Slave Summary'>><</replace>>
-			<</link>>
-		">> |
-	<</if>>
-<</for>>
-
-<span id='summarylist'><<include "Slave Summary">></span>
-
-<<if $lineSeparations == 0>><br><<else>><hr style="margin:0"><</if>>
-<<if $positionMainLinks <= 0>>
-	<br><center>
-	<<= App.UI.View.MainLinks()>>
-	</center>
-<</if>>
+<<if $useSlaveSummaryTabs === 0>>  /*Display traditionally, without tabs*/
 
 <<set _j = "Back", _k = "AS Dump", _l = "Main">>
 <<for $i = 0; $i < _SL; $i++>>
diff --git a/src/uncategorized/masterSuite.tw b/src/uncategorized/masterSuite.tw
index 363deb44f62094f2df64c1d832b8e792f5c78222..45f86f62680dac92e167a0acfe534578826b01b2 100644
--- a/src/uncategorized/masterSuite.tw
+++ b/src/uncategorized/masterSuite.tw
@@ -4,7 +4,6 @@
 
 <<SlaveIDSort $MastSiIDs>>
 <<set _DL = $MastSiIDs.length, $masterSuiteSlaves = _DL>>
-<<suiteAssignmentFilter>>
 
 <<if $masterSuiteName != "the Master Suite">>
 	<<set $masterSuiteNameCaps = $masterSuiteName.replace("the ", "The ")>>
@@ -345,53 +344,6 @@ $masterSuiteNameCaps is furnished
 <</if>>
 
 <br><br>
-<<if $Concubine != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as your Concubine. [[Appoint one|Concubine Select]]
-<</if>>
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $masterSuiteSlaves > 0>>
-			<<suiteAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$masterSuiteNameCaps is empty for the moment//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($masterSuite <= $masterSuiteSlaves)>>
-			''$masterSuiteNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $masterSuiteSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.MasterSuite == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.masterSuite)>>
 
 <br><br>Rename $masterSuiteName: <<textbox "$masterSuiteName" $masterSuiteName "Master Suite">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/matchmaking.tw b/src/uncategorized/matchmaking.tw
index b6fe91ee68b3ee6ecd8285bd63b48d749b237d5e..11d7ff4ebabdeb9fa286cceccca1b43f372d4913 100644
--- a/src/uncategorized/matchmaking.tw
+++ b/src/uncategorized/matchmaking.tw
@@ -381,9 +381,12 @@ Despite $his devotion and trust, $he is still a slave, and probably knows that $
 <<if $seeImages == 1>><br style="clear:both"><</if>>
 
 <br><br>__Put $him with another worshipful <<if $eventSlave.relationship == -2>>emotionally bonded slave<<else>>emotional slut<</if>>:__
-<<set $SlaveSummaryFiler = "occupying">>
-<<include "Slave Summary">>
-
+<<print App.UI.SlaveList.slaveSelectionList(
+	s => s.devotion >= 100 && s.relationship === $activeSlave.relationship && s.ID !== $activeSlave.ID,
+	App.UI.SlaveList.SlaveInteract.stdInteract,
+	null,
+	(s, i) => App.UI.passageLink('Match them', 'Matchmaking', `$subSlave = $slaves[${i}]`)
+)>>
 </span>
 
 <<else>>
diff --git a/src/uncategorized/milkmaidSelect.tw b/src/uncategorized/milkmaidSelect.tw
index aa43ca7b82515e77fa74500f392c6eea77ec9310..f85d344ca00a98fb90cf826a5189400e67043b25 100644
--- a/src/uncategorized/milkmaidSelect.tw
+++ b/src/uncategorized/milkmaidSelect.tw
@@ -1,7 +1,6 @@
 :: Milkmaid Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Dairy", $showEncyclopedia = 1, $encyclopedia = "Milkmaid">>
-<<showallAssignmentFilter>>
 <<if ($Milkmaid != 0)>>
 	<<set $Milkmaid = getSlave($Milkmaid.ID)>>
 	<<setLocalPronouns $Milkmaid>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Milkmaid from your obedient slaves:''
 <br><br>[[None|Milkmaid Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.dairy)>>
diff --git a/src/uncategorized/newGamePlus.tw b/src/uncategorized/newGamePlus.tw
index a4ddbdd8642f80350869c8c727a61841f0db61ae..739c8960d2ba26576c344adb9b70dd2b6d1386ca 100644
--- a/src/uncategorized/newGamePlus.tw
+++ b/src/uncategorized/newGamePlus.tw
@@ -53,47 +53,4 @@ You <<if $cash >= _fee>>have<<else>>lack<</if>> the funds to bring more than $sl
 
 Select up to $slavesToImportMax slaves to be imported into a new game and then click [[here.|init][$saveImported = 1,$oldCareer = "undefined",$slavesToImport = 0]]
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Import a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove from import</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $slavesToImport > 0>>''
-			<<if $slavesToImport === 1>>
-				This slave
-			<<else>>
-				These slaves
-			<</if>>
-			will be imported into the new game'':
-			<<if $slavesToImport >= $slavesToImportMax>>
-				//Current slave import capacity exceded.//
-			<</if>>
-			<<set $SlaveSummaryFiler = "occupying">> <<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if $slavesToImport >= $slavesToImportMax>>
-		<<else>>
-			<<if $slaves.length > $slavesToImport>>
-				''These slaves are available to be imported into the new game:''
-				<<set $SlaveSummaryFiler = "assignable">> <<include "Slave Summary">>
-			<</if>>
-		<</if>>
-	</div>
-</div>
-
-
-<<if ($tabChoice.NewGamePlus == "remove")>>
-	<script>document.getElementById("tab remove").click();</script>
-<<else>>
-	<script>document.getElementById("tab assign").click();</script>
-<</if>>
-
-</body>
\ No newline at end of file
+<<print App.UI.SlaveList.listNGPSlaves()>>
diff --git a/src/uncategorized/nurseSelect.tw b/src/uncategorized/nurseSelect.tw
index 028cd08d534da1043b35aca3a5a702eaa05abed6..20b5a750ecb47d47cf5563cc1ca869084a175c4f 100644
--- a/src/uncategorized/nurseSelect.tw
+++ b/src/uncategorized/nurseSelect.tw
@@ -1,7 +1,6 @@
 :: Nurse Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Clinic", $showEncyclopedia = 1, $encyclopedia = "Nurse">>
-<<showallAssignmentFilter>>
 <<if ($Nurse != 0)>>
 	<<set $Nurse = getSlave($Nurse.ID)>>
 	<<setLocalPronouns $Nurse>>
@@ -13,9 +12,5 @@
 <br><br>''Appoint a Nurse from your devoted slaves:''
 <br><br>[[None|Nurse Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.clinic)>>
diff --git a/src/uncategorized/personalAttentionSelect.tw b/src/uncategorized/personalAttentionSelect.tw
index 2f0d636e14039d596a368aa7a7f6b790e7ec3367..433c9d972d0361d37762fec9ffc51f9b37c2ccd2 100644
--- a/src/uncategorized/personalAttentionSelect.tw
+++ b/src/uncategorized/personalAttentionSelect.tw
@@ -351,6 +351,7 @@
 <</if>> /* CLOSES NO SLAVE SELECTED */
 
 <br><br>__Select a slave to train:__ <<if $PC.slaving >= 100>>//Your @@.springgreen;slaving experience@@ allows you to divide your attention between more than one slave each week, with slightly reduced efficiency//<</if>>
-<<include "Slave Summary">>
-
-<br>
+<<= App.UI.SlaveList.slaveSelectionList(
+		s => s.assignmentVisible === 1 && s.fuckdoll === 0,
+		s => `<<link "${SlaveFullName(s)}">><<run App.UI.selectSlaveForPersonalAttention(${s.ID})>><</link>>`
+	)>>
diff --git a/src/uncategorized/pit.tw b/src/uncategorized/pit.tw
index e8a3332ad6807ea6af78a10f5f55d6b8c9dd15bc..ca708feebf5de7873308896a9ac0f1bb739d617b 100644
--- a/src/uncategorized/pit.tw
+++ b/src/uncategorized/pit.tw
@@ -1,7 +1,6 @@
 :: Pit [nobr]
 
 <<set $nextButton = "Back to Main", $nextLink = "Main", $returnTo = "Pit", $showEncyclopedia = 1, $encyclopedia = "Pit", _DL = $fighterIDs.length, _SL = $slaves.length, _CL = $canines.length, _HL = $hooved.length, _FL = $felines.length>>
-<<showallAssignmentFilter>>
 <<if $pitName != "the Pit">>
 	<<set $pitNameCaps = $pitName.replace("the ", "The ")>>
 <</if>>
@@ -333,39 +332,7 @@ $pitNameCaps is clean and ready,
 <</if>>
 <br><br>
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Select a slave to fight</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Cancel a slave's fight</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if _DL > 0>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-		<<else>>
-			<br><br>//$pitNameCaps is empty for the moment//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if (_SL > _DL)>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Pit == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.listSJFacilitySlaves(App.Entity.facilities.pit, passage(), false,
+{assign: "Select a slave to fight", remove: "Cancel a slave's fight"})>>
 
 <br><br>Rename $pitName: <<textbox "$pitName" $pitName "Pit">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/recruiterSelect.tw b/src/uncategorized/recruiterSelect.tw
index 716748044db1564f13dfb90311d399fd4b78008a..f21248fbc81048d60eeebc97f319a867f1474b6a 100644
--- a/src/uncategorized/recruiterSelect.tw
+++ b/src/uncategorized/recruiterSelect.tw
@@ -1,7 +1,6 @@
 :: Recruiter Select [nobr]
 
 <<set $nextButton = "Back to Main", $nextLink = "Main", $showEncyclopedia = 1, $encyclopedia = "Recruiter">>
-<<showallAssignmentFilter>>
 <<if ($Recruiter != 0)>>
 	<<set $Recruiter = getSlave($Recruiter.ID)>>
 	<<setLocalPronouns $Recruiter>>
@@ -66,9 +65,4 @@
 <br><br>''Appoint a recruiter from among your devoted slaves:''
 <br>[[None|Recruiter Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.penthouse)>>
diff --git a/src/uncategorized/rulesSlaveExclude.tw b/src/uncategorized/rulesSlaveExclude.tw
index 50ff00c308ea639e7445b88fd6a79b8aba140590..11fc9c657d3d3dd6e24fa976fa13e892ba8ed1c2 100644
--- a/src/uncategorized/rulesSlaveExclude.tw
+++ b/src/uncategorized/rulesSlaveExclude.tw
@@ -9,13 +9,20 @@
 <<if ($currentRule.excludedSlaves.length < 1)>>
 	<<set $SlaveSummaryFiler = "assignable">>
 	Select slaves to exclude from Rule $r:
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => !ruleSlaveExcluded(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Exclude Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 <<else>>
 	Slaves currently excluded from Rule $r: [[Clear list|Rules Slave Exclude][$currentRule.excludedSlaves = []]]
-	<<set $SlaveSummaryFiler = "occupying">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => ruleSlaveExcluded(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave NoExclude Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 	<br><br>
 	Select more slaves to exclude from Rule $r:
-	<<set $SlaveSummaryFiler = "assignable">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => !ruleSlaveExcluded(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Exclude Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 <</if>>
diff --git a/src/uncategorized/rulesSlaveSelect.tw b/src/uncategorized/rulesSlaveSelect.tw
index ded8c3ef46ca23f4ef1eb37fbfdd57d2955c2c5a..abda187c938d3914eb83c4c2999e9c17fa213fdb 100644
--- a/src/uncategorized/rulesSlaveSelect.tw
+++ b/src/uncategorized/rulesSlaveSelect.tw
@@ -9,13 +9,21 @@
 <<if ($currentRule.selectedSlaves.length < 1)>>
 	<<set $SlaveSummaryFiler = "assignable">>
 	Choose specific slaves to limit Rule $r:
-	<<include "Slave Summary">>
+	Select slaves to exclude from Rule $r:
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => !ruleSlaveSelected(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Select Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 <<else>>
 	Rule $r currently limited to specific slaves: [[Clear list|Rules Slave Select][$currentRule.selectedSlaves = []]]
-	<<set $SlaveSummaryFiler = "occupying">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => ruleSlaveSelected(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Deselect Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 	<br><br>
 	Choose more specific slaves:
-	<<set $SlaveSummaryFiler = "assignable">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.slaveSelectionList(
+		s => !ruleSlaveSelected(s, $currentRule),
+		(s, i) => `<u><strong>${App.UI.passageLink(SlaveFullName(s), 'Rules Slave Select Workaround', `$activeSlave = $slaves[${i}]`)}</strong></u>`
+	)>>
 <</if>>
diff --git a/src/uncategorized/schoolroom.tw b/src/uncategorized/schoolroom.tw
index a1b75e32d5ed0ee10b30adf3535d429530eaa6a7..4fe30644ec7f84aa92e82efccc67d3258c016bdd 100644
--- a/src/uncategorized/schoolroom.tw
+++ b/src/uncategorized/schoolroom.tw
@@ -5,7 +5,6 @@
 <<if $schoolroomName != "the Schoolroom">>
 	<<set $schoolroomNameCaps = $schoolroomName.replace("the ", "The ")>>
 <</if>>
-<<schoolAssignmentFilter>>
 $schoolroomNameCaps is well-equipped, with wallscreens to display lessons. These are currently
 <<switch $schoolroomDecoration>>
 <<case "Roman Revivalist">>
@@ -116,67 +115,6 @@ $schoolroomNameCaps is well-equipped, with wallscreens to display lessons. These
 <</if>>
 
 <br><br>
-<<if $Schoolteacher != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a Schoolteacher. [[Appoint one|Schoolteacher Select]]
-<</if>>
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'transfer')" id="tab transfer">Transfer from Facility</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $schoolroomSlaves > 0>>
-			<<schoolAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$schoolroomNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($schoolroom <= $schoolroomSlaves)>>
-			''$schoolroomNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $schoolroomSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<div id="transfer" class="tabcontent">
-	<div class="content">
-		<<if ($schoolroom <= $schoolroomSlaves)>>
-			''$schoolroomNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $schoolroomSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "transferable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Schoolroom == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<elseif ($tabChoice.Schoolroom == "remove")>>
-	<script>document.getElementById("tab remove").click();</script>
-<<elseif ($tabChoice.Schoolroom == "transfer")>>
-	<script>document.getElementById("tab transfer").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.schoolroom, true)>>
 
 <br><br>Rename $schoolroomName: <<textbox "$schoolroomName" $schoolroomName "Schoolroom">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/schoolteacherSelect.tw b/src/uncategorized/schoolteacherSelect.tw
index 549b492526feac4be2785a5c955f1f4c1cd93c52..edc0e2505573454e1b522bc90a1eb1b8b404ddb6 100644
--- a/src/uncategorized/schoolteacherSelect.tw
+++ b/src/uncategorized/schoolteacherSelect.tw
@@ -1,7 +1,6 @@
 :: Schoolteacher Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Schoolroom", $showEncyclopedia = 1, $encyclopedia = "Schoolteacher">>
-<<showallAssignmentFilter>>
 <<if ($Schoolteacher != 0)>>
 	<<set $Schoolteacher = getSlave($Schoolteacher.ID)>>
 	<<setLocalPronouns $Schoolteacher>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Schoolteacher from your devoted slaves:''
 <br><br>[[None|Schoolteacher Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.schoolroom)>>
diff --git a/src/uncategorized/servantsQuarters.tw b/src/uncategorized/servantsQuarters.tw
index ae1fbcc51cb4d0f161ef216133d6275a8d734b43..000cd2699d3d06a5e9babb9b69db9da8283b7744 100644
--- a/src/uncategorized/servantsQuarters.tw
+++ b/src/uncategorized/servantsQuarters.tw
@@ -5,7 +5,6 @@
 <<if $servantsQuartersName != "the Servants' Quarters">>
 	<<set $servantsQuartersNameCaps = $servantsQuartersName.replace("the ", "The ")>>
 <</if>>
-<<quartersAssignmentFilter>>
 $servantsQuartersNameCaps
 <<switch $servantsQuartersDecoration>>
 <<case "Roman Revivalist">>
@@ -103,10 +102,10 @@ $servantsQuartersNameCaps
 <</if>>
 
 <br><br>
+<<set _facility = App.Entity.facilities.servantsQuarters>>
 <<if $Stewardess != 0>>
 	<<setLocalPronouns $Stewardess>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
+	<<print App.UI.SlaveList.displayManager(_facility)>>
 	<<if canAchieveErection($Stewardess) && $Stewardess.pubertyXY == 1>>
 		<br>&nbsp;&nbsp;&nbsp;&nbsp;
 		<<if $stewardessImpregnates == 1>>
@@ -121,44 +120,6 @@ $servantsQuartersNameCaps
 
 <br><br>
 
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $servantsQuartersSlaves > 0>>
-			<<quartersAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$servantsQuartersNameCaps is empty for the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($servantsQuarters <= $servantsQuartersSlaves)>>
-			''$servantsQuartersNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $servantsQuartersSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.ServantsQuarters == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<else>>
-	<script>document.getElementById("tab remove").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.listSJFacilitySlaves(_facility, passage())>>
 
 <br><br>Rename $servantsQuartersName: <<textbox "$servantsQuartersName" $servantsQuartersName "Servants' Quarters">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/slaveSummary.tw b/src/uncategorized/slaveSummary.tw
deleted file mode 100644
index 8a44cf7adebb039456ac43659b3fde964399ee12..0000000000000000000000000000000000000000
--- a/src/uncategorized/slaveSummary.tw
+++ /dev/null
@@ -1,13 +0,0 @@
-:: Slave Summary [nobr]
-
-<<print App.UI.slaveSummaryList(passage())>>
-
-<<run $(document).one(':passagedisplay', function() {
-	$("[data-quick-index]").click(function() {
-		let which = this.attributes["data-quick-index"].value;
-		let quick = $("div#list_index" + which);
-		quick.toggleClass("hidden");
-	});
-	quickListBuildLinks();
-});>>
-<<set _Slave = 0>>
diff --git a/src/uncategorized/spa.tw b/src/uncategorized/spa.tw
index 1c7e28ba55915ba469c9194c1af4687cdfb4e805..2a1ab9bce4b2e2e9f522bc7ae701795d97824759 100644
--- a/src/uncategorized/spa.tw
+++ b/src/uncategorized/spa.tw
@@ -5,7 +5,6 @@
 <<if $spaName != "the Spa">>
 	<<set $spaNameCaps = $spaName.replace("the ", "The ")>>
 <</if>>
-<<spaAssignmentFilter>>
 $spaNameCaps
 <<switch $spaDecoration>>
 <<case "Roman Revivalist">>
@@ -118,69 +117,6 @@ $spaNameCaps
 <</if>>
 
 <br><br>
-<<if $Attendant != 0>>
-	<<set $SlaveSummaryFiler = "leading">>
-	<<include "Slave Summary">>
-<<else>>
-	You do not have a slave serving as a spa Attendant. [[Appoint one|Attendant Select]]
-<</if>>
-
-
-<br><br>
-
-<body>
-
-<div class="tab">
-	<button class="tablinks" onclick="opentab(event, 'assign')" id="tab assign">Assign a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'remove')" id="tab remove">Remove a slave</button>
-	<button class="tablinks" onclick="opentab(event, 'transfer')" id="tab transfer">Transfer from Facility</button>
-</div>
-
-<div id="remove" class="tabcontent">
-	<div class="content">
-		<<if $spaSlaves > 0>>
-			<<spaAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "occupying">>
-			<<include "Slave Summary">>
-			<<resetAssignmentFilter>>
-		<<else>>
-			<br><br>//$spaNameCaps is empty at the moment.<br>//
-		<</if>>
-	</div>
-</div>
-
-<div id="assign" class="tabcontent">
-	<div class="content">
-		<<if ($spa <= $spaSlaves)>>
-			''$spaNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $spaSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "assignable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<div id="transfer" class="tabcontent">
-	<div class="content">
-		<<if ($spa <= $spaSlaves)>>
-			''$spaNameCaps is full and cannot hold any more slaves''
-		<<elseif ($slaves.length > $spaSlaves)>>
-			<<resetAssignmentFilter>>
-			<<set $SlaveSummaryFiler = "transferable">>
-			<<include "Slave Summary">>
-		<</if>>
-	</div>
-</div>
-
-<<if ($tabChoice.Spa == "assign")>>
-	<script>document.getElementById("tab assign").click();</script>
-<<elseif ($tabChoice.Spa == "remove")>>
-	<script>document.getElementById("tab remove").click();</script>
-<<elseif ($tabChoice.Spa == "transfer")>>
-	<script>document.getElementById("tab transfer").click();</script>
-<</if>>
-
-</body>
+<<print App.UI.SlaveList.stdFacilityPage(App.Entity.facilities.spa, true)>>
 
 <br><br>Rename $spaName: <<textbox "$spaName" $spaName "Spa">> //Use a noun or similar short phrase//
diff --git a/src/uncategorized/stewardessSelect.tw b/src/uncategorized/stewardessSelect.tw
index 94344364a47b279595d0c714ef258ef7ca19100e..9a300a7a9f0b7b1361bc385bfc359cbb55071fe0 100644
--- a/src/uncategorized/stewardessSelect.tw
+++ b/src/uncategorized/stewardessSelect.tw
@@ -1,7 +1,6 @@
 :: Stewardess Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Servants' Quarters", $showEncyclopedia = 1, $encyclopedia = "Stewardess">>
-<<showallAssignmentFilter>>
 <<if ($Stewardess != 0)>>
 	<<set $Stewardess = getSlave($Stewardess.ID)>>
 	<<setLocalPronouns $Stewardess>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Stewardess from your devoted slaves:''
 <br><br>[[None|Stewardess Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.servantsQuarters)>>
diff --git a/src/uncategorized/storyCaption.tw b/src/uncategorized/storyCaption.tw
index 7b8a8d46359146c9570f614f9d76b031ab3d98d4..8d32d58f048ac6cb7b324b7525e02628b7ab47b1 100644
--- a/src/uncategorized/storyCaption.tw
+++ b/src/uncategorized/storyCaption.tw
@@ -55,9 +55,7 @@
 	<</if>>
 	<br><br>
 	<<if $nextButton == "END WEEK">>
-		<span id="endWeekButton"><strong><<link [[($nextButton)|($nextLink)]]>>
-		<<resetAssignmentFilter>> /* very important! */
-		<</link>></strong></span> @@.cyan;[Ent]@@
+		<span id="endWeekButton"><strong><<link [[($nextButton)|($nextLink)]]>><</link>></strong></span> @@.cyan;[Ent]@@
 		<<if $rulesError && $rulesAssistantAuto == 1>><br>@@.yellow; WARNING: some custom rules will change slave variables@@<</if>>
 	<<elseif $nextButton !== " ">>
 		<span id="nextButton"> /* target for miscWidgets' <<UpdateNextButton>> */
diff --git a/src/uncategorized/subordinateTargeting.tw b/src/uncategorized/subordinateTargeting.tw
index da5bd036ea75acbff64edf31b836e8faab0c4af6..a742da8af47876f40994340b5ebf7799eda33e34 100644
--- a/src/uncategorized/subordinateTargeting.tw
+++ b/src/uncategorized/subordinateTargeting.tw
@@ -18,7 +18,11 @@
 <</if>>
 
 <br><br>__Select a slave for $him to submit to, sexually:__
-<<include "Slave Summary">>
+<<= App.UI.SlaveList.slaveSelectionList(
+		s => s.devotion >= -20 && s.fuckdoll === 0 && State.variables.activeSlave.ID !== s.ID &&
+			(State.variables.activeSlave.amp !== 1 || s.amp !== 1),
+		(s, i) => App.UI.passageLink(SlaveFullName(s), 'Subordinate Targeting', `$activeSlave.subTarget = ${s.ID}`),
+	)>>
 
 <br><br>[[None|Subordinate Targeting][$activeSlave.subTarget = 0]]
 
diff --git a/src/uncategorized/wardenessSelect.tw b/src/uncategorized/wardenessSelect.tw
index 216a8802525e08fd840ec6b81458f83b4eb3b78c..c356d1dc21bcd86df31224541616ad6bc57a0a7c 100644
--- a/src/uncategorized/wardenessSelect.tw
+++ b/src/uncategorized/wardenessSelect.tw
@@ -1,7 +1,6 @@
 :: Wardeness Select [nobr]
 
 <<set $nextButton = "Back", $nextLink = "Cellblock", $showEncyclopedia = 1, $encyclopedia = "Wardeness">>
-<<showallAssignmentFilter>>
 <<if ($Wardeness != 0)>>
 	<<set $Wardeness = getSlave($Wardeness.ID)>>
 	<<setLocalPronouns $Wardeness>>
@@ -13,9 +12,4 @@
 <br><br>''Appoint a Wardeness from your devoted slaves:''
 <br><br>[[None|Wardeness Workaround][$i = -1]]
 <br><br>
-<<assignmentFilter>>
-<span id="ComingGoing">
-	<<showallAssignmentFilter>>
-	<<include "Slave Summary">>
-	<<resetAssignmentFilter>>
-</span>
\ No newline at end of file
+<<print App.UI.SlaveList.facilityManagerSelection(App.Entity.facilities.cellblock)>>