diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27023a351e139c670e863c4c01a4aa705bc8d724..1ca348de1b89ac3732475603fa38bcda14fc1a85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 
 ## Unreleased
 
+## 0.10.7.1-4.0.0-alpha.21 - 2022-10-10
+
+* fixed major issue
+
+## 0.10.7.1-4.0.0-alpha.20 - 2022-10-10
+
+* added player mobility
+* added porn studio for better porn control
+* added new slimness enthusiast food policy
+* overhauled the neighbor FS selection process
+* locate slave improvements
+* removed dTree in favor of lodash and d3
+* fixes
+
 ## 0.10.7.1-4.0.0-alpha.19 - 2022-08-27
+
 * fixes and code improvements
 
 ## 0.10.7.1-4.0.0-alpha.18 - 2022-08-26
diff --git a/FCHost/fchost/fchost_handler_linux.cc b/FCHost/fchost/fchost_handler_linux.cc
index f960f287892e3759892627a28edfd9076d77931f..d78e9f63c1c85af0a4f46e901d59204d1f4b7ebf 100644
--- a/FCHost/fchost/fchost_handler_linux.cc
+++ b/FCHost/fchost/fchost_handler_linux.cc
@@ -70,7 +70,7 @@ namespace {
 
 		switch (mode) {
 			case CefDialogHandler::FileDialogMode::FILE_DIALOG_OPEN_MULTIPLE:
-				cmdLine << " --multiple"; [[fallthrough]]
+				cmdLine << " --multiple"; [[fallthrough]];
 			case CefDialogHandler::FileDialogMode::FILE_DIALOG_OPEN:
 				cmdLine << " --getopenfilename";
 				break;
@@ -171,7 +171,8 @@ namespace {
 		// we will try to launch kdialog or zenity
 		std::string dialogExecutable;
 		// try to determine which environment we run inside
-		std::string desktop = getenv("XDG_CURRENT_DESKTOP");
+		const char* desktop_env = getenv("XDG_CURRENT_DESKTOP");
+		std::string desktop = desktop_env == nullptr ? "" : desktop_env;
 
 		const auto checkExeExists = [](const char* name) {
 			int ec = ::system((std::string(name) + " --help > /dev/null").c_str());
diff --git a/css/facilities/studio.css b/css/facilities/studio.css
new file mode 100644
index 0000000000000000000000000000000000000000..57c8e3aed053d70f4f33b4d430ffa2c560a7faa7
--- /dev/null
+++ b/css/facilities/studio.css
@@ -0,0 +1,29 @@
+/* these colors have to be accessed directly for graph colors */
+:root {
+	--genre-color-paraphilia: yellow;
+	--genre-color-fetish: lightcoral;
+	--genre-color-generic: gray;
+	--genre-color-quirk: lawngreen;
+	--genre-color-general: white;
+}
+
+/* and they have to be accessed through classes for text */
+.genre.paraphilia {
+	color: var(--genre-color-paraphilia);
+}
+
+.genre.fetish {
+	color: var(--genre-color-fetish);
+}
+
+.genre.generic {
+	color: var(--genre-color-generic);
+}
+
+.genre.quirk {
+	color: var(--genre-color-quirk);
+}
+
+.genre.general {
+	color: var(--genre-color-general);
+}
diff --git a/css/futureSocieties/fsPassage.css b/css/futureSocieties/fsPassage.css
new file mode 100644
index 0000000000000000000000000000000000000000..6c61e92f93fa9d49e9469076acd6114a9eedec96
--- /dev/null
+++ b/css/futureSocieties/fsPassage.css
@@ -0,0 +1,26 @@
+.fs-recommend {
+	border: 1px solid;
+	padding: 2px;
+	border-radius: 3px;
+	font-size: smaller;
+}
+
+.fs-recommend-great {
+	border-color: green;
+	color: green;
+}
+
+.fs-recommend-good {
+	border-color: greenyellow;
+	color: greenyellow;
+}
+
+.fs-recommend-neutral {
+	border-color: gold;
+	color: gold;
+}
+
+.fs-recommend-bad {
+	border-color: red;
+	color: red;
+}
\ No newline at end of file
diff --git a/css/general/textColors.css b/css/general/textColors.css
index 7cd98be1785c161dd64e47bcac96c257916b80c8..03fec45d8fef64e8c1b1632aa2a2e2d424b68ec6 100644
--- a/css/general/textColors.css
+++ b/css/general/textColors.css
@@ -131,11 +131,11 @@
 
 /* generally between red and green, and a lot of other places */
 .orange, .orange a, .stupid, .stupid a, .change.negative, .change.negative a, .defiant.careful, .defiant.careful a,
-.ncs, .ncs a, .miscarriage, .miscarriage a, .intro.question {
+.ncs, .ncs a, .miscarriage, .miscarriage a, .hindrance.mid, .intro.question {
 	color: orange
 }
 
-.orangered, .orangered a, .defiant.inc, .defiant.inc a, .defiant.bold, .defiant.bold a, .education.neg a, .unintelligent {
+.orangered, .orangered a, .defiant.inc, .defiant.inc a, .defiant.bold, .defiant.bold a, .education.neg a, .unintelligent, .hindrance.high {
 	color: orangered
 }
 
@@ -147,7 +147,7 @@
 /* generally bad stuff */
 /* note: .error is for unexpected behavior, .warning for player feedback */
 .red, .red a, .health.dec, .health.dec a, .cash.dec, .cash.dec a, .food.dec, .food.dec a, .stat.drop, .stat.drop a, .flaw, .flaw a, .flaw.gain, .flaw.gain a,
-.mindbreak, .mindbreak a, .error, .error a, .elites.loss, .elites.loss a, .reputation.dec, .reputation.dec a,
+.mindbreak, .mindbreak a, .error, .error a, .elites.loss, .elites.loss a, .reputation.dec, .reputation.dec a, .immobile, .hindrance.max,
 .warning, .warning a, .prosperity.dec {
 	color: red
 }
@@ -177,7 +177,7 @@
 	color: teal
 }
 
-.yellow, .yellow a, .noteworthy, .noteworthy a, .paraphilia.gain, .paraphilia.gain a,
+.yellow, .yellow a, .noteworthy, .noteworthy a, .paraphilia.gain, .paraphilia.gain a, .hindrance.low,
 .devotion.ambivalent, .devotion.ambivalent a, .trust.fearful, .trust.fearful a, .job.change {
 	color: yellow
 }
diff --git a/css/gui/slaveList/cardStyle.css b/css/gui/slaveList/cardStyle.css
index f560bfb0c5a6dff5e87726ca532b2e13be610abb..e40715994d1ae142f24da540a033169d474c15da 100644
--- a/css/gui/slaveList/cardStyle.css
+++ b/css/gui/slaveList/cardStyle.css
@@ -1,8 +1,6 @@
 .card {
 	border: 2px solid #333333;
 	background-color: #1a1a1a;
-	box-shadow: 10px 10px 10px black,
-		-10px 10px 10px black;
 	padding: 1em;
 	margin-bottom: 1em;
 }
diff --git a/css/gui/tooltips/tippy.css b/css/gui/tooltips/tippy.css
index ab4273b3700380a1de20978f2830d372b0b6b375..020f60d5d539062a097b435a48003672c64127a4 100644
--- a/css/gui/tooltips/tippy.css
+++ b/css/gui/tooltips/tippy.css
@@ -4,6 +4,7 @@
 
 .tippy-content {
 	text-indent: initial;
+	font-weight: initial;
 }
 
 .tippy-content ul {
diff --git a/css/interaction/export.css b/css/interaction/export.css
index d54575954576d2049ff25d425cc8a7b9d21871b9..5fe2a1109fa2dd87edbeec36d69cdcd77bc9e4ca 100644
--- a/css/interaction/export.css
+++ b/css/interaction/export.css
@@ -1,6 +1,7 @@
-div.output {
+.export-field {
 	width: 100vw;
 	max-width: 100%;
 	word-break: break-all;
 	white-space: normal;
+	height: 80vh;
 }
diff --git a/css/interaction/slaveInteract.css b/css/interaction/slaveInteract.css
index 403f30d2892fa168071b423359ded448114626f9..30f21dd02d1d07b842e419a8cc42fd0225c9dc25 100644
--- a/css/interaction/slaveInteract.css
+++ b/css/interaction/slaveInteract.css
@@ -10,6 +10,24 @@
 	font-size: 1.5em;
 }
 
+.si-slave-title {
+	color: coral;
+	font-weight: bold;
+}
+
+.si-relationship {
+	color: lightgreen;
+	font-weight: bold;
+}
+
+.si-family {
+	color: lightgreen;
+}
+
+.si-rival {
+	color: salmon;
+}
+
 /* notification */
 a.with-note::after /*notification for links with notes in tooltips */
 {
diff --git a/devNotes/encyclopedia.js b/devNotes/encyclopedia.js
index 76fc5ad4c826635f0805a007b2e61bf6ede3d161..06b7902a75d6bde0554fdfb20a320f141d2374e4 100644
--- a/devNotes/encyclopedia.js
+++ b/devNotes/encyclopedia.js
@@ -282,139 +282,6 @@ App.Encyclopedia.UI = function() {
 				r.push(link("sexually self neglectful", "Self Neglect"));
 				r.addToLast(".");
 				break;
-			// SLAVE BEHAVIORAL FLAWS
-			case "Flaws":
-				r.push(highlight("Unflinching"), "are negative slave qualities.");
-				r.push("They decrease slaves' value and performance at sexual assignments, and each flaw also has other, differing effects. Each flaw is associated with a corresponding");
-				r.push(link("quirk", "Quirks"), ", and slave can have two flaws (a sexual flaw and a behavioral flaw), just like quirks. New slaves will often have flaws, and tough experiences can also cause them to appear.");
-				r.toParagraph();
-
-				r.push("Flaws can softened or removed either by orders given to the", link("Head Girl"), "or via personal attention provided by the player character.");
-				r.push("Flaws can also be naturally softened or removed by fetishes, and can resolve on their own if a slave is happy.");
-				r.toNode("div");
-				break;
-			case "Anorexic":
-				r.push(highlight("Anorexic"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("insecure"), link("quirk.", "Quirks"));
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, anorexia can cause unexpected weight loss. Anorexics will enjoy dieting but dislike gaining weight, and may bilk attempts to make them fatten up.");
-				r.toNode("div");
-				break;
-			case "Arrogant":
-				r.push(highlight("Arrogant"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("confident"), link("quirk.", "Quirks"));
-				r.push("The", link("submissive", "Submissives"), "fetish fetish can do this naturally.");
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", devotion(), "gains are limited.");
-				r.toNode("div");
-				break;
-			case "Bitchy":
-				r.push(highlight("Bitchy"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("cutting"), link("quirk.", "Quirks"));
-				r.push("The", link("humiliation", "Humiliation Fetishists"), "fetish fetish can do this naturally.");
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", devotion(), "gains are limited.");
-				r.toNode("div");
-				break;
-			case "Devout":
-				r.push(highlight("Devout"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("sinful"), link("quirk.", "Quirks"));
-				r.push("A very powerful sex drive can do this naturally.");
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", devotion(), "gains are limited.");
-				r.toNode("div");
-				break;
-			case "Gluttonous":
-				r.push(highlight("Gluttonous"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("fitness"), link("quirk.", "Quirks"));
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, gluttons will enjoy gaining weight but dislike dieting, and may bilk attempts to make them lose weight.");
-				r.toNode("div");
-				break;
-			case "Hates Men":
-				r.push(highlight("Hates men"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("adores women"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("boob fetish.", "Boob Fetishists"));
-				r.push("Strong attraction to men or the", link("pregnancy fetish", "Pregnancy Fetishists"), "will soften it so she", link("adores men"), "instead.");
-				r.push("This flaw can also be removed by serving a player character or another slave with a dick.");
-				r.toNode("div");
-				break;
-			case "Hates Women":
-				r.push(highlight("Hates women"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("adores men"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("cumslut", "Cumsluts"), "fetish.");
-				r.push("Strong attraction to women or the", link("pregnancy fetish", "Pregnancy Fetishists"), "will soften it so she", link("Adores women"), "instead.");
-				r.push("This flaw can also be removed by serving a player character or another slave with a vagina.");
-				r.toNode("div");
-				break;
-			case "Liberated":
-				r.push(highlight("Liberated"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("advocate"), link("quirk.", "Quirks"));
-				r.push("The", link("submissive", "Submissives"), "fetish can do this naturally.");
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", devotion(), "gains are limited.");
-				r.toNode("div");
-				break;
-			case "Odd":
-				r.push(highlight("Odd"), "is a behavioral", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("funny"), link("quirk.", "Quirks"));
-				r.push("The", link("humiliation", "Humiliation Fetishists"), "fetish can do this naturally.");
-				r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", devotion(), "gains are limited.");
-				r.toParagraph();
-				break;
-			// SLAVE SEXUAL FLAWS
-			case "Apathetic":
-				r.push(highlight("Apathetic"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("caring"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("submissive", "Humiliation Submissive"), "fetish.");
-				r.push("It can also be removed by the", link("dom", "Doms"), "fetish.");
-				r.toParagraph();
-				break;
-			case "Crude":
-				r.push(highlight("Crude"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("unflinching"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("cumslut", "Cumsluts"), "fetish.");
-				r.toParagraph();
-				break;
-			case "Hates Anal":
-				r.push(highlight("Hates anal"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("painal queen"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("buttslut", "Buttsluts"), "fetish.");
-				r.push("This flaw can also be removed by serving the player character.");
-				r.toParagraph();
-				break;
-			case "Hates Oral":
-				r.push(highlight("Hates oral"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("gagfuck queen"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("cumslut", "Cumsluts"), "fetish.");
-				r.push("This flaw can also be removed by serving the player character.");
-				r.toParagraph();
-				break;
-			case "Hates Penetration":
-				r.push(highlight("Hates penetration"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("strugglefuck queen"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("buttslut", "Buttsluts"), "fetish.");
-				r.push("This flaw can also be removed by serving the player character.");
-				r.toParagraph();
-				break;
-			case "Idealistic":
-				r.push(highlight("Idealistic"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("romantic"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("submissive", "Humiliation Submissive"), "fetish.");
-				r.toParagraph();
-				break;
-			case "Judgemental":
-				r.push(highlight("Judgemental"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("size queen", "Size Queen"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("submissive", "Humiliation Submissive"), "fetish.");
-				r.toParagraph();
-				break;
-			case "Repressed":
-				r.push(highlight("Repressed"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("perverted"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("cumslut", "Cumsluts"), "fetish, or the", link("buttslut", "Buttsluts"), "fetish.");
-				r.toParagraph();
-				break;
-			case "Shamefast":
-				r.push(highlight("Shamefast"), "is a sexual", link("flaw", "Flaws"), "that can be softened into the");
-				r.push(link("tease"), link("quirk", "Quirks"), "by training,");
-				r.push("a good", link("Attendant"), ", a powerful sex drive, or the", link("submissive", "Humiliation Submissive"), "fetish.");
-				r.toParagraph();
-				break;
 			// SLAVE PARAPHILIAS
 			case "Paraphilias":
 				r.push(highlight("Paraphilias"), "are intense forms of sexual", link("flaws"), "that cannot be softened.");
diff --git a/devTools/types/FC/arcology.d.ts b/devTools/types/FC/arcology.d.ts
index 1ce42f9e1bcb2f12221724e0d757f8c403097b99..f116eae9487c80d83061d6bda0d6ed47a5c16c1a 100644
--- a/devTools/types/FC/arcology.d.ts
+++ b/devTools/types/FC/arcology.d.ts
@@ -50,7 +50,7 @@ declare namespace FC {
 		};
 		FSSlimnessEnthusiast: {
 			noun: "Slimness Enthusiasm", adj: "Slimness Enthusiast", deco: "Slimness Enthusiast",
-			research: true, SMR: true, policy: "Law", choice: undefined
+			research: true, SMR: true, policy: "Law" | "FoodLaw", choice: undefined
 		};
 		FSAssetExpansionist: {
 			noun: "Asset Expansionism", adj: "Asset Expansionist", deco: "Asset Expansionist",
diff --git a/devTools/types/FC/desc.d.ts b/devTools/types/FC/desc.d.ts
index 913ff2eaff7dbd03d921fba98109432dbfe290c0..92de5e62b2c4435f889be53556860ece8168ee33 100644
--- a/devTools/types/FC/desc.d.ts
+++ b/devTools/types/FC/desc.d.ts
@@ -5,6 +5,8 @@ declare namespace FC {
 			market?: Zeroable<SlaveMarketName | SpecialMarketName | "starting">;
 			marketText?: string; /* extra text to be appended to the first line of the description, dependent on the original market */
 			noArt?: boolean;
+			/** Allow linking to other passages, for example to other slaves */
+			links?:boolean;
 		}
 	}
 }
diff --git a/devTools/types/FC/gameState.d.ts b/devTools/types/FC/gameState.d.ts
index 7226eeb1442ceba8177858fd7c32d68225308b7f..53338f89c27c7ec8801427a3840c66c5e78fc29c 100644
--- a/devTools/types/FC/gameState.d.ts
+++ b/devTools/types/FC/gameState.d.ts
@@ -18,7 +18,7 @@ declare namespace FC {
 		- 1: Not established
 		- 2: Established
 		- 3: Captured
-		- 4: Killed
+		- 4: Killed / Accepted offer
 		- 5: Enslaved
 		 */
 		state: number;
diff --git a/devTools/types/extensions.d.ts b/devTools/types/extensions.d.ts
index 07c495c194f1cb1f82c91c0135b92ea8b7d30e03..dc832d2fe297695691cf4463eae41518226d85e2 100644
--- a/devTools/types/extensions.d.ts
+++ b/devTools/types/extensions.d.ts
@@ -19,107 +19,3 @@ interface ObjectConstructor {
 	keys<K extends PropertyKey, V>(o: Partial<Record<K, V>>): EnumerablePropertyKey<K>[];
 	entries<K extends PropertyKey, V>(o: Partial<Record<K, V>>): [EnumerablePropertyKey<K>, V][];
 }
-
-// d3-dtree
-
-declare namespace d3dTree {
-	interface Person {
-		name: string;
-	}
-	interface Marriage {
-		spouse: Person;
-		/**
-		 * List of children nodes
-		 */
-		children: Person[];
-	}
-
-	interface DataItem {
-		/**
-		 * The name of the node
-		 */
-		name: string;
-		/**
-		 * The CSS class of the node
-		 */
-		class: string;
-		/**
-		 * The CSS class of the text in the node
-		 */
-		textClass: string;
-		/**
-		 * Generational height offset
-		 */
-		depthOffset?: number;
-		/** Marriages is a list of nodes
-		 * Each marriage has one spouse
-		 */
-		marriages: Marriage[];
-		/**
-		 * Custom data passed to renderers
-		 */
-		extra?: object;
-	}
-
-	interface Options {
-		target: string;
-		debug: boolean;
-		width: number;
-		height: number;
-		hideMarriageNodes: boolean;
-		marriageNodeSize: number;
-		/**
-		 * Callbacks should only be overwritten on a need to basis.
-		 * See the section about callbacks below.
-		 */
-		callbacks: {
-		},
-		margin: {
-			top: number;
-			right: number;
-			bottom: number;
-			left: number;
-		},
-		nodeWidth: number;
-		styles: {
-			node: string;
-			linage: string;
-			marriage: string;
-			text: string;
-		}
-	}
-
-	interface Tree {
-		/**
-		 * Reset zoom and position to initial state
-		 * @param duration Default is 500
-		 */
-		resetZoom(duration?: number): void;
-		/**
-		 * Zoom to a specific position
-		 * @param x
-		 * @param y
-		 * @param zoom = 1
-		 * @param duration = 500
-		 */
-		zoomTo(x: number, y: number, zoom?: number, duration?: number): void;
-		/**
-		 * Zoom to a specific node
-		 * @param nodeId
-		 * @param zoom = 2
-		 * @param duration = 500
-		 */
-		zoomToNode(nodeId: string, zoom?: number, duration?: number): void;
-		/**
-		 * Zoom to fit the entire tree into the viewport
-		 * @param duration = 500
-		 */
-		zoomToFit(duration?: number): void;
-	}
-
-	interface dTree {
-		init(data: DataItem[], options: Partial<Options>): Tree;
-	}
-}
-
-declare const dTree: d3dTree.dTree;
diff --git a/js/001-lib/d3.min.js b/js/001-lib/d3.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b05c90b864985684059d9b2811a91b8035ec96c
--- /dev/null
+++ b/js/001-lib/d3.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org v7.6.1 Copyright 2010-2022 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return null==t||null==n?NaN:t<n?-1:t>n?1:t>=n?0:NaN}function e(t,n){return null==t||null==n?NaN:n<t?-1:n>t?1:n>=t?0:NaN}function r(t){let r,o,a;function u(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<0?e=r+1:i=r}while(e<i)}return e}return 2!==t.length?(r=n,o=(e,r)=>n(t(e),r),a=(n,e)=>t(n)-e):(r=t===n||t===e?t:i,o=t,a=t),{left:u,center:function(t,n,e=0,r=t.length){const i=u(t,n,e,r-1);return i>e&&a(t[i-1],n)>-a(t[i],n)?i-1:i},right:function(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<=0?e=r+1:i=r}while(e<i)}return e}}}function i(){return 0}function o(t){return null===t?NaN:+t}function*a(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}const u=r(n),c=u.right,f=u.left,s=r(o).center;var l=c;const h=p(v),d=p((function(t){const n=v(t);return(t,e,r,i,o)=>{n(t,e,(r<<=2)+0,(i<<=2)+0,o<<=2),n(t,e,r+1,i+1,o),n(t,e,r+2,i+2,o),n(t,e,r+3,i+3,o)}}));function p(t){return function(n,e,r=e){if(!((e=+e)>=0))throw new RangeError("invalid rx");if(!((r=+r)>=0))throw new RangeError("invalid ry");let{data:i,width:o,height:a}=n;if(!((o=Math.floor(o))>=0))throw new RangeError("invalid width");if(!((a=Math.floor(void 0!==a?a:i.length/o))>=0))throw new RangeError("invalid height");if(!o||!a||!e&&!r)return n;const u=e&&t(e),c=r&&t(r),f=i.slice();return u&&c?(g(u,f,i,o,a),g(u,i,f,o,a),g(u,f,i,o,a),y(c,i,f,o,a),y(c,f,i,o,a),y(c,i,f,o,a)):u?(g(u,i,f,o,a),g(u,f,i,o,a),g(u,i,f,o,a)):c&&(y(c,i,f,o,a),y(c,f,i,o,a),y(c,i,f,o,a)),n}}function g(t,n,e,r,i){for(let o=0,a=r*i;o<a;)t(n,e,o,o+=r,1)}function y(t,n,e,r,i){for(let o=0,a=r*i;o<r;++o)t(n,e,o,o+a,r)}function v(t){const n=Math.floor(t);if(n===t)return function(t){const n=2*t+1;return(e,r,i,o,a)=>{if(!((o-=a)>=i))return;let u=t*r[i];const c=a*t;for(let t=i,n=i+c;t<n;t+=a)u+=r[Math.min(o,t)];for(let t=i,f=o;t<=f;t+=a)u+=r[Math.min(o,t+c)],e[t]=u/n,u-=r[Math.max(i,t-c)]}}(t);const e=t-n,r=2*t+1;return(t,i,o,a,u)=>{if(!((a-=u)>=o))return;let c=n*i[o];const f=u*n,s=f+u;for(let t=o,n=o+f;t<n;t+=u)c+=i[Math.min(a,t)];for(let n=o,l=a;n<=l;n+=u)c+=i[Math.min(a,n+f)],t[n]=(c+e*(i[Math.max(o,n-s)]+i[Math.min(a,n+s)]))/r,c-=i[Math.max(o,n-f)]}}function _(t,n){let e=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function b(t){return 0|t.length}function m(t){return!(t>0)}function x(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function w(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function M(t,n){const e=w(t,n);return e?Math.sqrt(e):e}function A(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r<n&&(r=n)));else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(void 0===e?o>=o&&(e=r=o):(e>o&&(e=o),r<o&&(r=o)))}return[e,r]}class T{constructor(){this._partials=new Float64Array(32),this._n=0}add(t){const n=this._partials;let e=0;for(let r=0;r<this._n&&r<32;r++){const i=n[r],o=t+i,a=Math.abs(t)<Math.abs(i)?t-(o-i):i-(o-t);a&&(n[e++]=a),t=o}return n[e]=t,this._n=e+1,this}valueOf(){const t=this._partials;let n,e,r,i=this._n,o=0;if(i>0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}class InternMap extends Map{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,e]of t)this.set(n,e)}get(t){return super.get(S(this,t))}has(t){return super.has(S(this,t))}set(t,n){return super.set(E(this,t),n)}delete(t){return super.delete(k(this,t))}}class InternSet extends Set{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(S(this,t))}add(t){return super.add(E(this,t))}delete(t){return super.delete(k(this,t))}}function S({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):e}function E({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):(t.set(r,e),e)}function k({_intern:t,_key:n},e){const r=n(e);return t.has(r)&&(e=t.get(r),t.delete(r)),e}function N(t){return null!==t&&"object"==typeof t?t.valueOf():t}function C(t){return t}function P(t,...n){return I(t,C,C,n)}function z(t,...n){return I(t,Array.from,C,n)}function D(t,n){for(let e=1,r=n.length;e<r;++e)t=t.flatMap((t=>t.pop().map((([n,e])=>[...t,n,e]))));return t}function R(t,n,...e){return I(t,C,n,e)}function F(t,n,...e){return I(t,Array.from,n,e)}function q(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function I(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new InternMap,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}function O(t,n){return Array.from(n,(n=>t[n]))}function U(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[e]=n;if(e&&2!==e.length||n.length>1){const r=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),r.sort(((t,e)=>{for(const r of n){const n=Y(r[t],r[e]);if(n)return n}}))):(e=t.map(e),r.sort(((t,n)=>Y(e[t],e[n])))),O(t,r)}return t.sort(B(e))}function B(t=n){if(t===n)return Y;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,e)=>{const r=t(n,e);return r||0===r?r:(0===t(e,e))-(0===t(n,n))}}function Y(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(t<n?-1:t>n?1:0)}var L=Array.prototype.slice;function j(t){return()=>t}var $=Math.sqrt(50),H=Math.sqrt(10),X=Math.sqrt(2);function G(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=V(t,n,e))||!isFinite(a))return[];if(a>0){let e=Math.round(t/a),r=Math.round(n/a);for(e*a<t&&++e,r*a>n&&--r,o=new Array(i=r-e+1);++u<i;)o[u]=(e+u)*a}else{a=-a;let e=Math.round(t*a),r=Math.round(n*a);for(e/a<t&&++e,r/a>n&&--r,o=new Array(i=r-e+1);++u<i;)o[u]=(e+u)/a}return r&&o.reverse(),o}function V(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=$?10:o>=H?5:o>=X?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=$?10:o>=H?5:o>=X?2:1)}function W(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=$?i*=10:o>=H?i*=5:o>=X&&(i*=2),n<t?-i:i}function Z(t,n,e){let r;for(;;){const i=V(t,n,e);if(i===r||0===i||!isFinite(i))return[t,n];i>0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function K(t){return Math.ceil(Math.log(_(t))/Math.LN2)+1}function Q(){var t=C,n=A,e=K;function r(r){Array.isArray(r)||(r=Array.from(r));var i,o,a,u=r.length,c=new Array(u);for(i=0;i<u;++i)c[i]=t(r[i],i,r);var f=n(c),s=f[0],h=f[1],d=e(c,s,h);if(!Array.isArray(d)){const t=h,e=+d;if(n===A&&([s,h]=Z(s,h,e)),(d=G(s,h,e))[0]<=s&&(a=V(s,h,e)),d[d.length-1]>=h)if(t>=h&&n===A){const t=V(s,h,e);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length;d[0]<=s;)d.shift(),--p;for(;d[p-1]>h;)d.pop(),--p;var g,y=new Array(p+1);for(i=0;i<=p;++i)(g=y[i]=[]).x0=i>0?d[i-1]:s,g.x1=i<p?d[i]:h;if(isFinite(a)){if(a>0)for(i=0;i<u;++i)null!=(o=c[i])&&s<=o&&o<=h&&y[Math.min(p,Math.floor((o-s)/a))].push(r[i]);else if(a<0)for(i=0;i<u;++i)if(null!=(o=c[i])&&s<=o&&o<=h){const t=Math.floor((s-o)*a);y[Math.min(p,t+(d[t]<=o))].push(r[i])}}else for(i=0;i<u;++i)null!=(o=c[i])&&s<=o&&o<=h&&y[l(d,o,0,p)].push(r[i]);return y}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:j(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:j([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?j(L.call(t)):j(t),r):e},r}function J(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e<n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e<i||void 0===e&&i>=i)&&(e=i)}return e}function tt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e<n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e<o||void 0===e&&o>=o)&&(e=o,r=i);return r}function nt(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function et(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function rt(t,n,e=0,r=t.length-1,i){for(i=void 0===i?Y:B(i);r>e;){if(r-e>600){const o=r-e+1,a=n-e+1,u=Math.log(o),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(o-c)/o)*(a-o/2<0?-1:1);rt(t,n,Math.max(e,Math.floor(n-a*c/o+f)),Math.min(r,Math.floor(n+(o-a)*c/o+f)),i)}const o=t[n];let a=e,u=r;for(it(t,e,n),i(t[r],o)>0&&it(t,e,r);a<u;){for(it(t,a,u),++a,--u;i(t[a],o)<0;)++a;for(;i(t[u],o)>0;)--u}0===i(t[e],o)?it(t,e,u):(++u,it(t,u,r)),u<=n&&(e=u+1),n<=u&&(r=u-1)}return t}function it(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function ot(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r}function at(t,n,e){if(r=(t=Float64Array.from(a(t,e))).length){if((n=+n)<=0||r<2)return nt(t);if(n>=1)return J(t);var r,i=(r-1)*n,o=Math.floor(i),u=J(rt(t,o).subarray(0,o+1));return u+(nt(t.subarray(o+1))-u)*(i-o)}}function ut(t,n,e=o){if(r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,a=Math.floor(i),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(i-a)}}function ct(t,n,e){if(r=(t=Float64Array.from(a(t,e))).length){if((n=+n)<=0||r<2)return et(t);if(n>=1)return tt(t);var r,i=Math.floor((r-1)*n),o=rt(Uint32Array.from(t,((t,n)=>n)),i,0,r-1,((n,e)=>Y(t[n],t[e])));return ot(o.subarray(0,i+1),(n=>t[n]))}}function ft(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function st(t,n){return[t,n]}function lt(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}function ht(t,e=n){if(1===e.length)return et(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)<0)&&(r=n,i=o);return i}var dt=pt(Math.random);function pt(t){return function(n,e=0,r=n.length){let i=r-(e=+e);for(;i;){const r=t()*i--|0,o=n[i+e];n[i+e]=n[r+e],n[r+e]=o}return n}}function gt(t){if(!(i=t.length))return[];for(var n=-1,e=nt(t,yt),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function yt(t){return t.length}function vt(t){return t instanceof InternSet?t:new InternSet(t)}function _t(t,n){const e=t[Symbol.iterator](),r=new Set;for(const t of n){const n=bt(t);if(r.has(n))continue;let i,o;for(;({value:i,done:o}=e.next());){if(o)return!1;const t=bt(i);if(r.add(t),Object.is(n,t))break}}return!0}function bt(t){return null!==t&&"object"==typeof t?t.valueOf():t}function mt(t){return t}var xt=1e-6;function wt(t){return"translate("+t+",0)"}function Mt(t){return"translate(0,"+t+")"}function At(t){return n=>+t(n)}function Tt(t,n){return n=Math.max(0,t.bandwidth()-2*n)/2,t.round()&&(n=Math.round(n)),e=>+t(e)+n}function St(){return!this.__axis}function Et(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,f=1===t||4===t?-1:1,s=4===t||2===t?"x":"y",l=1===t||3===t?wt:Mt;function h(h){var d=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,p=null==i?n.tickFormat?n.tickFormat.apply(n,e):mt:i,g=Math.max(o,0)+u,y=n.range(),v=+y[0]+c,_=+y[y.length-1]+c,b=(n.bandwidth?Tt:At)(n.copy(),c),m=h.selection?h.selection():h,x=m.selectAll(".domain").data([null]),w=m.selectAll(".tick").data(d,n).order(),M=w.exit(),A=w.enter().append("g").attr("class","tick"),T=w.select("line"),S=w.select("text");x=x.merge(x.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),w=w.merge(A),T=T.merge(A.append("line").attr("stroke","currentColor").attr(s+"2",f*o)),S=S.merge(A.append("text").attr("fill","currentColor").attr(s,f*g).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),h!==m&&(x=x.transition(h),w=w.transition(h),T=T.transition(h),S=S.transition(h),M=M.transition(h).attr("opacity",xt).attr("transform",(function(t){return isFinite(t=b(t))?l(t+c):this.getAttribute("transform")})),A.attr("opacity",xt).attr("transform",(function(t){var n=this.parentNode.__axis;return l((n&&isFinite(n=n(t))?n:b(t))+c)}))),M.remove(),x.attr("d",4===t||2===t?a?"M"+f*a+","+v+"H"+c+"V"+_+"H"+f*a:"M"+c+","+v+"V"+_:a?"M"+v+","+f*a+"V"+c+"H"+_+"V"+f*a:"M"+v+","+c+"H"+_),w.attr("opacity",1).attr("transform",(function(t){return l(b(t)+c)})),T.attr(s+"2",f*o),S.attr(s,f*g).text(p),m.filter(St).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),m.each((function(){this.__axis=b}))}return h.scale=function(t){return arguments.length?(n=t,h):n},h.ticks=function(){return e=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(e=null==t?[]:Array.from(t),h):e.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(c=+t,h):c},h}var kt={value:()=>{}};function Nt(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new Ct(r)}function Ct(t){this._=t}function Pt(t,n){return t.trim().split(/^|\s+/).map((function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))}function zt(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function Dt(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=kt,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}Ct.prototype=Nt.prototype={constructor:Ct,on:function(t,n){var e,r=this._,i=Pt(t+"",r),o=-1,a=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<a;)if(e=(t=i[o]).type)r[e]=Dt(r[e],t.name,n);else if(null==n)for(e in r)r[e]=Dt(r[e],t.name,null);return this}for(;++o<a;)if((e=(t=i[o]).type)&&(e=zt(r[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new Ct(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Rt="http://www.w3.org/1999/xhtml",Ft={svg:"http://www.w3.org/2000/svg",xhtml:Rt,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function qt(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ft.hasOwnProperty(n)?{space:Ft[n],local:t}:t}function It(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Rt&&n.documentElement.namespaceURI===Rt?n.createElement(t):n.createElementNS(e,t)}}function Ot(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Ut(t){var n=qt(t);return(n.local?Ot:It)(n)}function Bt(){}function Yt(t){return null==t?Bt:function(){return this.querySelector(t)}}function Lt(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function jt(){return[]}function $t(t){return null==t?jt:function(){return this.querySelectorAll(t)}}function Ht(t){return function(){return this.matches(t)}}function Xt(t){return function(n){return n.matches(t)}}var Gt=Array.prototype.find;function Vt(){return this.firstElementChild}var Wt=Array.prototype.filter;function Zt(){return Array.from(this.children)}function Kt(t){return new Array(t.length)}function Qt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function Jt(t){return function(){return t}}function tn(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new Qt(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function nn(t,n,e,r,i,o,a){var u,c,f,s=new Map,l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=a.call(c,c.__data__,u,n)+"",s.has(f)?i[u]=c:s.set(f,c));for(u=0;u<h;++u)f=a.call(t,o[u],u,o)+"",(c=s.get(f))?(r[u]=c,c.__data__=o[u],s.delete(f)):e[u]=new Qt(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s.get(d[u])===c&&(i[u]=c)}function en(t){return t.__data__}function rn(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function on(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function an(t){return function(){this.removeAttribute(t)}}function un(t){return function(){this.removeAttributeNS(t.space,t.local)}}function cn(t,n){return function(){this.setAttribute(t,n)}}function fn(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function sn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function ln(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function hn(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function dn(t){return function(){this.style.removeProperty(t)}}function pn(t,n,e){return function(){this.style.setProperty(t,n,e)}}function gn(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function yn(t,n){return t.style.getPropertyValue(n)||hn(t).getComputedStyle(t,null).getPropertyValue(n)}function vn(t){return function(){delete this[t]}}function _n(t,n){return function(){this[t]=n}}function bn(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function mn(t){return t.trim().split(/^|\s+/)}function xn(t){return t.classList||new wn(t)}function wn(t){this._node=t,this._names=mn(t.getAttribute("class")||"")}function Mn(t,n){for(var e=xn(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function An(t,n){for(var e=xn(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function Tn(t){return function(){Mn(this,t)}}function Sn(t){return function(){An(this,t)}}function En(t,n){return function(){(n.apply(this,arguments)?Mn:An)(this,t)}}function kn(){this.textContent=""}function Nn(t){return function(){this.textContent=t}}function Cn(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function Pn(){this.innerHTML=""}function zn(t){return function(){this.innerHTML=t}}function Dn(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function Rn(){this.nextSibling&&this.parentNode.appendChild(this)}function Fn(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function qn(){return null}function In(){var t=this.parentNode;t&&t.removeChild(this)}function On(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Un(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Bn(t){return t.trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}function Yn(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.options);++i?n.length=i:delete this.__on}}}function Ln(t,n,e){return function(){var r,i=this.__on,o=function(t){return function(n){t.call(this,n,this.__data__)}}(n);if(i)for(var a=0,u=i.length;a<u;++a)if((r=i[a]).type===t.type&&r.name===t.name)return this.removeEventListener(r.type,r.listener,r.options),this.addEventListener(r.type,r.listener=o,r.options=e),void(r.value=n);this.addEventListener(t.type,o,e),r={type:t.type,name:t.name,value:n,listener:o,options:e},i?i.push(r):this.__on=[r]}}function jn(t,n,e){var r=hn(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function $n(t,n){return function(){return jn(this,t,n)}}function Hn(t,n){return function(){return jn(this,t,n.apply(this,arguments))}}Qt.prototype={constructor:Qt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}},wn.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Xn=[null];function Gn(t,n){this._groups=t,this._parents=n}function Vn(){return new Gn([[document.documentElement]],Xn)}function Wn(t){return"string"==typeof t?new Gn([[document.querySelector(t)]],[document.documentElement]):new Gn([[t]],Xn)}Gn.prototype=Vn.prototype={constructor:Gn,select:function(t){"function"!=typeof t&&(t=Yt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Gn(r,this._parents)},selectAll:function(t){t="function"==typeof t?function(t){return function(){return Lt(t.apply(this,arguments))}}(t):$t(t);for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Gn(r,i)},selectChild:function(t){return this.select(null==t?Vt:function(t){return function(){return Gt.call(this.children,t)}}("function"==typeof t?t:Xt(t)))},selectChildren:function(t){return this.selectAll(null==t?Zt:function(t){return function(){return Wt.call(this.children,t)}}("function"==typeof t?t:Xt(t)))},filter:function(t){"function"!=typeof t&&(t=Ht(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Gn(r,this._parents)},data:function(t,n){if(!arguments.length)return Array.from(this,en);var e=n?nn:tn,r=this._parents,i=this._groups;"function"!=typeof t&&(t=Jt(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=rn(t.call(s,s&&s.__data__,f,r)),p=d.length,g=u[f]=new Array(p),y=a[f]=new Array(p),v=c[f]=new Array(h);e(s,l,g,y,v,d,n);for(var _,b,m=0,x=0;m<p;++m)if(_=g[m]){for(m>=x&&(x=m+1);!(b=y[x])&&++x<p;);_._next=b||null}}return(a=new Gn(a,r))._enter=u,a._exit=c,a},enter:function(){return new Gn(this._enter||this._groups.map(Kt),this._parents)},exit:function(){return new Gn(this._exit||this._groups.map(Kt),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return"function"==typeof t?(r=t(r))&&(r=r.selection()):r=r.append(t+""),null!=n&&(i=n(i))&&(i=i.selection()),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=t.selection?t.selection():t,e=this._groups,r=n._groups,i=e.length,o=r.length,a=Math.min(i,o),u=new Array(i),c=0;c<a;++c)for(var f,s=e[c],l=r[c],h=s.length,d=u[c]=new Array(h),p=0;p<h;++p)(f=s[p]||l[p])&&(d[p]=f);for(;c<i;++c)u[c]=e[c];return new Gn(u,this._parents)},selection:function(){return this},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=on);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Gn(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){return Array.from(this)},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){let t=0;for(const n of this)++t;return t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=qt(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?un:an:"function"==typeof n?e.local?ln:sn:e.local?fn:cn)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?dn:"function"==typeof n?gn:pn)(t,n,null==e?"":e)):yn(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?vn:"function"==typeof n?bn:_n)(t,n)):this.node()[t]},classed:function(t,n){var e=mn(t+"");if(arguments.length<2){for(var r=xn(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?En:n?Tn:Sn)(e,n))},text:function(t){return arguments.length?this.each(null==t?kn:("function"==typeof t?Cn:Nn)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?Pn:("function"==typeof t?Dn:zn)(t)):this.node().innerHTML},raise:function(){return this.each(Rn)},lower:function(){return this.each(Fn)},append:function(t){var n="function"==typeof t?t:Ut(t);return this.select((function(){return this.appendChild(n.apply(this,arguments))}))},insert:function(t,n){var e="function"==typeof t?t:Ut(t),r=null==n?qn:"function"==typeof n?n:Yt(n);return this.select((function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)}))},remove:function(){return this.each(In)},clone:function(t){return this.select(t?Un:On)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=Bn(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?Ln:Yn,r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?Hn:$n)(t,n))},[Symbol.iterator]:function*(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r,i=t[n],o=0,a=i.length;o<a;++o)(r=i[o])&&(yield r)}};var Zn=0;function Kn(){return new Qn}function Qn(){this._="@"+(++Zn).toString(36)}function Jn(t){let n;for(;n=t.sourceEvent;)t=n;return t}function te(t,n){if(t=Jn(t),void 0===n&&(n=t.currentTarget),n){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(n.getScreenCTM().inverse())).x,r.y]}if(n.getBoundingClientRect){var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}}return[t.pageX,t.pageY]}Qn.prototype=Kn.prototype={constructor:Qn,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};const ne={passive:!1},ee={capture:!0,passive:!1};function re(t){t.stopImmediatePropagation()}function ie(t){t.preventDefault(),t.stopImmediatePropagation()}function oe(t){var n=t.document.documentElement,e=Wn(t).on("dragstart.drag",ie,ee);"onselectstart"in n?e.on("selectstart.drag",ie,ee):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function ae(t,n){var e=t.document.documentElement,r=Wn(t).on("dragstart.drag",null);n&&(r.on("click.drag",ie,ee),setTimeout((function(){r.on("click.drag",null)}),0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}var ue=t=>()=>t;function ce(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function fe(t){return!t.ctrlKey&&!t.button}function se(){return this.parentNode}function le(t,n){return null==n?{x:t.x,y:t.y}:n}function he(){return navigator.maxTouchPoints||"ontouchstart"in this}function de(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function pe(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function ge(){}ce.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var ye=.7,ve=1/ye,_e="\\s*([+-]?\\d+)\\s*",be="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",me="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",xe=/^#([0-9a-f]{3,8})$/,we=new RegExp(`^rgb\\(${_e},${_e},${_e}\\)$`),Me=new RegExp(`^rgb\\(${me},${me},${me}\\)$`),Ae=new RegExp(`^rgba\\(${_e},${_e},${_e},${be}\\)$`),Te=new RegExp(`^rgba\\(${me},${me},${me},${be}\\)$`),Se=new RegExp(`^hsl\\(${be},${me},${me}\\)$`),Ee=new RegExp(`^hsla\\(${be},${me},${me},${be}\\)$`),ke={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function Ne(){return this.rgb().formatHex()}function Ce(){return this.rgb().formatRgb()}function Pe(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=xe.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?ze(n):3===e?new qe(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?De(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?De(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=we.exec(t))?new qe(n[1],n[2],n[3],1):(n=Me.exec(t))?new qe(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ae.exec(t))?De(n[1],n[2],n[3],n[4]):(n=Te.exec(t))?De(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Se.exec(t))?Le(n[1],n[2]/100,n[3]/100,1):(n=Ee.exec(t))?Le(n[1],n[2]/100,n[3]/100,n[4]):ke.hasOwnProperty(t)?ze(ke[t]):"transparent"===t?new qe(NaN,NaN,NaN,0):null}function ze(t){return new qe(t>>16&255,t>>8&255,255&t,1)}function De(t,n,e,r){return r<=0&&(t=n=e=NaN),new qe(t,n,e,r)}function Re(t){return t instanceof ge||(t=Pe(t)),t?new qe((t=t.rgb()).r,t.g,t.b,t.opacity):new qe}function Fe(t,n,e,r){return 1===arguments.length?Re(t):new qe(t,n,e,null==r?1:r)}function qe(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ie(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}`}function Oe(){const t=Ue(this.opacity);return`${1===t?"rgb(":"rgba("}${Be(this.r)}, ${Be(this.g)}, ${Be(this.b)}${1===t?")":`, ${t})`}`}function Ue(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Be(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Ye(t){return((t=Be(t))<16?"0":"")+t.toString(16)}function Le(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new He(t,n,e,r)}function je(t){if(t instanceof He)return new He(t.h,t.s,t.l,t.opacity);if(t instanceof ge||(t=Pe(t)),!t)return new He;if(t instanceof He)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new He(a,u,c,t.opacity)}function $e(t,n,e,r){return 1===arguments.length?je(t):new He(t,n,e,null==r?1:r)}function He(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Xe(t){return(t=(t||0)%360)<0?t+360:t}function Ge(t){return Math.max(0,Math.min(1,t||0))}function Ve(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}de(ge,Pe,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Ne,formatHex:Ne,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return je(this).formatHsl()},formatRgb:Ce,toString:Ce}),de(qe,Fe,pe(ge,{brighter(t){return t=null==t?ve:Math.pow(ve,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?ye:Math.pow(ye,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new qe(Be(this.r),Be(this.g),Be(this.b),Ue(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ie,formatHex:Ie,formatHex8:function(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}${Ye(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Oe,toString:Oe})),de(He,$e,pe(ge,{brighter(t){return t=null==t?ve:Math.pow(ve,t),new He(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ye:Math.pow(ye,t),new He(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new qe(Ve(t>=240?t-240:t+120,i,r),Ve(t,i,r),Ve(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new He(Xe(this.h),Ge(this.s),Ge(this.l),Ue(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Ue(this.opacity);return`${1===t?"hsl(":"hsla("}${Xe(this.h)}, ${100*Ge(this.s)}%, ${100*Ge(this.l)}%${1===t?")":`, ${t})`}`}}));const We=Math.PI/180,Ze=180/Math.PI,Ke=.96422,Qe=.82521,Je=4/29,tr=6/29,nr=3*tr*tr;function er(t){if(t instanceof ir)return new ir(t.l,t.a,t.b,t.opacity);if(t instanceof lr)return hr(t);t instanceof qe||(t=Re(t));var n,e,r=cr(t.r),i=cr(t.g),o=cr(t.b),a=or((.2225045*r+.7168786*i+.0606169*o)/1);return r===i&&i===o?n=e=a:(n=or((.4360747*r+.3850649*i+.1430804*o)/Ke),e=or((.0139322*r+.0971045*i+.7141733*o)/Qe)),new ir(116*a-16,500*(n-a),200*(a-e),t.opacity)}function rr(t,n,e,r){return 1===arguments.length?er(t):new ir(t,n,e,null==r?1:r)}function ir(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function or(t){return t>.008856451679035631?Math.pow(t,1/3):t/nr+Je}function ar(t){return t>tr?t*t*t:nr*(t-Je)}function ur(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function cr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function fr(t){if(t instanceof lr)return new lr(t.h,t.c,t.l,t.opacity);if(t instanceof ir||(t=er(t)),0===t.a&&0===t.b)return new lr(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Ze;return new lr(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function sr(t,n,e,r){return 1===arguments.length?fr(t):new lr(t,n,e,null==r?1:r)}function lr(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function hr(t){if(isNaN(t.h))return new ir(t.l,0,0,t.opacity);var n=t.h*We;return new ir(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}de(ir,rr,pe(ge,{brighter(t){return new ir(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker(t){return new ir(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new qe(ur(3.1338561*(n=Ke*ar(n))-1.6168667*(t=1*ar(t))-.4906146*(e=Qe*ar(e))),ur(-.9787684*n+1.9161415*t+.033454*e),ur(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),de(lr,sr,pe(ge,{brighter(t){return new lr(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker(t){return new lr(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb(){return hr(this).rgb()}}));var dr=-.14861,pr=1.78277,gr=-.29227,yr=-.90649,vr=1.97294,_r=vr*yr,br=vr*pr,mr=pr*gr-yr*dr;function xr(t){if(t instanceof Mr)return new Mr(t.h,t.s,t.l,t.opacity);t instanceof qe||(t=Re(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(mr*r+_r*n-br*e)/(mr+_r-br),o=r-i,a=(vr*(e-i)-gr*o)/yr,u=Math.sqrt(a*a+o*o)/(vr*i*(1-i)),c=u?Math.atan2(a,o)*Ze-120:NaN;return new Mr(c<0?c+360:c,u,i,t.opacity)}function wr(t,n,e,r){return 1===arguments.length?xr(t):new Mr(t,n,e,null==r?1:r)}function Mr(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ar(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function Tr(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return Ar((e-r/n)*n,a,i,o,u)}}function Sr(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return Ar((e-r/n)*n,i,o,a,u)}}de(Mr,wr,pe(ge,{brighter(t){return t=null==t?ve:Math.pow(ve,t),new Mr(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ye:Math.pow(ye,t),new Mr(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=isNaN(this.h)?0:(this.h+120)*We,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new qe(255*(n+e*(dr*r+pr*i)),255*(n+e*(gr*r+yr*i)),255*(n+e*(vr*r)),this.opacity)}}));var Er=t=>()=>t;function kr(t,n){return function(e){return t+e*n}}function Nr(t,n){var e=n-t;return e?kr(t,e>180||e<-180?e-360*Math.round(e/360):e):Er(isNaN(t)?n:t)}function Cr(t){return 1==(t=+t)?Pr:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Er(isNaN(n)?e:n)}}function Pr(t,n){var e=n-t;return e?kr(t,e):Er(isNaN(t)?n:t)}var zr=function t(n){var e=Cr(n);function r(t,n){var r=e((t=Fe(t)).r,(n=Fe(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=Pr(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Dr(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=Fe(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var Rr=Dr(Tr),Fr=Dr(Sr);function qr(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function Ir(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Or(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Hr(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function Ur(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function Br(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function Yr(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Hr(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var Lr=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,jr=new RegExp(Lr.source,"g");function $r(t,n){var e,r,i,o=Lr.lastIndex=jr.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=Lr.exec(t))&&(r=jr.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:Br(e,r)})),o=jr.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Hr(t,n){var e,r=typeof n;return null==n||"boolean"===r?Er(n):("number"===r?Br:"string"===r?(e=Pe(n))?(n=e,zr):$r:n instanceof Pe?zr:n instanceof Date?Ur:Ir(n)?qr:Array.isArray(n)?Or:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?Yr:Br)(t,n)}function Xr(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var Gr,Vr=180/Math.PI,Wr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Zr(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Vr,skewX:Math.atan(c)*Vr,scaleX:a,scaleY:u}}function Kr(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:Br(t,i)},{i:c-2,x:Br(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Br(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Br(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Br(t,e)},{i:u-2,x:Br(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var Qr=Kr((function(t){const n=new("function"==typeof DOMMatrix?DOMMatrix:WebKitCSSMatrix)(t+"");return n.isIdentity?Wr:Zr(n.a,n.b,n.c,n.d,n.e,n.f)}),"px, ","px)","deg)"),Jr=Kr((function(t){return null==t?Wr:(Gr||(Gr=document.createElementNS("http://www.w3.org/2000/svg","g")),Gr.setAttribute("transform",t),(t=Gr.transform.baseVal.consolidate())?Zr((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Wr)}),", ",")",")");function ti(t){return((t=Math.exp(t))+1/t)/2}var ni=function t(n,e,r){function i(t,i){var o,a,u=t[0],c=t[1],f=t[2],s=i[0],l=i[1],h=i[2],d=s-u,p=l-c,g=d*d+p*p;if(g<1e-12)a=Math.log(h/f)/n,o=function(t){return[u+t*d,c+t*p,f*Math.exp(n*t*a)]};else{var y=Math.sqrt(g),v=(h*h-f*f+r*g)/(2*f*e*y),_=(h*h-f*f-r*g)/(2*h*e*y),b=Math.log(Math.sqrt(v*v+1)-v),m=Math.log(Math.sqrt(_*_+1)-_);a=(m-b)/n,o=function(t){var r=t*a,i=ti(b),o=f/(e*y)*(i*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(n*r+b)-function(t){return((t=Math.exp(t))-1/t)/2}(b));return[u+o*d,c+o*p,f*i/ti(n*r+b)]}}return o.duration=1e3*a*n/Math.SQRT2,o}return i.rho=function(n){var e=Math.max(.001,+n),r=e*e;return t(e,r,r*r)},i}(Math.SQRT2,2,4);function ei(t){return function(n,e){var r=t((n=$e(n)).h,(e=$e(e)).h),i=Pr(n.s,e.s),o=Pr(n.l,e.l),a=Pr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var ri=ei(Nr),ii=ei(Pr);function oi(t){return function(n,e){var r=t((n=sr(n)).h,(e=sr(e)).h),i=Pr(n.c,e.c),o=Pr(n.l,e.l),a=Pr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var ai=oi(Nr),ui=oi(Pr);function ci(t){return function n(e){function r(n,r){var i=t((n=wr(n)).h,(r=wr(r)).h),o=Pr(n.s,r.s),a=Pr(n.l,r.l),u=Pr(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var fi=ci(Nr),si=ci(Pr);function li(t,n){void 0===n&&(n=t,t=Hr);for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}}var hi,di,pi=0,gi=0,yi=0,vi=0,_i=0,bi=0,mi="object"==typeof performance&&performance.now?performance:Date,xi="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function wi(){return _i||(xi(Mi),_i=mi.now()+bi)}function Mi(){_i=0}function Ai(){this._call=this._time=this._next=null}function Ti(t,n,e){var r=new Ai;return r.restart(t,n,e),r}function Si(){wi(),++pi;for(var t,n=hi;n;)(t=_i-n._time)>=0&&n._call.call(void 0,t),n=n._next;--pi}function Ei(){_i=(vi=mi.now())+bi,pi=gi=0;try{Si()}finally{pi=0,function(){var t,n,e=hi,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:hi=n);di=t,Ni(r)}(),_i=0}}function ki(){var t=mi.now(),n=t-vi;n>1e3&&(bi-=n,vi=t)}function Ni(t){pi||(gi&&(gi=clearTimeout(gi)),t-_i>24?(t<1/0&&(gi=setTimeout(Ei,t-mi.now()-bi)),yi&&(yi=clearInterval(yi))):(yi||(vi=mi.now(),yi=setInterval(ki,1e3)),pi=1,xi(Ei)))}function Ci(t,n,e){var r=new Ai;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ai.prototype=Ti.prototype={constructor:Ai,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?wi():+e)+(null==n?0:+n),this._next||di===this||(di?di._next=this:hi=this,di=this),this._call=t,this._time=e,Ni()},stop:function(){this._call&&(this._call=null,this._time=1/0,Ni())}};var Pi=Nt("start","end","cancel","interrupt"),zi=[];function Di(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=1,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(1!==e.state)return c();for(f in i)if((h=i[f]).name===e.name){if(3===h.state)return Ci(a);4===h.state?(h.state=6,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=6,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(Ci((function(){3===e.state&&(e.state=4,e.timer.restart(u,e.delay,e.time),u(o))})),e.state=2,e.on.call("start",t,t.__data__,e.index,e.group),2===e.state){for(e.state=3,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function u(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(c),e.state=5,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);5===e.state&&(e.on.call("end",t,t.__data__,e.index,e.group),c())}function c(){for(var r in e.state=6,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=Ti(o,0,e.time)}(t,e,{name:n,index:r,group:i,on:Pi,tween:zi,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:0})}function Ri(t,n){var e=qi(t,n);if(e.state>0)throw new Error("too late; already scheduled");return e}function Fi(t,n){var e=qi(t,n);if(e.state>3)throw new Error("too late; already running");return e}function qi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Ii(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>2&&e.state<5,e.state=6,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Oi(t,n){var e,r;return function(){var i=Fi(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}function Ui(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Fi(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}}function Bi(t,n,e){var r=t._id;return t.each((function(){var t=Fi(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)})),function(t){return qi(t,r).value[n]}}function Yi(t,n){var e;return("number"==typeof n?Br:n instanceof Pe?zr:(e=Pe(n))?(n=e,zr):$r)(t,n)}function Li(t){return function(){this.removeAttribute(t)}}function ji(t){return function(){this.removeAttributeNS(t.space,t.local)}}function $i(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}}function Hi(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}function Xi(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}}function Gi(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}function Vi(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}function Wi(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}function Zi(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&Wi(t,i)),e}return i._value=n,i}function Ki(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&Vi(t,i)),e}return i._value=n,i}function Qi(t,n){return function(){Ri(this,t).delay=+n.apply(this,arguments)}}function Ji(t,n){return n=+n,function(){Ri(this,t).delay=n}}function to(t,n){return function(){Fi(this,t).duration=+n.apply(this,arguments)}}function no(t,n){return n=+n,function(){Fi(this,t).duration=n}}function eo(t,n){if("function"!=typeof n)throw new Error;return function(){Fi(this,t).ease=n}}function ro(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every((function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?Ri:Fi;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}var io=Vn.prototype.constructor;function oo(t){return function(){this.style.removeProperty(t)}}function ao(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}function uo(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&ao(t,o,e)),r}return o._value=n,o}function co(t){return function(n){this.textContent=t.call(this,n)}}function fo(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&co(r)),n}return r._value=t,r}var so=0;function lo(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function ho(t){return Vn().transition(t)}function po(){return++so}var go=Vn.prototype;lo.prototype=ho.prototype={constructor:lo,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Yt(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,Di(l[h],n,e,h,l,qi(u,e)));return new lo(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=$t(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=qi(c,e),g=0,y=d.length;g<y;++g)(h=d[g])&&Di(h,n,e,g,d,p);o.push(d),a.push(c)}return new lo(o,a,n,e)},selectChild:go.selectChild,selectChildren:go.selectChildren,filter:function(t){"function"!=typeof t&&(t=Ht(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new lo(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new lo(a,this._parents,this._name,this._id)},selection:function(){return new io(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=po(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=qi(a,n);Di(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new lo(r,this._parents,t,e)},call:go.call,nodes:go.nodes,node:go.node,size:go.size,empty:go.empty,each:go.each,on:function(t,n){var e=this._id;return arguments.length<2?qi(this.node(),e).on.on(t):this.each(ro(e,t,n))},attr:function(t,n){var e=qt(t),r="transform"===e?Jr:Yi;return this.attrTween(t,"function"==typeof n?(e.local?Gi:Xi)(e,r,Bi(this,"attr."+t,n)):null==n?(e.local?ji:Li)(e):(e.local?Hi:$i)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=qt(t);return this.tween(e,(r.local?Zi:Ki)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?Qr:Yi;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=yn(this,t),a=(this.style.removeProperty(t),yn(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,oo(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=yn(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=yn(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Bi(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Fi(this,t),f=c.on,s=null==c.value[a]?o||(o=oo(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=yn(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,uo(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Bi(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,fo(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=qi(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Oi:Ui)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Qi:Ji)(n,t)):qi(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?to:no)(n,t)):qi(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(eo(n,t)):qi(this.node(),n).ease},easeVarying:function(t){if("function"!=typeof t)throw new Error;return this.each(function(t,n){return function(){var e=n.apply(this,arguments);if("function"!=typeof e)throw new Error;Fi(this,t).ease=e}}(this._id,t))},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise((function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each((function(){var e=Fi(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})),0===i&&o()}))},[Symbol.iterator]:go[Symbol.iterator]};function yo(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function vo(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var _o=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),bo=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),mo=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),xo=Math.PI,wo=xo/2;function Mo(t){return(1-Math.cos(xo*t))/2}function Ao(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function To(t){return((t*=2)<=1?Ao(1-t):2-Ao(t-1))/2}function So(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Eo=4/11,ko=7.5625;function No(t){return(t=+t)<Eo?ko*t*t:t<.7272727272727273?ko*(t-=.5454545454545454)*t+.75:t<.9090909090909091?ko*(t-=.8181818181818182)*t+.9375:ko*(t-=.9545454545454546)*t+.984375}var Co=1.70158,Po=function t(n){function e(t){return(t=+t)*t*(n*(t-1)+t)}return n=+n,e.overshoot=t,e}(Co),zo=function t(n){function e(t){return--t*t*((t+1)*n+t)+1}return n=+n,e.overshoot=t,e}(Co),Do=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Co),Ro=2*Math.PI,Fo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ro);function i(t){return n*Ao(- --t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*Ro)},i.period=function(e){return t(n,e)},i}(1,.3),qo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ro);function i(t){return 1-n*Ao(t=+t)*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*Ro)},i.period=function(e){return t(n,e)},i}(1,.3),Io=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ro);function i(t){return((t=2*t-1)<0?n*Ao(-t)*Math.sin((r-t)/e):2-n*Ao(t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*Ro)},i.period=function(e){return t(n,e)},i}(1,.3),Oo={time:null,delay:0,duration:250,ease:vo};function Uo(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))throw new Error(`transition ${n} not found`);return e}Vn.prototype.interrupt=function(t){return this.each((function(){Ii(this,t)}))},Vn.prototype.transition=function(t){var n,e;t instanceof lo?(n=t._id,t=t._name):(n=po(),(e=Oo).time=wi(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&Di(a,t,n,f,u,e||Uo(a,n));return new lo(r,this._parents,t,n)};var Bo=[null];var Yo=t=>()=>t;function Lo(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function jo(t){t.stopImmediatePropagation()}function $o(t){t.preventDefault(),t.stopImmediatePropagation()}var Ho={name:"drag"},Xo={name:"space"},Go={name:"handle"},Vo={name:"center"};const{abs:Wo,max:Zo,min:Ko}=Math;function Qo(t){return[+t[0],+t[1]]}function Jo(t){return[Qo(t[0]),Qo(t[1])]}var ta={name:"x",handles:["w","e"].map(ca),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},na={name:"y",handles:["n","s"].map(ca),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},ea={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(ca),input:function(t){return null==t?null:Jo(t)},output:function(t){return t}},ra={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},ia={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},oa={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},aa={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},ua={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function ca(t){return{type:t}}function fa(t){return!t.ctrlKey&&!t.button}function sa(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function la(){return navigator.maxTouchPoints||"ontouchstart"in this}function ha(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function da(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function pa(t){var n,e=sa,r=fa,i=la,o=!0,a=Nt("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([ca("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",ra.overlay).merge(e).each((function(){var t=ha(this).extent;Wn(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([ca("selection")]).enter().append("rect").attr("class","selection").attr("cursor",ra.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return ra[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=Wn(this),n=ha(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?Ho:o&&e.altKey?Vo:Go,x=t===na?null:aa[b],w=t===ta?null:ua[b],M=ha(_),A=M.extent,T=M.selection,S=A[0][0],E=A[0][1],k=A[1][0],N=A[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,D=Array.from(e.touches||[e],(t=>{const n=t.identifier;return(t=te(t,_)).point0=t.slice(),t.identifier=n,t}));Ii(_);var R=s(_,arguments,!0).beforestart();if("overlay"===b){T&&(g=!0);const n=[D[0],D[1]||D[0]];M.selection=T=[[i=t===na?S:Ko(n[0][0],n[1][0]),u=t===ta?E:Ko(n[0][1],n[1][1])],[l=t===na?k:Zo(n[0][0],n[1][0]),d=t===ta?N:Zo(n[0][1],n[1][1])]],D.length>1&&U(e)}else i=T[0][0],u=T[0][1],l=T[1][0],d=T[1][1];a=i,c=u,h=l,p=d;var F=Wn(_).attr("pointer-events","none"),q=F.selectAll(".overlay").attr("cursor",ra[b]);if(e.touches)R.moved=O,R.ended=B;else{var I=Wn(e.view).on("mousemove.brush",O,!0).on("mouseup.brush",B,!0);o&&I.on("keydown.brush",Y,!0).on("keyup.brush",L,!0),oe(e.view)}f.call(_),R.start(e,m.name)}function O(t){for(const n of t.changedTouches||[t])for(const t of D)t.identifier===n.identifier&&(t.cur=te(n,_));if(z&&!y&&!v&&1===D.length){const t=D[0];Wo(t.cur[0]-t[0])>Wo(t.cur[1]-t[1])?v=!0:y=!0}for(const t of D)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,$o(t),U(t)}function U(t){const n=D[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case Xo:case Ho:x&&(C=Zo(S-i,Ko(k-l,C)),a=i+C,h=l+C),w&&(P=Zo(E-u,Ko(N-d,P)),c=u+P,p=d+P);break;case Go:D[1]?(x&&(a=Zo(S,Ko(k,D[0][0])),h=Zo(S,Ko(k,D[1][0])),x=1),w&&(c=Zo(E,Ko(N,D[0][1])),p=Zo(E,Ko(N,D[1][1])),w=1)):(x<0?(C=Zo(S-i,Ko(k-i,C)),a=i+C,h=l):x>0&&(C=Zo(S-l,Ko(k-l,C)),a=i,h=l+C),w<0?(P=Zo(E-u,Ko(N-u,P)),c=u+P,p=d):w>0&&(P=Zo(E-d,Ko(N-d,P)),c=u,p=d+P));break;case Vo:x&&(a=Zo(S,Ko(k,i-C*x)),h=Zo(S,Ko(k,l+C*x))),w&&(c=Zo(E,Ko(N,u-P*w)),p=Zo(E,Ko(N,d+P*w)))}h<a&&(x*=-1,r=i,i=l,l=r,r=a,a=h,h=r,b in ia&&q.attr("cursor",ra[b=ia[b]])),p<c&&(w*=-1,r=u,u=d,d=r,r=c,c=p,p=r,b in oa&&q.attr("cursor",ra[b=oa[b]])),M.selection&&(T=M.selection),y&&(a=T[0][0],h=T[1][0]),v&&(c=T[0][1],p=T[1][1]),T[0][0]===a&&T[0][1]===c&&T[1][0]===h&&T[1][1]===p||(M.selection=[[a,c],[h,p]],f.call(_),R.brush(t,m.name))}function B(t){if(jo(t),t.touches){if(t.touches.length)return;n&&clearTimeout(n),n=setTimeout((function(){n=null}),500)}else ae(t.view,g),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);F.attr("pointer-events","all"),q.attr("cursor",ra.overlay),M.selection&&(T=M.selection),da(T)&&(M.selection=null,f.call(_)),R.end(t,m.name)}function Y(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===Go&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=Vo,U(t));break;case 32:m!==Go&&m!==Vo||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=Xo,q.attr("cursor",ra.selection),U(t));break;default:return}$o(t)}function L(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,U(t));break;case 18:m===Vo&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=Go,U(t));break;case 32:m===Xo&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=Vo):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=Go),q.attr("cursor",ra[b]),U(t));break;default:return}$o(t)}}function d(t){s(this,arguments).moved(t)}function p(t){s(this,arguments).ended(t)}function g(){var n=this.__brush||{selection:null};return n.extent=Jo(e.apply(this,arguments)),n.dim=t,n}return c.move=function(n,e,r){n.tween?n.on("start.brush",(function(t){s(this,arguments).beforestart().start(t)})).on("interrupt.brush end.brush",(function(t){s(this,arguments).end(t)})).tween("brush",(function(){var n=this,r=n.__brush,i=s(n,arguments),o=r.selection,a=t.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Hr(o,a);function c(t){r.selection=1===t&&null===a?null:u(t),f.call(n),i.brush()}return null!==o&&null!==a?c:c(1)})):n.each((function(){var n=this,i=arguments,o=n.__brush,a=t.input("function"==typeof e?e.apply(n,i):e,o.extent),u=s(n,i).beforestart();Ii(n),o.selection=null===a?null:a,f.call(n),u.start(r).brush(r).end(r)}))},c.clear=function(t,n){c.move(t,null,n)},l.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(t,n){return this.starting?(this.starting=!1,this.emit("start",t,n)):this.emit("brush",t),this},brush:function(t,n){return this.emit("brush",t,n),this},end:function(t,n){return 0==--this.active&&(delete this.state.emitter,this.emit("end",t,n)),this},emit:function(n,e,r){var i=Wn(this.that).datum();a.call(n,this.that,new Lo(n,{sourceEvent:e,target:c,selection:t.output(this.state.selection),mode:r,dispatch:a}),i)}},c.extent=function(t){return arguments.length?(e="function"==typeof t?t:Yo(Jo(t)),c):e},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:Yo(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:Yo(!!t),c):i},c.handleSize=function(t){return arguments.length?(u=+t,c):u},c.keyModifiers=function(t){return arguments.length?(o=!!t,c):o},c.on=function(){var t=a.on.apply(a,arguments);return t===a?c:t},c}var ga=Math.abs,ya=Math.cos,va=Math.sin,_a=Math.PI,ba=_a/2,ma=2*_a,xa=Math.max,wa=1e-12;function Ma(t,n){return Array.from({length:n-t},((n,e)=>t+e))}function Aa(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function Ta(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=Ma(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;n<c;++n){let e=0;for(let r=0;r<c;++r)e+=a[n*c+r]+t*a[r*c+n];d+=f[n]=e}u=(d=xa(0,ma-e*c)/d)?e:ma/c;{let n=0;r&&s.sort(((t,n)=>r(f[t],f[n])));for(const e of s){const r=n;if(t){const t=Ma(1+~c,c).filter((t=>t<0?a[~t*c+e]:a[e*c+t]));i&&t.sort(((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n])));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=Ma(0,c).filter((t=>a[e*c+t]||a[t*c+e]));i&&t.sort(((t,n)=>i(a[e*c+t],a[e*c+n])));for(const r of t){let t;if(e<r?(t=l[e*c+r]||(l[e*c+r]={source:null,target:null}),t.source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}):(t=l[r*c+e]||(l[r*c+e]={source:null,target:null}),t.target={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]},e===r&&(t.source=t.target)),t.source&&t.target&&t.source.value<t.target.value){const n=t.source;t.source=t.target,t.target=n}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}n+=u}}return(l=Object.values(l)).groups=h,o?l.sort(o):l}return a.padAngle=function(t){return arguments.length?(e=xa(0,t),a):e},a.sortGroups=function(t){return arguments.length?(r=t,a):r},a.sortSubgroups=function(t){return arguments.length?(i=t,a):i},a.sortChords=function(t){return arguments.length?(null==t?o=null:(o=Aa(t))._=t,a):o&&o._},a}const Sa=Math.PI,Ea=2*Sa,ka=1e-6,Na=Ea-ka;function Ca(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function Pa(){return new Ca}Ca.prototype=Pa.prototype={constructor:Ca,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>ka)if(Math.abs(s*u-c*f)>ka&&i){var h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan((Sa-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>ka&&(this._+="L"+(t+b*f)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>f*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,o=!!o;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+f:(Math.abs(this._x1-c)>ka||Math.abs(this._y1-f)>ka)&&(this._+="L"+c+","+f),e&&(l<0&&(l=l%Ea+Ea),l>Na?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=c)+","+(this._y1=f):l>ka&&(this._+="A"+e+","+e+",0,"+ +(l>=Sa)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var za=Array.prototype.slice;function Da(t){return function(){return t}}function Ra(t){return t.source}function Fa(t){return t.target}function qa(t){return t.radius}function Ia(t){return t.startAngle}function Oa(t){return t.endAngle}function Ua(){return 0}function Ba(){return 10}function Ya(t){var n=Ra,e=Fa,r=qa,i=qa,o=Ia,a=Oa,u=Ua,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=za.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-ba,y=a.apply(this,d)-ba,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-ba,b=a.apply(this,d)-ba;if(c||(c=f=Pa()),h>wa&&(ga(y-g)>2*h+wa?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,ga(b-_)>2*h+wa?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*ya(g),p*va(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=+t.apply(this,arguments),x=v-m,w=(_+b)/2;c.quadraticCurveTo(0,0,x*ya(_),x*va(_)),c.lineTo(v*ya(w),v*va(w)),c.lineTo(x*ya(b),x*va(b))}else c.quadraticCurveTo(0,0,v*ya(_),v*va(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*ya(g),p*va(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:Da(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:Da(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:Da(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:Da(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:Da(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:Da(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:Da(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var La=Array.prototype.slice;function ja(t,n){return t-n}var $a=t=>()=>t;function Ha(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=Xa(t,n[r]))return e;return 0}function Xa(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(Ga(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function Ga(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function Va(){}var Wa=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function Za(){var t=1,n=1,e=K,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(ja);else{const e=A(t),r=W(e[0],e[1],n);n=G(Math.floor(e[0]/r)*r,Math.floor(e[1]/r-1)*r,n)}return n.map((n=>o(t,n)))}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=e[0]>=r,Wa[f<<1].forEach(p);for(;++o<t-1;)c=f,f=e[o+1]>=r,Wa[c|f<<1].forEach(p);Wa[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=e[u*t+t]>=r,s=e[u*t]>=r,Wa[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,Wa[c|f<<1|s<<2|l<<3].forEach(p);Wa[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,Wa[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,Wa[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}Wa[s<<3].forEach(p)}(e,i,(function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)})),u.forEach((function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==Ha((n=o[e])[0],t))return void n.push(t)})),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach((function(e){var o,a=e[0],u=e[1],c=0|a,f=0|u,s=r[f*t+c];a>0&&a<t&&c===a&&(o=r[f*t+c-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&f===u&&(o=r[(f-1)*t+c],e[1]=u+(i-o)/(s-o)-.5)}))}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.floor(e[0]),o=Math.floor(e[1]);if(!(r>=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?$a(La.call(t)):$a(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:Va,i):r===u},i}function Ka(t){return t[0]}function Qa(t){return t[1]}function Ja(){return 1}const tu=134217729;function nu(t,n,e,r,i){let o,a,u,c,f=n[0],s=r[0],l=0,h=0;s>f==s>-f?(o=f,f=n[++l]):(o=s,s=r[++h]);let d=0;if(l<t&&h<e)for(s>f==s>-f?(a=f+o,u=o-(a-f),f=n[++l]):(a=s+o,u=o-(a-s),s=r[++h]),o=a,0!==u&&(i[d++]=u);l<t&&h<e;)s>f==s>-f?(a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l]):(a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h]),o=a,0!==u&&(i[d++]=u);for(;l<t;)a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l],o=a,0!==u&&(i[d++]=u);for(;h<e;)a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h],o=a,0!==u&&(i[d++]=u);return 0===o&&0!==d||(i[d++]=o),d}function eu(t){return new Float64Array(t)}const ru=eu(4),iu=eu(8),ou=eu(12),au=eu(16),uu=eu(4);function cu(t,n,e,r,i,o){const a=(n-o)*(e-i),u=(t-i)*(r-o),c=a-u;if(0===a||0===u||a>0!=u>0)return c;const f=Math.abs(a+u);return Math.abs(c)>=33306690738754716e-32*f?c:-function(t,n,e,r,i,o,a){let u,c,f,s,l,h,d,p,g,y,v,_,b,m,x,w,M,A;const T=t-i,S=e-i,E=n-o,k=r-o;m=T*k,h=tu*T,d=h-(h-T),p=T-d,h=tu*k,g=h-(h-k),y=k-g,x=p*y-(m-d*g-p*g-d*y),w=E*S,h=tu*E,d=h-(h-E),p=E-d,h=tu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,ru[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,ru[1]=b-(v+l)+(l-w),A=_+v,l=A-_,ru[2]=_-(A-l)+(v-l),ru[3]=A;let N=function(t,n){let e=n[0];for(let r=1;r<t;r++)e+=n[r];return e}(4,ru),C=22204460492503146e-32*a;if(N>=C||-N>=C)return N;if(l=t-T,u=t-(T+l)+(l-i),l=e-S,f=e-(S+l)+(l-i),l=n-E,c=n-(E+l)+(l-o),l=r-k,s=r-(k+l)+(l-o),0===u&&0===c&&0===f&&0===s)return N;if(C=11093356479670487e-47*a+33306690738754706e-32*Math.abs(N),N+=T*s+k*u-(E*f+S*c),N>=C||-N>=C)return N;m=u*k,h=tu*u,d=h-(h-u),p=u-d,h=tu*k,g=h-(h-k),y=k-g,x=p*y-(m-d*g-p*g-d*y),w=c*S,h=tu*c,d=h-(h-c),p=c-d,h=tu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,uu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,uu[1]=b-(v+l)+(l-w),A=_+v,l=A-_,uu[2]=_-(A-l)+(v-l),uu[3]=A;const P=nu(4,ru,4,uu,iu);m=T*s,h=tu*T,d=h-(h-T),p=T-d,h=tu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=E*f,h=tu*E,d=h-(h-E),p=E-d,h=tu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,uu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,uu[1]=b-(v+l)+(l-w),A=_+v,l=A-_,uu[2]=_-(A-l)+(v-l),uu[3]=A;const z=nu(P,iu,4,uu,ou);m=u*s,h=tu*u,d=h-(h-u),p=u-d,h=tu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=c*f,h=tu*c,d=h-(h-c),p=c-d,h=tu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,uu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,uu[1]=b-(v+l)+(l-w),A=_+v,l=A-_,uu[2]=_-(A-l)+(v-l),uu[3]=A;const D=nu(z,ou,4,uu,au);return au[D-1]}(t,n,e,r,i,o,f)}const fu=Math.pow(2,-52),su=new Uint32Array(512);class lu{static from(t,n=vu,e=_u){const r=t.length,i=new Float64Array(2*r);for(let o=0;o<r;o++){const r=t[o];i[2*o]=n(r),i[2*o+1]=e(r)}return new lu(i)}constructor(t){const n=t.length>>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;n<o;n++){const e=t[2*n],r=t[2*n+1];e<a&&(a=e),r<u&&(u=r),e>c&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p,g=1/0;for(let n=0;n<o;n++){const e=hu(s,l,t[2*n],t[2*n+1]);e<g&&(h=n,g=e)}const y=t[2*h],v=t[2*h+1];g=1/0;for(let n=0;n<o;n++){if(n===h)continue;const e=hu(y,v,t[2*n],t[2*n+1]);e<g&&e>0&&(d=n,g=e)}let _=t[2*d],b=t[2*d+1],m=1/0;for(let n=0;n<o;n++){if(n===h||n===d)continue;const e=pu(y,v,_,b,t[2*n],t[2*n+1]);e<m&&(p=n,m=e)}let x=t[2*p],w=t[2*p+1];if(m===1/0){for(let n=0;n<o;n++)this._dists[n]=t[2*n]-t[0]||t[2*n+1]-t[1];gu(this._ids,this._dists,0,o-1);const n=new Uint32Array(o);let e=0;for(let t=0,r=-1/0;t<o;t++){const i=this._ids[t];this._dists[i]>r&&(n[e++]=i,r=this._dists[i])}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(cu(y,v,_,b,x,w)<0){const t=d,n=_,e=b;d=p,_=x,b=w,p=t,x=n,w=e}const M=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c);return{x:t+(f*s-u*l)*h,y:n+(a*l-c*s)*h}}(y,v,_,b,x,w);this._cx=M.x,this._cy=M.y;for(let n=0;n<o;n++)this._dists[n]=hu(t[2*n],t[2*n+1],M.x,M.y);gu(this._ids,this._dists,0,o-1),this._hullStart=h;let A=3;e[h]=n[p]=d,e[d]=n[h]=p,e[p]=n[d]=h,r[h]=0,r[d]=1,r[p]=2,i.fill(-1),i[this._hashKey(y,v)]=h,i[this._hashKey(_,b)]=d,i[this._hashKey(x,w)]=p,this.trianglesLen=0,this._addTriangle(h,d,p,-1,-1,-1);for(let o,a,u=0;u<this._ids.length;u++){const c=this._ids[u],f=t[2*c],s=t[2*c+1];if(u>0&&Math.abs(f-o)<=fu&&Math.abs(s-a)<=fu)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t<this._hashSize&&(l=i[(n+t)%this._hashSize],-1===l||l===e[l]);t++);l=n[l];let g,y=l;for(;g=e[y],cu(f,s,t[2*y],t[2*y+1],t[2*g],t[2*g+1])>=0;)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,A++;let _=e[y];for(;g=e[_],cu(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1])<0;)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,A--,_=g;if(y===l)for(;g=n[y],cu(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1])<0;)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,A--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(A);for(let t=0,n=this._hullStart;t<A;t++)this.hull[t]=n,n=e[n];this.triangles=this._triangles.subarray(0,this.trianglesLen),this.halfedges=this._halfedges.subarray(0,this.trianglesLen)}_hashKey(t,n){return Math.floor(function(t,n){const e=t/(Math.abs(t)+Math.abs(n));return(n>0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=su[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(du(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i<su.length&&(su[i++]=u)}else{if(0===i)break;t=su[--i]}}return o}_link(t,n){this._halfedges[t]=n,-1!==n&&(this._halfedges[n]=t)}_addTriangle(t,n,e,r,i,o){const a=this.trianglesLen;return this._triangles[a]=t,this._triangles[a+1]=n,this._triangles[a+2]=e,this._link(a,r),this._link(a+1,i),this._link(a+2,o),this.trianglesLen+=3,a}}function hu(t,n,e,r){const i=t-e,o=n-r;return i*i+o*o}function du(t,n,e,r,i,o,a,u){const c=t-a,f=n-u,s=e-a,l=r-u,h=i-a,d=o-u,p=s*s+l*l,g=h*h+d*d;return c*(l*g-p*d)-f*(s*g-p*h)+(c*c+f*f)*(s*d-l*h)<0}function pu(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=(f*s-u*l)*h,p=(a*l-c*s)*h;return d*d+p*p}function gu(t,n,e,r){if(r-e<=20)for(let i=e+1;i<=r;i++){const r=t[i],o=n[r];let a=i-1;for(;a>=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;yu(t,e+r>>1,i),n[t[e]]>n[t[r]]&&yu(t,e,r),n[t[i]]>n[t[r]]&&yu(t,i,r),n[t[e]]>n[t[i]]&&yu(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]<u);do{o--}while(n[t[o]]>u);if(o<i)break;yu(t,i,o)}t[e+1]=t[o],t[o]=a,r-i+1>=o-e?(gu(t,n,i,r),gu(t,n,e,o-1)):(gu(t,n,e,o-1),gu(t,n,i,r))}}function yu(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function vu(t){return t[0]}function _u(t){return t[1]}const bu=1e-6;class mu{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>bu||Math.abs(this._y1-i)>bu)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class xu{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class wu{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this,i=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let n,r,o=0,a=0,u=e.length;o<u;o+=3,a+=2){const u=2*e[o],c=2*e[o+1],f=2*e[o+2],s=t[u],l=t[u+1],h=t[c],d=t[c+1],p=t[f],g=t[f+1],y=h-s,v=d-l,_=p-s,b=g-l,m=2*(y*b-v*_);if(Math.abs(m)<1e-9){let i=1e9;const o=2*e[0];i*=Math.sign((t[o]-s)*b-(t[o+1]-l)*_),n=(s+p)/2-i*b,r=(l+g)/2+i*_}else{const t=1/m,e=y*y+v*v,i=_*_+b*b;n=s+(b*e-v*i)*t,r=l+(y*i-_*e)*t}i[a]=n,i[a+1]=r}let o,a,u,c=n[n.length-1],f=4*c,s=t[2*c],l=t[2*c+1];r.fill(0);for(let e=0;e<n.length;++e)c=n[e],o=f,a=s,u=l,f=4*c,s=t[2*c],l=t[2*c+1],r[o+2]=r[f]=u-l,r[o+3]=r[f+1]=s-a}render(t){const n=null==t?t=new mu:void 0,{delaunay:{halfedges:e,inedges:r,hull:i},circumcenters:o,vectors:a}=this;if(i.length<=1)return null;for(let n=0,r=e.length;n<r;++n){const r=e[n];if(r<n)continue;const i=2*Math.floor(n/3),a=2*Math.floor(r/3),u=o[i],c=o[i+1],f=o[a],s=o[a+1];this._renderSegment(u,c,f,s,t)}let u,c=i[i.length-1];for(let n=0;n<i.length;++n){u=c,c=i[n];const e=2*Math.floor(r[c]/3),f=o[e],s=o[e+1],l=4*u,h=this._project(f,s,a[l+2],a[l+3]);h&&this._renderSegment(f,s,h[0],h[1],t)}return n&&n.value()}renderBounds(t){const n=null==t?t=new mu:void 0;return t.rect(this.xmin,this.ymin,this.xmax-this.xmin,this.ymax-this.ymin),n&&n.value()}renderCell(t,n){const e=null==n?n=new mu:void 0,r=this._clip(t);if(null===r||!r.length)return;n.moveTo(r[0],r[1]);let i=r.length;for(;r[0]===r[i-2]&&r[1]===r[i-1]&&i>1;)i-=2;for(let t=2;t<i;t+=2)r[t]===r[t-2]&&r[t+1]===r[t-1]||n.lineTo(r[t],r[t+1]);return n.closePath(),e&&e.value()}*cellPolygons(){const{delaunay:{points:t}}=this;for(let n=0,e=t.length/2;n<e;++n){const t=this.cellPolygon(n);t&&(t.index=n,yield t)}}cellPolygon(t){const n=new xu;return this.renderCell(t,n),n.value()}_renderSegment(t,n,e,r,i){let o;const a=this._regioncode(t,n),u=this._regioncode(e,r);0===a&&0===u?(i.moveTo(t,n),i.lineTo(e,r)):(o=this._clipSegment(t,n,e,r,a,u))&&(i.moveTo(o[0],o[1]),i.lineTo(o[2],o[3]))}contains(t,n,e){return(n=+n)==n&&(e=+e)==e&&this.delaunay._step(t,n,e)===t}*neighbors(t){const n=this._clip(t);if(n)for(const e of this.delaunay.neighbors(t)){const t=this._clip(e);if(t)t:for(let r=0,i=n.length;r<i;r+=2)for(let o=0,a=t.length;o<a;o+=2)if(n[r]==t[o]&&n[r+1]==t[o+1]&&n[(r+2)%i]==t[(o+a-2)%a]&&n[(r+3)%i]==t[(o+a-1)%a]){yield e;break t}}}_cell(t){const{circumcenters:n,delaunay:{inedges:e,halfedges:r,triangles:i}}=this,o=e[t];if(-1===o)return null;const a=[];let u=o;do{const e=Math.floor(u/3);if(a.push(n[2*e],n[2*e+1]),u=u%3==2?u-2:u+1,i[u]!==t)break;u=r[u]}while(u!==o&&-1!==u);return a}_clip(t){if(0===t&&1===this.delaunay.hull.length)return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];const n=this._cell(t);if(null===n)return null;const{vectors:e}=this,r=4*t;return e[r]||e[r+1]?this._clipInfinite(t,n,e[r],e[r+1],e[r+2],e[r+3]):this._clipFinite(t,n)}_clipFinite(t,n){const e=n.length;let r,i,o,a,u=null,c=n[e-2],f=n[e-1],s=this._regioncode(c,f),l=0;for(let h=0;h<e;h+=2)if(r=c,i=f,c=n[h],f=n[h+1],o=s,s=this._regioncode(c,f),0===o&&0===s)a=l,l=0,u?u.push(c,f):u=[c,f];else{let n,e,h,d,p;if(0===o){if(null===(n=this._clipSegment(r,i,c,f,o,s)))continue;[e,h,d,p]=n}else{if(null===(n=this._clipSegment(c,f,r,i,s,o)))continue;[d,p,e,h]=n,a=l,l=this._edgecode(e,h),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(e,h):u=[e,h]}a=l,l=this._edgecode(d,p),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(d,p):u=[d,p]}if(u)a=l,l=this._edgecode(u[0],u[1]),a&&l&&this._edge(t,a,l,u,u.length);else if(this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2))return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];return u}_clipSegment(t,n,e,r,i,o){for(;;){if(0===i&&0===o)return[t,n,e,r];if(i&o)return null;let a,u,c=i||o;8&c?(a=t+(e-t)*(this.ymax-n)/(r-n),u=this.ymax):4&c?(a=t+(e-t)*(this.ymin-n)/(r-n),u=this.ymin):2&c?(u=n+(r-n)*(this.xmax-t)/(e-t),a=this.xmax):(u=n+(r-n)*(this.xmin-t)/(e-t),a=this.xmin),i?(t=a,n=u,i=this._regioncode(t,n)):(e=a,r=u,o=this._regioncode(e,r))}}_clipInfinite(t,n,e,r,i,o){let a,u=Array.from(n);if((a=this._project(u[0],u[1],e,r))&&u.unshift(a[0],a[1]),(a=this._project(u[u.length-2],u[u.length-1],i,o))&&u.push(a[0],a[1]),u=this._clipFinite(t,u))for(let n,e=0,r=u.length,i=this._edgecode(u[r-2],u[r-1]);e<r;e+=2)n=i,i=this._edgecode(u[e],u[e+1]),n&&i&&(e=this._edge(t,n,i,u,e),r=u.length);else this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2)&&(u=[this.xmin,this.ymin,this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax]);return u}_edge(t,n,e,r,i){for(;n!==e;){let e,o;switch(n){case 5:n=4;continue;case 4:n=6,e=this.xmax,o=this.ymin;break;case 6:n=2;continue;case 2:n=10,e=this.xmax,o=this.ymax;break;case 10:n=8;continue;case 8:n=9,e=this.xmin,o=this.ymax;break;case 9:n=1;continue;case 1:n=5,e=this.xmin,o=this.ymin}r[i]===e&&r[i+1]===o||!this.contains(t,e,o)||(r.splice(i,0,e,o),i+=2)}if(r.length>4)for(let t=0;t<r.length;t+=2){const n=(t+2)%r.length,e=(t+4)%r.length;(r[t]===r[n]&&r[n]===r[e]||r[t+1]===r[n+1]&&r[n+1]===r[e+1])&&(r.splice(n,2),t-=2)}return i}_project(t,n,e,r){let i,o,a,u=1/0;if(r<0){if(n<=this.ymin)return null;(i=(this.ymin-n)/r)<u&&(a=this.ymin,o=t+(u=i)*e)}else if(r>0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)<u&&(a=this.ymax,o=t+(u=i)*e)}if(e>0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)<u&&(o=this.xmax,a=n+(u=i)*r)}else if(e<0){if(t<=this.xmin)return null;(i=(this.xmin-t)/e)<u&&(o=this.xmin,a=n+(u=i)*r)}return[o,a]}_edgecode(t,n){return(t===this.xmin?1:t===this.xmax?2:0)|(n===this.ymin?4:n===this.ymax?8:0)}_regioncode(t,n){return(t<this.xmin?1:t>this.xmax?2:0)|(n<this.ymin?4:n>this.ymax?8:0)}}const Mu=2*Math.PI,Au=Math.pow;function Tu(t){return t[0]}function Su(t){return t[1]}function Eu(t,n,e){return[t+Math.sin(t+n)*e,n+Math.cos(t-n)*e]}class ku{static from(t,n=Tu,e=Su,r){return new ku("length"in t?function(t,n,e,r){const i=t.length,o=new Float64Array(2*i);for(let a=0;a<i;++a){const i=t[a];o[2*a]=n.call(r,i,a,t),o[2*a+1]=e.call(r,i,a,t)}return o}(t,n,e,r):Float64Array.from(function*(t,n,e,r){let i=0;for(const o of t)yield n.call(r,o,i,t),yield e.call(r,o,i,t),++i}(t,n,e,r)))}constructor(t){this._delaunator=new lu(t),this.inedges=new Int32Array(t.length/2),this._hullIndex=new Int32Array(t.length/2),this.points=this._delaunator.coords,this._init()}update(){return this._delaunator.update(),this._init(),this}_init(){const t=this._delaunator,n=this.points;if(t.hull&&t.hull.length>2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t<n.length;t+=3){const r=2*n[t],i=2*n[t+1],o=2*n[t+2];if((e[o]-e[r])*(e[i+1]-e[r+1])-(e[i]-e[r])*(e[o+1]-e[r+1])>1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},((t,n)=>n)).sort(((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]));const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t<e;++t){const e=Eu(n[2*t],n[2*t+1],i);n[2*t]=e[0],n[2*t+1]=e[1]}this._delaunator=new lu(n)}else delete this.collinear;const e=this.halfedges=this._delaunator.halfedges,r=this.hull=this._delaunator.hull,i=this.triangles=this._delaunator.triangles,o=this.inedges.fill(-1),a=this._hullIndex.fill(-1);for(let t=0,n=e.length;t<n;++t){const n=i[t%3==2?t-2:t+1];-1!==e[t]&&-1!==o[n]||(o[n]=t)}for(let t=0,n=r.length;t<n;++t)a[r[t]]=t;r.length<=2&&r.length>0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],o[r[0]]=1,2===r.length&&(o[r[1]]=0,this.triangles[1]=r[1],this.triangles[2]=r[1]))}voronoi(t){return new wu(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n<a.length-1&&(yield a[n+1]))}const u=n[t];if(-1===u)return;let c=u,f=-1;do{if(yield f=o[c],c=c%3==2?c-2:c+1,o[c]!==t)return;if(c=i[c],-1===c){const n=e[(r[t]+1)%e.length];return void(n!==f&&(yield n))}}while(c!==u)}find(t,n,e=0){if((t=+t)!=t||(n=+n)!=n)return-1;const r=e;let i;for(;(i=this._step(e,t,n))>=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=Au(n-c[2*t],2)+Au(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=Au(n-c[2*r],2)+Au(e-c[2*r+1],2);if(l<s&&(s=l,f=r),h=h%3==2?h-2:h+1,u[h]!==t)break;if(h=a[h],-1===h){if(h=i[(o[t]+1)%i.length],h!==r&&Au(n-c[2*h],2)+Au(e-c[2*h+1],2)<s)return h;break}}while(h!==l);return f}render(t){const n=null==t?t=new mu:void 0,{points:e,halfedges:r,triangles:i}=this;for(let n=0,o=r.length;n<o;++n){const o=r[n];if(o<n)continue;const a=2*i[n],u=2*i[o];t.moveTo(e[a],e[a+1]),t.lineTo(e[u],e[u+1])}return this.renderHull(t),n&&n.value()}renderPoints(t,n){void 0!==n||t&&"function"==typeof t.moveTo||(n=t,t=null),n=null==n?2:+n;const e=null==t?t=new mu:void 0,{points:r}=this;for(let e=0,i=r.length;e<i;e+=2){const i=r[e],o=r[e+1];t.moveTo(i+n,o),t.arc(i,o,n,0,Mu)}return e&&e.value()}renderHull(t){const n=null==t?t=new mu:void 0,{hull:e,points:r}=this,i=2*e[0],o=e.length;t.moveTo(r[i],r[i+1]);for(let n=1;n<o;++n){const i=2*e[n];t.lineTo(r[i],r[i+1])}return t.closePath(),n&&n.value()}hullPolygon(){const t=new xu;return this.renderHull(t),t.value()}renderTriangle(t,n){const e=null==n?n=new mu:void 0,{points:r,triangles:i}=this,o=2*i[t*=3],a=2*i[t+1],u=2*i[t+2];return n.moveTo(r[o],r[o+1]),n.lineTo(r[a],r[a+1]),n.lineTo(r[u],r[u+1]),n.closePath(),e&&e.value()}*trianglePolygons(){const{triangles:t}=this;for(let n=0,e=t.length/3;n<e;++n)yield this.trianglePolygon(n)}trianglePolygon(t){const n=new xu;return this.renderTriangle(t,n),n.value()}}var Nu={},Cu={};function Pu(t){return new Function("d","return {"+t.map((function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'})).join(",")+"}")}function zu(t){var n=Object.create(null),e=[];return t.forEach((function(t){for(var r in t)r in n||e.push(n[r]=r)})),e}function Du(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Ru(t){var n=t.getUTCHours(),e=t.getUTCMinutes(),r=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":function(t){return t<0?"-"+Du(-t,6):t>9999?"+"+Du(t,6):Du(t,4)}(t.getUTCFullYear())+"-"+Du(t.getUTCMonth()+1,2)+"-"+Du(t.getUTCDate(),2)+(i?"T"+Du(n,2)+":"+Du(e,2)+":"+Du(r,2)+"."+Du(i,3)+"Z":r?"T"+Du(n,2)+":"+Du(e,2)+":"+Du(r,2)+"Z":e||n?"T"+Du(n,2)+":"+Du(e,2)+"Z":"")}function Fu(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Cu;if(f)return f=!1,Nu;var n,r,i=a;if(34===t.charCodeAt(i)){for(;a++<o&&34!==t.charCodeAt(a)||34===t.charCodeAt(++a););return(n=a)>=o?c=!0:10===(r=t.charCodeAt(a++))?f=!0:13===r&&(f=!0,10===t.charCodeAt(a)&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if(10===(r=t.charCodeAt(n=a++)))f=!0;else if(13===r)f=!0,10===t.charCodeAt(a)&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(10===t.charCodeAt(o-1)&&--o,13===t.charCodeAt(o-1)&&--o;(r=s())!==Cu;){for(var l=[];r!==Nu&&r!==Cu;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map((function(n){return e.map((function(t){return a(n[t])})).join(t)}))}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Ru(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,(function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Pu(t);return function(r,i){return n(e(r),i,t)}}(t,n):Pu(t)}));return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=zu(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=zu(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var qu=Fu(","),Iu=qu.parse,Ou=qu.parseRows,Uu=qu.format,Bu=qu.formatBody,Yu=qu.formatRows,Lu=qu.formatRow,ju=qu.formatValue,$u=Fu("\t"),Hu=$u.parse,Xu=$u.parseRows,Gu=$u.format,Vu=$u.formatBody,Wu=$u.formatRows,Zu=$u.formatRow,Ku=$u.formatValue;const Qu=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function Ju(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function tc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function nc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function ec(t,n){return fetch(t,n).then(nc)}function rc(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),ec(n,e).then((function(n){return t(n,r)}))}}var ic=rc(Iu),oc=rc(Hu);function ac(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function uc(t){return(n,e)=>ec(n,e).then((n=>(new DOMParser).parseFromString(n,t)))}var cc=uc("application/xml"),fc=uc("text/html"),sc=uc("image/svg+xml");function lc(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function hc(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function dc(t){return t[0]}function pc(t){return t[1]}function gc(t,n,e){var r=new yc(null==n?dc:n,null==e?pc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function yc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function vc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var _c=gc.prototype=yc.prototype;function bc(t){return function(){return t}}function mc(t){return 1e-6*(t()-.5)}function xc(t){return t.x+t.vx}function wc(t){return t.y+t.vy}function Mc(t){return t.index}function Ac(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}_c.copy=function(){var t,n,e=new yc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=vc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=vc(n));return e},_c.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return lc(this.cover(n,e),n,e,t)},_c.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)lc(this,a[e],u[e],t[e]);return this},_c.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e||1,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},_c.data=function(){var t=[];return this.visit((function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)})),t},_c.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},_c.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],g=this._root;for(g&&p.push(new hc(g,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(g=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(g.length){var y=(i+a)/2,v=(o+u)/2;p.push(new hc(g[3],y,v,a,u),new hc(g[2],i,v,y,u),new hc(g[1],y,o,a,v),new hc(g[0],i,o,y,v)),(f=(n>=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=g.data}}return r},_c.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,g=this._y0,y=this._x1,v=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},_c.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},_c.root=function(){return this._root},_c.size=function(){var t=0;return this.visit((function(n){if(!n.length)do{++t}while(n=n.next)})),t},_c.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new hc(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new hc(e,f,s,o,a)),(e=c[2])&&u.push(new hc(e,r,s,f,a)),(e=c[1])&&u.push(new hc(e,f,i,o,s)),(e=c[0])&&u.push(new hc(e,r,i,f,s))}return this},_c.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new hc(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new hc(o,a,u,s,l)),(o=i[1])&&e.push(new hc(o,s,u,c,l)),(o=i[2])&&e.push(new hc(o,a,l,s,f)),(o=i[3])&&e.push(new hc(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},_c.x=function(t){return arguments.length?(this._x=t,this):this._x},_c.y=function(t){return arguments.length?(this._y=t,this):this._y};const Tc=4294967296;function Sc(t){return t.x}function Ec(t){return t.y}var kc=Math.PI*(3-Math.sqrt(5));function Nc(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Cc(t){return(t=Nc(Math.abs(t)))?t[1]:NaN}var Pc,zc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Dc(t){if(!(n=zc.exec(t)))throw new Error("invalid format: "+t);var n;return new Rc({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Rc(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Fc(t,n){var e=Nc(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Dc.prototype=Rc.prototype,Rc.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var qc={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>Fc(100*t,n),r:Fc,s:function(t,n){var e=Nc(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Pc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Nc(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Ic(t){return t}var Oc,Uc=Array.prototype.map,Bc=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Yc(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?Ic:(n=Uc.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?Ic:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(Uc.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Dc(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):qc[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=qc[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var A=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),A&&0==+t&&"+"!==l&&(A=!1),h=(A?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?Bc[8+Pc/3]:"")+M+(A&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var T=h.length+t.length+M.length,S=T<p?new Array(p-T+1).join(n):"";switch(g&&d&&(t=r(S+t,S.length?p-M.length:1/0),S=""),e){case"<":t=h+t+M+S;break;case"=":t=h+S+t+M;break;case"^":t=S.slice(0,T=S.length>>1)+h+t+M+S.slice(T);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Dc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Cc(n)/3))),i=Math.pow(10,-r),o=Bc[8+r/3];return function(t){return e(i*t)+o}}}}function Lc(n){return Oc=Yc(n),t.format=Oc.format,t.formatPrefix=Oc.formatPrefix,Oc}function jc(t){return Math.max(0,-Cc(Math.abs(t)))}function $c(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Cc(n)/3)))-Cc(Math.abs(t)))}function Hc(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Cc(n)-Cc(t))+1}t.format=void 0,t.formatPrefix=void 0,Lc({thousands:",",grouping:[3],currency:["$",""]});var Xc=1e-6,Gc=1e-12,Vc=Math.PI,Wc=Vc/2,Zc=Vc/4,Kc=2*Vc,Qc=180/Vc,Jc=Vc/180,tf=Math.abs,nf=Math.atan,ef=Math.atan2,rf=Math.cos,of=Math.ceil,af=Math.exp,uf=Math.hypot,cf=Math.log,ff=Math.pow,sf=Math.sin,lf=Math.sign||function(t){return t>0?1:t<0?-1:0},hf=Math.sqrt,df=Math.tan;function pf(t){return t>1?0:t<-1?Vc:Math.acos(t)}function gf(t){return t>1?Wc:t<-1?-Wc:Math.asin(t)}function yf(t){return(t=sf(t/2))*t}function vf(){}function _f(t,n){t&&mf.hasOwnProperty(t.type)&&mf[t.type](t,n)}var bf={Feature:function(t,n){_f(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)_f(e[r].geometry,n)}},mf={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){xf(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)xf(e[r],n,0)},Polygon:function(t,n){wf(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)wf(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)_f(e[r],n)}};function xf(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function wf(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)xf(t[e],n,1);n.polygonEnd()}function Mf(t,n){t&&bf.hasOwnProperty(t.type)?bf[t.type](t,n):_f(t,n)}var Af,Tf,Sf,Ef,kf,Nf,Cf,Pf,zf,Df,Rf,Ff,qf,If,Of,Uf,Bf=new T,Yf=new T,Lf={point:vf,lineStart:vf,lineEnd:vf,polygonStart:function(){Bf=new T,Lf.lineStart=jf,Lf.lineEnd=$f},polygonEnd:function(){var t=+Bf;Yf.add(t<0?Kc+t:t),this.lineStart=this.lineEnd=this.point=vf},sphere:function(){Yf.add(Kc)}};function jf(){Lf.point=Hf}function $f(){Xf(Af,Tf)}function Hf(t,n){Lf.point=Xf,Af=t,Tf=n,Sf=t*=Jc,Ef=rf(n=(n*=Jc)/2+Zc),kf=sf(n)}function Xf(t,n){var e=(t*=Jc)-Sf,r=e>=0?1:-1,i=r*e,o=rf(n=(n*=Jc)/2+Zc),a=sf(n),u=kf*a,c=Ef*o+u*rf(i),f=u*r*sf(i);Bf.add(ef(f,c)),Sf=t,Ef=o,kf=a}function Gf(t){return[ef(t[1],t[0]),gf(t[2])]}function Vf(t){var n=t[0],e=t[1],r=rf(e);return[r*rf(n),r*sf(n),sf(e)]}function Wf(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Zf(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Kf(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Qf(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Jf(t){var n=hf(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var ts,ns,es,rs,is,os,as,us,cs,fs,ss,ls,hs,ds,ps,gs,ys={point:vs,lineStart:bs,lineEnd:ms,polygonStart:function(){ys.point=xs,ys.lineStart=ws,ys.lineEnd=Ms,If=new T,Lf.polygonStart()},polygonEnd:function(){Lf.polygonEnd(),ys.point=vs,ys.lineStart=bs,ys.lineEnd=ms,Bf<0?(Nf=-(Pf=180),Cf=-(zf=90)):If>Xc?zf=90:If<-1e-6&&(Cf=-90),Uf[0]=Nf,Uf[1]=Pf},sphere:function(){Nf=-(Pf=180),Cf=-(zf=90)}};function vs(t,n){Of.push(Uf=[Nf=t,Pf=t]),n<Cf&&(Cf=n),n>zf&&(zf=n)}function _s(t,n){var e=Vf([t*Jc,n*Jc]);if(qf){var r=Zf(qf,e),i=Zf([r[1],-r[0],0],r);Jf(i),i=Gf(i);var o,a=t-Df,u=a>0?1:-1,c=i[0]*Qc*u,f=tf(a)>180;f^(u*Df<c&&c<u*t)?(o=i[1]*Qc)>zf&&(zf=o):f^(u*Df<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*Qc)<Cf&&(Cf=o):(n<Cf&&(Cf=n),n>zf&&(zf=n)),f?t<Df?As(Nf,t)>As(Nf,Pf)&&(Pf=t):As(t,Pf)>As(Nf,Pf)&&(Nf=t):Pf>=Nf?(t<Nf&&(Nf=t),t>Pf&&(Pf=t)):t>Df?As(Nf,t)>As(Nf,Pf)&&(Pf=t):As(t,Pf)>As(Nf,Pf)&&(Nf=t)}else Of.push(Uf=[Nf=t,Pf=t]);n<Cf&&(Cf=n),n>zf&&(zf=n),qf=e,Df=t}function bs(){ys.point=_s}function ms(){Uf[0]=Nf,Uf[1]=Pf,ys.point=vs,qf=null}function xs(t,n){if(qf){var e=t-Df;If.add(tf(e)>180?e+(e>0?360:-360):e)}else Rf=t,Ff=n;Lf.point(t,n),_s(t,n)}function ws(){Lf.lineStart()}function Ms(){xs(Rf,Ff),Lf.lineEnd(),tf(If)>Xc&&(Nf=-(Pf=180)),Uf[0]=Nf,Uf[1]=Pf,qf=null}function As(t,n){return(n-=t)<0?n+360:n}function Ts(t,n){return t[0]-n[0]}function Ss(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Es={sphere:vf,point:ks,lineStart:Cs,lineEnd:Ds,polygonStart:function(){Es.lineStart=Rs,Es.lineEnd=Fs},polygonEnd:function(){Es.lineStart=Cs,Es.lineEnd=Ds}};function ks(t,n){t*=Jc;var e=rf(n*=Jc);Ns(e*rf(t),e*sf(t),sf(n))}function Ns(t,n,e){++ts,es+=(t-es)/ts,rs+=(n-rs)/ts,is+=(e-is)/ts}function Cs(){Es.point=Ps}function Ps(t,n){t*=Jc;var e=rf(n*=Jc);ds=e*rf(t),ps=e*sf(t),gs=sf(n),Es.point=zs,Ns(ds,ps,gs)}function zs(t,n){t*=Jc;var e=rf(n*=Jc),r=e*rf(t),i=e*sf(t),o=sf(n),a=ef(hf((a=ps*o-gs*i)*a+(a=gs*r-ds*o)*a+(a=ds*i-ps*r)*a),ds*r+ps*i+gs*o);ns+=a,os+=a*(ds+(ds=r)),as+=a*(ps+(ps=i)),us+=a*(gs+(gs=o)),Ns(ds,ps,gs)}function Ds(){Es.point=ks}function Rs(){Es.point=qs}function Fs(){Is(ls,hs),Es.point=ks}function qs(t,n){ls=t,hs=n,t*=Jc,n*=Jc,Es.point=Is;var e=rf(n);ds=e*rf(t),ps=e*sf(t),gs=sf(n),Ns(ds,ps,gs)}function Is(t,n){t*=Jc;var e=rf(n*=Jc),r=e*rf(t),i=e*sf(t),o=sf(n),a=ps*o-gs*i,u=gs*r-ds*o,c=ds*i-ps*r,f=uf(a,u,c),s=gf(f),l=f&&-s/f;cs.add(l*a),fs.add(l*u),ss.add(l*c),ns+=s,os+=s*(ds+(ds=r)),as+=s*(ps+(ps=i)),us+=s*(gs+(gs=o)),Ns(ds,ps,gs)}function Os(t){return function(){return t}}function Us(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Bs(t,n){return[tf(t)>Vc?t+Math.round(-t/Kc)*Kc:t,n]}function Ys(t,n,e){return(t%=Kc)?n||e?Us(js(t),$s(n,e)):js(t):n||e?$s(n,e):Bs}function Ls(t){return function(n,e){return[(n+=t)>Vc?n-Kc:n<-Vc?n+Kc:n,e]}}function js(t){var n=Ls(t);return n.invert=Ls(-t),n}function $s(t,n){var e=rf(t),r=sf(t),i=rf(n),o=sf(n);function a(t,n){var a=rf(n),u=rf(t)*a,c=sf(t)*a,f=sf(n),s=f*e+u*r;return[ef(c*i-s*o,u*e-f*r),gf(s*i+c*o)]}return a.invert=function(t,n){var a=rf(n),u=rf(t)*a,c=sf(t)*a,f=sf(n),s=f*i-c*o;return[ef(c*i+f*o,u*e+s*r),gf(s*e-u*r)]},a}function Hs(t){function n(n){return(n=t(n[0]*Jc,n[1]*Jc))[0]*=Qc,n[1]*=Qc,n}return t=Ys(t[0]*Jc,t[1]*Jc,t.length>2?t[2]*Jc:0),n.invert=function(n){return(n=t.invert(n[0]*Jc,n[1]*Jc))[0]*=Qc,n[1]*=Qc,n},n}function Xs(t,n,e,r,i,o){if(e){var a=rf(n),u=sf(n),c=r*e;null==i?(i=n+r*Kc,o=n-c/2):(i=Gs(a,i),o=Gs(a,o),(r>0?i<o:i>o)&&(i+=r*Kc));for(var f,s=i;r>0?s>o:s<o;s-=c)f=Gf([a,-u*rf(s),-u*sf(s)]),t.point(f[0],f[1])}}function Gs(t,n){(n=Vf(n))[0]-=t,Jf(n);var e=pf(-n[1]);return((-n[2]<0?-e:e)+Kc-Xc)%Kc}function Vs(){var t,n=[];return{point:function(n,e,r){t.push([n,e,r])},lineStart:function(){n.push(t=[])},lineEnd:vf,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function Ws(t,n){return tf(t[0]-n[0])<Xc&&tf(t[1]-n[1])<Xc}function Zs(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Ks(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach((function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(Ws(r,a)){if(!r[2]&&!a[2]){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a[0]+=2e-6}u.push(e=new Zs(r,t,null,!0)),c.push(e.o=new Zs(r,null,e,!1)),u.push(e=new Zs(a,t,null,!1)),c.push(e.o=new Zs(a,null,e,!0))}})),u.length){for(c.sort(n),Qs(u),Qs(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function Qs(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Js(t){return tf(t[0])<=Vc?t[0]:lf(t[0])*((tf(t[0])+Vc)%Kc-Vc)}function tl(t,n){var e=Js(n),r=n[1],i=sf(r),o=[sf(e),-rf(e),0],a=0,u=0,c=new T;1===i?r=Wc+Xc:-1===i&&(r=-Wc-Xc);for(var f=0,s=t.length;f<s;++f)if(h=(l=t[f]).length)for(var l,h,d=l[h-1],p=Js(d),g=d[1]/2+Zc,y=sf(g),v=rf(g),_=0;_<h;++_,p=m,y=w,v=M,d=b){var b=l[_],m=Js(b),x=b[1]/2+Zc,w=sf(x),M=rf(x),A=m-p,S=A>=0?1:-1,E=S*A,k=E>Vc,N=y*w;if(c.add(ef(N*S*sf(E),v*M+N*rf(E))),a+=k?A+S*Kc:A,k^p>=e^m>=e){var C=Zf(Vf(d),Vf(b));Jf(C);var P=Zf(o,C);Jf(P);var z=(k^A>=0?-1:1)*gf(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=k^A>=0?1:-1)}}return(a<-1e-6||a<Xc&&c<-1e-12)^1&u}function nl(t,n,e,r){return function(i){var o,a,u,c=n(i),f=Vs(),s=n(f),l=!1,h={point:d,lineStart:g,lineEnd:y,polygonStart:function(){h.point=v,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=g,h.lineEnd=y,a=ft(a);var t=tl(o,r);a.length?(l||(i.polygonStart(),l=!0),Ks(a,rl,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function g(){h.point=p,c.lineStart()}function y(){h.point=d,c.lineEnd()}function v(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){v(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(el))}return h}}function el(t){return t.length>1}function rl(t,n){return((t=t.x)[0]<0?t[1]-Wc-Xc:Wc-t[1])-((n=n.x)[0]<0?n[1]-Wc-Xc:Wc-n[1])}Bs.invert=Bs;var il=nl((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?Vc:-Vc,c=tf(o-e);tf(c-Vc)<Xc?(t.point(e,r=(r+a)/2>0?Wc:-Wc),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=Vc&&(tf(e-i)<Xc&&(e-=i*Xc),tf(o-u)<Xc&&(o-=u*Xc),r=function(t,n,e,r){var i,o,a=sf(t-e);return tf(a)>Xc?nf((sf(n)*(o=rf(r))*sf(e)-sf(r)*(i=rf(n))*sf(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*Wc,r.point(-Vc,i),r.point(0,i),r.point(Vc,i),r.point(Vc,0),r.point(Vc,-i),r.point(0,-i),r.point(-Vc,-i),r.point(-Vc,0),r.point(-Vc,i);else if(tf(t[0]-n[0])>Xc){var o=t[0]<n[0]?Vc:-Vc;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}),[-Vc,-Wc]);function ol(t){var n=rf(t),e=6*Jc,r=n>0,i=tf(n)>Xc;function o(t,e){return rf(t)*rf(e)>n}function a(t,e,r){var i=[1,0,0],o=Zf(Vf(t),Vf(e)),a=Wf(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=Zf(i,o),h=Qf(i,f);Kf(h,Qf(o,s));var d=l,p=Wf(h,d),g=Wf(d,d),y=p*p-g*(Wf(h,h)-1);if(!(y<0)){var v=hf(y),_=Qf(d,(-p-v)/g);if(Kf(_,h),_=Gf(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var A=x-m,T=tf(A-Vc)<Xc;if(!T&&M<w&&(b=w,w=M,M=b),T||A<Xc?T?w+M>0^_[1]<(tf(_[0]-m)<Xc?w:M):w<=_[1]&&_[1]<=M:A>Vc^(m<=_[0]&&_[0]<=x)){var S=Qf(d,(-p+v)/g);return Kf(S,h),[_,Gf(S)]}}}function u(n,e){var i=r?t:Vc-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return nl(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?Vc:-Vc),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||Ws(n,d)||Ws(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&Ws(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){Xs(o,t,e,i,n,r)}),r?[0,-t]:[-Vc,t-Vc])}var al,ul,cl,fl,sl=1e9,ll=-sl;function hl(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return tf(r[0]-t)<Xc?i>0?0:3:tf(r[0]-e)<Xc?i>0?2:1:tf(r[1]-n)<Xc?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=Vs(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,h=(l=u[c])[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=ft(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&Ks(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(ll,Math.min(sl,p)),g=Math.max(ll,Math.min(sl,g))],m=[o=Math.max(ll,Math.min(sl,o)),a=Math.max(ll,Math.min(sl,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var dl={sphere:vf,point:vf,lineStart:function(){dl.point=gl,dl.lineEnd=pl},lineEnd:vf,polygonStart:vf,polygonEnd:vf};function pl(){dl.point=dl.lineEnd=vf}function gl(t,n){ul=t*=Jc,cl=sf(n*=Jc),fl=rf(n),dl.point=yl}function yl(t,n){t*=Jc;var e=sf(n*=Jc),r=rf(n),i=tf(t-ul),o=rf(i),a=r*sf(i),u=fl*e-cl*r*o,c=cl*e+fl*r*o;al.add(ef(hf(a*a+u*u),c)),ul=t,cl=e,fl=r}function vl(t){return al=new T,Mf(t,dl),+al}var _l=[null,null],bl={type:"LineString",coordinates:_l};function ml(t,n){return _l[0]=t,_l[1]=n,vl(bl)}var xl={Feature:function(t,n){return Ml(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(Ml(e[r].geometry,n))return!0;return!1}},wl={Sphere:function(){return!0},Point:function(t,n){return Al(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Al(e[r],n))return!0;return!1},LineString:function(t,n){return Tl(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Tl(e[r],n))return!0;return!1},Polygon:function(t,n){return Sl(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Sl(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(Ml(e[r],n))return!0;return!1}};function Ml(t,n){return!(!t||!wl.hasOwnProperty(t.type))&&wl[t.type](t,n)}function Al(t,n){return 0===ml(t,n)}function Tl(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=ml(t[o],n)))return!0;if(o>0&&(i=ml(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<Gc*i)return!0;e=r}return!1}function Sl(t,n){return!!tl(t.map(El),kl(n))}function El(t){return(t=t.map(kl)).pop(),t}function kl(t){return[t[0]*Jc,t[1]*Jc]}function Nl(t,n,e){var r=lt(t,n-Xc,e).concat(n);return function(t){return r.map((function(n){return[t,n]}))}}function Cl(t,n,e){var r=lt(t,n-Xc,e).concat(n);return function(t){return r.map((function(n){return[n,t]}))}}function Pl(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,g=360,y=2.5;function v(){return{type:"MultiLineString",coordinates:_()}}function _(){return lt(of(r/p)*p,e,p).map(s).concat(lt(of(u/g)*g,a,g).map(l)).concat(lt(of(n/h)*h,t,h).filter((function(t){return tf(t%p)>Xc})).map(c)).concat(lt(of(o/d)*d,i,d).filter((function(t){return tf(t%g)>Xc})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Nl(o,i,90),f=Cl(n,t,y),s=Nl(u,a,90),l=Cl(r,e,y),v):y},v.extentMajor([[-180,-89.999999],[180,89.999999]]).extentMinor([[-180,-80.000001],[180,80.000001]])}var zl,Dl,Rl,Fl,ql=t=>t,Il=new T,Ol=new T,Ul={point:vf,lineStart:vf,lineEnd:vf,polygonStart:function(){Ul.lineStart=Bl,Ul.lineEnd=jl},polygonEnd:function(){Ul.lineStart=Ul.lineEnd=Ul.point=vf,Il.add(tf(Ol)),Ol=new T},result:function(){var t=Il/2;return Il=new T,t}};function Bl(){Ul.point=Yl}function Yl(t,n){Ul.point=Ll,zl=Rl=t,Dl=Fl=n}function Ll(t,n){Ol.add(Fl*t-Rl*n),Rl=t,Fl=n}function jl(){Ll(zl,Dl)}var $l=Ul,Hl=1/0,Xl=Hl,Gl=-Hl,Vl=Gl,Wl={point:function(t,n){t<Hl&&(Hl=t);t>Gl&&(Gl=t);n<Xl&&(Xl=n);n>Vl&&(Vl=n)},lineStart:vf,lineEnd:vf,polygonStart:vf,polygonEnd:vf,result:function(){var t=[[Hl,Xl],[Gl,Vl]];return Gl=Vl=-(Xl=Hl=1/0),t}};var Zl,Kl,Ql,Jl,th=Wl,nh=0,eh=0,rh=0,ih=0,oh=0,ah=0,uh=0,ch=0,fh=0,sh={point:lh,lineStart:hh,lineEnd:gh,polygonStart:function(){sh.lineStart=yh,sh.lineEnd=vh},polygonEnd:function(){sh.point=lh,sh.lineStart=hh,sh.lineEnd=gh},result:function(){var t=fh?[uh/fh,ch/fh]:ah?[ih/ah,oh/ah]:rh?[nh/rh,eh/rh]:[NaN,NaN];return nh=eh=rh=ih=oh=ah=uh=ch=fh=0,t}};function lh(t,n){nh+=t,eh+=n,++rh}function hh(){sh.point=dh}function dh(t,n){sh.point=ph,lh(Ql=t,Jl=n)}function ph(t,n){var e=t-Ql,r=n-Jl,i=hf(e*e+r*r);ih+=i*(Ql+t)/2,oh+=i*(Jl+n)/2,ah+=i,lh(Ql=t,Jl=n)}function gh(){sh.point=lh}function yh(){sh.point=_h}function vh(){bh(Zl,Kl)}function _h(t,n){sh.point=bh,lh(Zl=Ql=t,Kl=Jl=n)}function bh(t,n){var e=t-Ql,r=n-Jl,i=hf(e*e+r*r);ih+=i*(Ql+t)/2,oh+=i*(Jl+n)/2,ah+=i,uh+=(i=Jl*t-Ql*n)*(Ql+t),ch+=i*(Jl+n),fh+=3*i,lh(Ql=t,Jl=n)}var mh=sh;function xh(t){this._context=t}xh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Kc)}},result:vf};var wh,Mh,Ah,Th,Sh,Eh=new T,kh={point:vf,lineStart:function(){kh.point=Nh},lineEnd:function(){wh&&Ch(Mh,Ah),kh.point=vf},polygonStart:function(){wh=!0},polygonEnd:function(){wh=null},result:function(){var t=+Eh;return Eh=new T,t}};function Nh(t,n){kh.point=Ch,Mh=Th=t,Ah=Sh=n}function Ch(t,n){Th-=t,Sh-=n,Eh.add(hf(Th*Th+Sh*Sh)),Th=t,Sh=n}var Ph=kh;function zh(){this._string=[]}function Dh(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Rh(t){return function(n){var e=new Fh;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Fh(){}function qh(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Mf(e,t.stream(th)),n(th.result()),null!=r&&t.clipExtent(r),t}function Ih(t,n,e){return qh(t,(function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])}),e)}function Oh(t,n,e){return Ih(t,[[0,0],n],e)}function Uh(t,n,e){return qh(t,(function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])}),e)}function Bh(t,n,e){return qh(t,(function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])}),e)}zh.prototype={_radius:4.5,_circle:Dh(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Dh(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Fh.prototype={constructor:Fh,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Yh=rf(30*Jc);function Lh(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,g,y){var v=f-r,_=s-i,b=v*v+_*_;if(b>4*n&&g--){var m=a+h,x=u+d,w=c+p,M=hf(m*m+x*x+w*w),A=gf(w/=M),T=tf(tf(w)-1)<Xc||tf(o-l)<Xc?(o+l)/2:ef(x,m),S=t(T,A),E=S[0],k=S[1],N=E-r,C=k-i,P=_*N-v*C;(P*P/b>n||tf((v*N+_*C)/b-.5)>.3||a*h+u*d+c*p<Yh)&&(e(r,i,o,a,u,c,E,k,T,m/=M,x/=M,w,g,y),y.point(E,k),e(E,k,T,m,x,w,f,s,l,h,d,p,g,y))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,g={point:y,lineStart:v,lineEnd:b,polygonStart:function(){n.polygonStart(),g.lineStart=m},polygonEnd:function(){n.polygonEnd(),g.lineStart=v}};function y(e,r){e=t(e,r),n.point(e[0],e[1])}function v(){s=NaN,g.point=_,n.lineStart()}function _(r,i){var o=Vf([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],16,n),n.point(s,l)}function b(){g.point=y,n.lineEnd()}function m(){v(),g.point=x,g.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,g.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,16,n),g.lineEnd=b,b()}return g}}(t,n):function(t){return Rh({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var jh=Rh({point:function(t,n){this.stream.point(t*Jc,n*Jc)}});function $h(t,n,e,r,i,o){if(!o)return function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o}(t,n,e,r,i);var a=rf(o),u=sf(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function Hh(t){return Xh((function(){return t}))()}function Xh(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,g=0,y=0,v=0,_=0,b=0,m=1,x=1,w=null,M=il,A=null,T=ql,S=.5;function E(t){return c(t[0]*Jc,t[1]*Jc)}function k(t){return(t=c.invert(t[0],t[1]))&&[t[0]*Qc,t[1]*Qc]}function N(){var t=$h(l,0,0,m,x,b).apply(null,n(p,g)),r=$h(l,h-t[0],d-t[1],m,x,b);return e=Ys(y,v,_),u=Us(n,r),c=Us(e,u),a=Lh(u,S),C()}function C(){return f=s=null,E}return E.stream=function(t){return f&&s===t?f:f=jh(function(t){return Rh({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(T(s=t)))))},E.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},E.postclip=function(t){return arguments.length?(T=t,A=r=i=o=null,C()):T},E.clipAngle=function(t){return arguments.length?(M=+t?ol(w=t*Jc):(w=null,il),C()):w*Qc},E.clipExtent=function(t){return arguments.length?(T=null==t?(A=r=i=o=null,ql):hl(A=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==A?null:[[A,r],[i,o]]},E.scale=function(t){return arguments.length?(l=+t,N()):l},E.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],N()):[h,d]},E.center=function(t){return arguments.length?(p=t[0]%360*Jc,g=t[1]%360*Jc,N()):[p*Qc,g*Qc]},E.rotate=function(t){return arguments.length?(y=t[0]%360*Jc,v=t[1]%360*Jc,_=t.length>2?t[2]%360*Jc:0,N()):[y*Qc,v*Qc,_*Qc]},E.angle=function(t){return arguments.length?(b=t%360*Jc,N()):b*Qc},E.reflectX=function(t){return arguments.length?(m=t?-1:1,N()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,N()):x<0},E.precision=function(t){return arguments.length?(a=Lh(u,S=t*t),C()):hf(S)},E.fitExtent=function(t,n){return Ih(E,t,n)},E.fitSize=function(t,n){return Oh(E,t,n)},E.fitWidth=function(t,n){return Uh(E,t,n)},E.fitHeight=function(t,n){return Bh(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&k,N()}}function Gh(t){var n=0,e=Vc/3,r=Xh(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Jc,e=t[1]*Jc):[n*Qc,e*Qc]},i}function Vh(t,n){var e=sf(t),r=(e+sf(n))/2;if(tf(r)<Xc)return function(t){var n=rf(t);function e(t,e){return[t*n,sf(e)/n]}return e.invert=function(t,e){return[t/n,gf(e*n)]},e}(t);var i=1+e*(2*r-e),o=hf(i)/r;function a(t,n){var e=hf(i-2*r*sf(n))/r;return[e*sf(t*=r),o-e*rf(t)]}return a.invert=function(t,n){var e=o-n,a=ef(t,tf(e))*lf(e);return e*r<0&&(a-=Vc*lf(t)*lf(e)),[a/r,gf((i-(t*t+e*e)*r*r)/(2*r))]},a}function Wh(){return Gh(Vh).scale(155.424).center([0,33.6442])}function Zh(){return Wh().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function Kh(t){return function(n,e){var r=rf(n),i=rf(e),o=t(r*i);return o===1/0?[2,0]:[o*i*sf(n),o*sf(e)]}}function Qh(t){return function(n,e){var r=hf(n*n+e*e),i=t(r),o=sf(i),a=rf(i);return[ef(n*o,r*a),gf(r&&e*o/r)]}}var Jh=Kh((function(t){return hf(2/(1+t))}));Jh.invert=Qh((function(t){return 2*gf(t/2)}));var td=Kh((function(t){return(t=pf(t))&&t/sf(t)}));function nd(t,n){return[t,cf(df((Wc+n)/2))]}function ed(t){var n,e,r,i=Hh(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=Vc*a(),u=i(Hs(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===nd?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function rd(t){return df((Wc+t)/2)}function id(t,n){var e=rf(t),r=t===n?sf(t):cf(e/rf(n))/cf(rd(n)/rd(t)),i=e*ff(rd(t),r)/r;if(!r)return nd;function o(t,n){i>0?n<-Wc+Xc&&(n=-Wc+Xc):n>Wc-Xc&&(n=Wc-Xc);var e=i/ff(rd(n),r);return[e*sf(r*t),i-e*rf(r*t)]}return o.invert=function(t,n){var e=i-n,o=lf(r)*hf(t*t+e*e),a=ef(t,tf(e))*lf(e);return e*r<0&&(a-=Vc*lf(t)*lf(e)),[a/r,2*nf(ff(i/o,1/r))-Wc]},o}function od(t,n){return[t,n]}function ad(t,n){var e=rf(t),r=t===n?sf(t):(e-rf(n))/(n-t),i=e/r+t;if(tf(r)<Xc)return od;function o(t,n){var e=i-n,o=r*t;return[e*sf(o),i-e*rf(o)]}return o.invert=function(t,n){var e=i-n,o=ef(t,tf(e))*lf(e);return e*r<0&&(o-=Vc*lf(t)*lf(e)),[o/r,i-lf(r)*hf(t*t+e*e)]},o}td.invert=Qh((function(t){return t})),nd.invert=function(t,n){return[t,2*nf(af(n))-Wc]},od.invert=od;var ud=1.340264,cd=-.081106,fd=893e-6,sd=.003796,ld=hf(3)/2;function hd(t,n){var e=gf(ld*sf(n)),r=e*e,i=r*r*r;return[t*rf(e)/(ld*(ud+3*cd*r+i*(7*fd+9*sd*r))),e*(ud+cd*r+i*(fd+sd*r))]}function dd(t,n){var e=rf(n),r=rf(t)*e;return[e*sf(t)/r,sf(n)/r]}function pd(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function gd(t,n){return[rf(n)*sf(t),sf(n)]}function yd(t,n){var e=rf(n),r=1+rf(t)*e;return[e*sf(t)/r,sf(n)/r]}function vd(t,n){return[cf(df((Wc+n)/2)),-t]}function _d(t,n){return t.parent===n.parent?1:2}function bd(t,n){return t+n.x}function md(t,n){return Math.max(t,n.y)}function xd(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function wd(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Ad)):void 0===n&&(n=Md);for(var e,r,i,o,a,u=new Ed(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Ed(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Sd)}function Md(t){return t.children}function Ad(t){return Array.isArray(t)?t[1]:null}function Td(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Sd(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Ed(t){this.data=t,this.depth=this.height=0,this.parent=null}function kd(t){return null==t?null:Nd(t)}function Nd(t){if("function"!=typeof t)throw new Error;return t}function Cd(){return 0}function Pd(t){return function(){return t}}hd.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(ud+cd*i+o*(fd+sd*i))-n)/(ud+3*cd*i+o*(7*fd+9*sd*i)))*r)*i*i,!(tf(e)<Gc));++a);return[ld*t*(ud+3*cd*i+o*(7*fd+9*sd*i))/rf(r),gf(sf(r)/ld)]},dd.invert=Qh(nf),pd.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(tf(e)>Xc&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},gd.invert=Qh(gf),yd.invert=Qh((function(t){return 2*nf(t)})),vd.invert=function(t,n){return[-n,2*nf(af(t))-Wc]},Ed.prototype=wd.prototype={constructor:Ed,count:function(){return this.eachAfter(xd)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r]);for(;o=u.pop();)t.call(n,o,++c,this);return this},eachBefore:function(t,n){for(var e,r,i=this,o=[i],a=-1;i=o.pop();)if(t.call(n,i,++a,this),e=i.children)for(r=e.length-1;r>=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return wd(this).eachBefore(Td)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e])}while(o.length)}};const zd=4294967296;function Dd(){let t=1;return()=>(t=(1664525*t+1013904223)%zd)/zd}function Rd(t,n){for(var e,r,i=0,o=(t=function(t,n){let e,r,i=t.length;for(;i;)r=n()*i--|0,e=t[i],t[i]=t[r],t[r]=e;return t}(Array.from(t),n)).length,a=[];i<o;)e=t[i],r&&Id(r,e)?++i:(r=Ud(a=Fd(a,e)),i=0);return r}function Fd(t,n){var e,r;if(Od(n,t))return[n];for(e=0;e<t.length;++e)if(qd(n,t[e])&&Od(Bd(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(qd(Bd(t[e],t[r]),n)&&qd(Bd(t[e],n),t[r])&&qd(Bd(t[r],n),t[e])&&Od(Yd(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function qd(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function Id(t,n){var e=t.r-n.r+1e-9*Math.max(t.r,n.r,1),r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Od(t,n){for(var e=0;e<n.length;++e)if(!Id(t,n[e]))return!1;return!0}function Ud(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return Bd(t[0],t[1]);case 3:return Yd(t[0],t[1],t[2])}}function Bd(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function Yd(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,g=i-s,y=c-o,v=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*g,w=(p*m-g*b)/(2*x)-r,M=(g*y-p*v)/x,A=(d*b-h*m)/(2*x)-i,T=(h*v-d*y)/x,S=M*M+T*T-1,E=2*(o+w*M+A*T),k=w*w+A*A-o*o,N=-(Math.abs(S)>1e-6?(E+Math.sqrt(E*E-4*S*k))/(2*S):k/E);return{x:r+w+M*N,y:i+A+T*N,r:N}}function Ld(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function jd(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function $d(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Hd(t){this._=t,this.next=null,this.previous=null}function Xd(t,n){if(!(o=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var e,r,i,o,a,u,c,f,s,l,h;if((e=t[0]).x=0,e.y=0,!(o>1))return e.r;if(r=t[1],e.x=-r.r,r.x=e.r,r.y=0,!(o>2))return e.r+r.r;Ld(r,e,i=t[2]),e=new Hd(e),r=new Hd(r),i=new Hd(i),e.next=i.previous=r,r.next=e.previous=i,i.next=r.previous=e;t:for(c=3;c<o;++c){Ld(e._,r._,i=t[c]),i=new Hd(i),f=r.next,s=e.previous,l=r._.r,h=e._.r;do{if(l<=h){if(jd(f._,i._)){r=f,e.next=r,r.previous=e,--c;continue t}l+=f._.r,f=f.next}else{if(jd(s._,i._)){(e=s).next=r,r.previous=e,--c;continue t}h+=s._.r,s=s.previous}}while(f!==s.next);for(i.previous=e,i.next=r,e.next=r.previous=r=i,a=$d(e);(i=i.next)!==r;)(u=$d(i))<a&&(e=i,a=u);r=e.next}for(e=[r._],i=r;(i=i.next)!==r;)e.push(i._);for(i=Rd(e,n),c=0;c<o;++c)(e=t[c]).x-=i.x,e.y-=i.y;return i.r}function Gd(t){return Math.sqrt(t.value)}function Vd(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Wd(t,n,e){return function(r){if(i=r.children){var i,o,a,u=i.length,c=t(r)*n||0;if(c)for(o=0;o<u;++o)i[o].r+=c;if(a=Xd(i,e),c)for(o=0;o<u;++o)i[o].r-=c;r.r=a+c}}}function Zd(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Kd(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Qd(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var Jd={depth:-1},tp={},np={};function ep(t){return t.id}function rp(t){return t.parentId}function ip(t){let n=t.length;if(n<2)return"";for(;--n>1&&!op(t,n););return t.slice(0,n)}function op(t,n){if("/"===t[n]){let e=0;for(;n>0&&"\\"===t[--n];)++e;if(0==(1&e))return!0}return!1}function ap(t,n){return t.parent===n.parent?1:2}function up(t){var n=t.children;return n?n[0]:t.t}function cp(t){var n=t.children;return n?n[n.length-1]:t.t}function fp(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function sp(t,n,e){return t.a.parent===n.parent?t.a:e}function lp(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function hp(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}lp.prototype=Object.create(Ed.prototype);var dp=(1+Math.sqrt(5))/2;function pp(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,g,y,v=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,y=s*s*(g=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/y,y/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?Qd(a,e,r,i,w?r+=f*s/w:o):hp(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return v}var gp=function t(n){function e(t,e,r,i,o){pp(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(dp);var yp=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?Qd(u,e,r,i,d?r+=(o-r)*u.value/d:o):hp(u,e,r,d?e+=(i-e)*u.value/d:i,o),d-=u.value}else t._squarify=a=pp(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(dp);function vp(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function _p(t,n){return t[0]-n[0]||t[1]-n[1]}function bp(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r<n;++r){for(;i>1&&vp(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var mp=Math.random,xp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(mp),wp=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(mp),Mp=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(mp),Ap=function t(n){var e=Mp.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(mp),Tp=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(mp),Sp=function t(n){var e=Tp.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(mp),Ep=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(mp),kp=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(mp),Np=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(mp),Cp=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(mp),Pp=function t(n){var e=Mp.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(mp),zp=function t(n){var e=Pp.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(mp),Dp=function t(n){var e=Cp.source(n),r=zp.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(mp),Rp=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(mp),Fp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(mp),qp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(mp),Ip=function t(n){var e=Pp.source(n),r=Dp.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(mp);const Op=1/4294967296;function Up(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function Bp(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const Yp=Symbol("implicit");function Lp(){var t=new InternMap,n=[],e=[],r=Yp;function i(i){let o=t.get(i);if(void 0===o){if(r!==Yp)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new InternMap;for(const r of e)t.has(r)||t.set(r,n.push(r)-1);return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return Lp(n,e).unknown(r)},Up.apply(i,arguments),i}function jp(){var t,n,e=Lp().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=a<o,h=l?a:o,d=l?o:a;t=(d-h)/Math.max(1,e-c+2*f),u&&(t=Math.floor(t)),h+=(d-h-t*(e-c))*s,n=t*(1-c),u&&(h=Math.round(h),n=Math.round(n));var p=lt(e).map((function(n){return h+t*n}));return i(l?p.reverse():p)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),l()):r()},e.range=function(t){return arguments.length?([o,a]=t,o=+o,a=+a,l()):[o,a]},e.rangeRound=function(t){return[o,a]=t,o=+o,a=+a,u=!0,l()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(u=!!t,l()):u},e.padding=function(t){return arguments.length?(c=Math.min(1,f=+t),l()):c},e.paddingInner=function(t){return arguments.length?(c=Math.min(1,t),l()):c},e.paddingOuter=function(t){return arguments.length?(f=+t,l()):f},e.align=function(t){return arguments.length?(s=Math.max(0,Math.min(1,t)),l()):s},e.copy=function(){return jp(r(),[o,a]).round(u).paddingInner(c).paddingOuter(f).align(s)},Up.apply(l(),arguments)}function $p(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return $p(n())},t}function Hp(t){return+t}var Xp=[0,1];function Gp(t){return t}function Vp(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function Wp(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=Vp(i,r),o=e(a,o)):(r=Vp(r,i),o=e(o,a)),function(t){return o(r(t))}}function Zp(t,n,e){var r=Math.min(t.length,n.length)-1,i=new Array(r),o=new Array(r),a=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<r;)i[a]=Vp(t[a],t[a+1]),o[a]=e(n[a],n[a+1]);return function(n){var e=l(t,n,1,r)-1;return o[e](i[e](n))}}function Kp(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Qp(){var t,n,e,r,i,o,a=Xp,u=Xp,c=Hr,f=Gp;function s(){var t=Math.min(a.length,u.length);return f!==Gp&&(f=function(t,n){var e;return t>n&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?Zp:Wp,i=o=null,l}function l(n){return null==n||isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),Br)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,Hp),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=Xr,s()},l.clamp=function(t){return arguments.length?(f=!!t||Gp,s()):f!==Gp},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Jp(){return Qp()(Gp,Gp)}function tg(n,e,r,i){var o,a=W(n,e,r);switch((i=Dc(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=$c(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=Hc(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=jc(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function ng(t){var n=t.domain;return t.ticks=function(t){var e=n();return G(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return tg(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f<c&&(i=c,c=f,f=i,i=a,a=u,u=i);s-- >0;){if((i=V(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function eg(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function rg(t){return Math.log(t)}function ig(t){return Math.exp(t)}function og(t){return-Math.log(-t)}function ag(t){return-Math.exp(-t)}function ug(t){return isFinite(t)?+("1e"+t):t<0?0:t}function cg(t){return(n,e)=>-t(-n,e)}function fg(n){const e=n(rg,ig),r=e.domain;let i,o,a=10;function u(){return i=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),n=>Math.log(n)/t)}(a),o=function(t){return 10===t?ug:t===Math.E?Math.exp:n=>Math.pow(t,n)}(a),r()[0]<0?(i=cg(i),o=cg(o),n(og,ag)):n(rg,ig),e}return e.base=function(t){return arguments.length?(a=+t,u()):a},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=t=>{const n=r();let e=n[0],u=n[n.length-1];const c=u<e;c&&([e,u]=[u,e]);let f,s,l=i(e),h=i(u);const d=null==t?10:+t;let p=[];if(!(a%1)&&h-l<d){if(l=Math.floor(l),h=Math.ceil(h),e>0){for(;l<=h;++l)for(f=1;f<a;++f)if(s=l<0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}}else for(;l<=h;++l)for(f=a-1;f>=1;--f)if(s=l>0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}2*p.length<d&&(p=G(e,u,d))}else p=G(l,h,Math.min(h-l,d)).map(o);return c?p.reverse():p},e.tickFormat=(n,r)=>{if(null==n&&(n=10),null==r&&(r=10===a?"s":","),"function"!=typeof r&&(a%1||null!=(r=Dc(r)).precision||(r.trim=!0),r=t.format(r)),n===1/0)return r;const u=Math.max(1,a*n/e.ticks().length);return t=>{let n=t/o(Math.round(i(t)));return n*a<a-.5&&(n*=a),n<=u?r(t):""}},e.nice=()=>r(eg(r(),{floor:t=>o(Math.floor(i(t))),ceil:t=>o(Math.ceil(i(t)))})),e}function sg(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function lg(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function hg(t){var n=1,e=t(sg(n),lg(n));return e.constant=function(e){return arguments.length?t(sg(n=+e),lg(n)):n},ng(e)}function dg(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function pg(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function gg(t){return t<0?-t*t:t*t}function yg(t){var n=t(Gp,Gp),e=1;function r(){return 1===e?t(Gp,Gp):.5===e?t(pg,gg):t(dg(e),dg(1/e))}return n.exponent=function(t){return arguments.length?(e=+t,r()):e},ng(n)}function vg(){var t=yg(Qp());return t.copy=function(){return Kp(t,vg()).exponent(t.exponent())},Up.apply(t,arguments),t}function _g(t){return Math.sign(t)*t*t}function bg(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}var mg=new Date,xg=new Date;function wg(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=function(n){return t(n=new Date(+n)),n},i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return wg((function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););}))},e&&(i.count=function(n,r){return mg.setTime(+n),xg.setTime(+r),t(mg),t(xg),Math.floor(e(mg,xg))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var Mg=wg((function(){}),(function(t,n){t.setTime(+t+n)}),(function(t,n){return n-t}));Mg.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?wg((function(n){n.setTime(Math.floor(n/t)*t)}),(function(n,e){n.setTime(+n+e*t)}),(function(n,e){return(e-n)/t})):Mg:null};var Ag=Mg,Tg=Mg.range;const Sg=1e3,Eg=6e4,kg=36e5,Ng=864e5,Cg=6048e5,Pg=2592e6,zg=31536e6;var Dg=wg((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,n){t.setTime(+t+n*Sg)}),(function(t,n){return(n-t)/Sg}),(function(t){return t.getUTCSeconds()})),Rg=Dg,Fg=Dg.range,qg=wg((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*Sg)}),(function(t,n){t.setTime(+t+n*Eg)}),(function(t,n){return(n-t)/Eg}),(function(t){return t.getMinutes()})),Ig=qg,Og=qg.range,Ug=wg((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*Sg-t.getMinutes()*Eg)}),(function(t,n){t.setTime(+t+n*kg)}),(function(t,n){return(n-t)/kg}),(function(t){return t.getHours()})),Bg=Ug,Yg=Ug.range,Lg=wg((t=>t.setHours(0,0,0,0)),((t,n)=>t.setDate(t.getDate()+n)),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Eg)/Ng),(t=>t.getDate()-1)),jg=Lg,$g=Lg.range;function Hg(t){return wg((function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),(function(t,n){t.setDate(t.getDate()+7*n)}),(function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Eg)/Cg}))}var Xg=Hg(0),Gg=Hg(1),Vg=Hg(2),Wg=Hg(3),Zg=Hg(4),Kg=Hg(5),Qg=Hg(6),Jg=Xg.range,ty=Gg.range,ny=Vg.range,ey=Wg.range,ry=Zg.range,iy=Kg.range,oy=Qg.range,ay=wg((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,n){t.setMonth(t.getMonth()+n)}),(function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()})),uy=ay,cy=ay.range,fy=wg((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,n){t.setFullYear(t.getFullYear()+n)}),(function(t,n){return n.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));fy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?wg((function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),(function(n,e){n.setFullYear(n.getFullYear()+e*t)})):null};var sy=fy,ly=fy.range,hy=wg((function(t){t.setUTCSeconds(0,0)}),(function(t,n){t.setTime(+t+n*Eg)}),(function(t,n){return(n-t)/Eg}),(function(t){return t.getUTCMinutes()})),dy=hy,py=hy.range,gy=wg((function(t){t.setUTCMinutes(0,0,0)}),(function(t,n){t.setTime(+t+n*kg)}),(function(t,n){return(n-t)/kg}),(function(t){return t.getUTCHours()})),yy=gy,vy=gy.range,_y=wg((function(t){t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCDate(t.getUTCDate()+n)}),(function(t,n){return(n-t)/Ng}),(function(t){return t.getUTCDate()-1})),by=_y,my=_y.range;function xy(t){return wg((function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCDate(t.getUTCDate()+7*n)}),(function(t,n){return(n-t)/Cg}))}var wy=xy(0),My=xy(1),Ay=xy(2),Ty=xy(3),Sy=xy(4),Ey=xy(5),ky=xy(6),Ny=wy.range,Cy=My.range,Py=Ay.range,zy=Ty.range,Dy=Sy.range,Ry=Ey.range,Fy=ky.range,qy=wg((function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCMonth(t.getUTCMonth()+n)}),(function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())}),(function(t){return t.getUTCMonth()})),Iy=qy,Oy=qy.range,Uy=wg((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)}),(function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Uy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?wg((function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),(function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null};var By=Uy,Yy=Uy.range;function Ly(t,n,e,i,o,a){const u=[[Rg,1,Sg],[Rg,5,5e3],[Rg,15,15e3],[Rg,30,3e4],[a,1,Eg],[a,5,3e5],[a,15,9e5],[a,30,18e5],[o,1,kg],[o,3,108e5],[o,6,216e5],[o,12,432e5],[i,1,Ng],[i,2,1728e5],[e,1,Cg],[n,1,Pg],[n,3,7776e6],[t,1,zg]];function c(n,e,i){const o=Math.abs(e-n)/i,a=r((([,,t])=>t)).right(u,o);if(a===u.length)return t.every(W(n/zg,e/zg,i));if(0===a)return Ag.every(Math.max(W(n,e,i),1));const[c,f]=u[o/u[a-1][2]<u[a][2]/o?a-1:a];return c.every(f)}return[function(t,n,e){const r=n<t;r&&([t,n]=[n,t]);const i=e&&"function"==typeof e.range?e:c(t,n,e),o=i?i.range(t,+n+1):[];return r?o.reverse():o},c]}const[jy,$y]=Ly(By,Iy,wy,by,yy,dy),[Hy,Xy]=Ly(sy,uy,Xg,jg,Bg,Ig);function Gy(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Vy(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Wy(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function Zy(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=iv(i),s=ov(i),l=iv(o),h=ov(o),d=iv(a),p=ov(a),g=iv(u),y=ov(u),v=iv(c),_=ov(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Sv,e:Sv,f:Pv,g:Lv,G:$v,H:Ev,I:kv,j:Nv,L:Cv,m:zv,M:Dv,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:d_,s:p_,S:Rv,u:Fv,U:qv,V:Ov,w:Uv,W:Bv,x:null,X:null,y:Yv,Y:jv,Z:Hv,"%":h_},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:Xv,e:Xv,f:Kv,g:c_,G:s_,H:Gv,I:Vv,j:Wv,L:Zv,m:Qv,M:Jv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:d_,s:p_,S:t_,u:n_,U:e_,V:i_,w:o_,W:a_,x:null,X:null,y:u_,Y:f_,Z:l_,"%":h_},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return A(t,n,e,r)},d:yv,e:yv,f:wv,g:hv,G:lv,H:_v,I:_v,j:vv,L:xv,m:gv,M:bv,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:pv,Q:Av,s:Tv,S:mv,u:uv,U:cv,V:fv,w:av,W:sv,x:function(t,n,r){return A(t,e,n,r)},X:function(t,n,e){return A(t,r,n,e)},y:hv,Y:lv,Z:dv,"%":Mv};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=Qy[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=Wy(1900,void 0,1);if(A(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(n&&!("Z"in o)&&(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=Vy(Wy(o.y,0,1))).getUTCDay(),r=i>4||0===i?My.ceil(r):My(r),r=by.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=Gy(Wy(o.y,0,1))).getDay(),r=i>4||0===i?Gg.ceil(r):Gg(r),r=jg.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Vy(Wy(o.y,0,1)).getUTCDay():Gy(Wy(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Vy(o)):Gy(o)}}function A(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in Qy?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var Ky,Qy={"-":"",_:" ",0:"0"},Jy=/^\s*\d+/,tv=/^%/,nv=/[\\^$*+?|[\]().{}]/g;function ev(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function rv(t){return t.replace(nv,"\\$&")}function iv(t){return new RegExp("^(?:"+t.map(rv).join("|")+")","i")}function ov(t){return new Map(t.map(((t,n)=>[t.toLowerCase(),n])))}function av(t,n,e){var r=Jy.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function uv(t,n,e){var r=Jy.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function cv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function fv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function sv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function lv(t,n,e){var r=Jy.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function hv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function dv(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function pv(t,n,e){var r=Jy.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function gv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function yv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function vv(t,n,e){var r=Jy.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function _v(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function bv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function mv(t,n,e){var r=Jy.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function xv(t,n,e){var r=Jy.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function wv(t,n,e){var r=Jy.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Mv(t,n,e){var r=tv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Av(t,n,e){var r=Jy.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Tv(t,n,e){var r=Jy.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Sv(t,n){return ev(t.getDate(),n,2)}function Ev(t,n){return ev(t.getHours(),n,2)}function kv(t,n){return ev(t.getHours()%12||12,n,2)}function Nv(t,n){return ev(1+jg.count(sy(t),t),n,3)}function Cv(t,n){return ev(t.getMilliseconds(),n,3)}function Pv(t,n){return Cv(t,n)+"000"}function zv(t,n){return ev(t.getMonth()+1,n,2)}function Dv(t,n){return ev(t.getMinutes(),n,2)}function Rv(t,n){return ev(t.getSeconds(),n,2)}function Fv(t){var n=t.getDay();return 0===n?7:n}function qv(t,n){return ev(Xg.count(sy(t)-1,t),n,2)}function Iv(t){var n=t.getDay();return n>=4||0===n?Zg(t):Zg.ceil(t)}function Ov(t,n){return t=Iv(t),ev(Zg.count(sy(t),t)+(4===sy(t).getDay()),n,2)}function Uv(t){return t.getDay()}function Bv(t,n){return ev(Gg.count(sy(t)-1,t),n,2)}function Yv(t,n){return ev(t.getFullYear()%100,n,2)}function Lv(t,n){return ev((t=Iv(t)).getFullYear()%100,n,2)}function jv(t,n){return ev(t.getFullYear()%1e4,n,4)}function $v(t,n){var e=t.getDay();return ev((t=e>=4||0===e?Zg(t):Zg.ceil(t)).getFullYear()%1e4,n,4)}function Hv(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+ev(n/60|0,"0",2)+ev(n%60,"0",2)}function Xv(t,n){return ev(t.getUTCDate(),n,2)}function Gv(t,n){return ev(t.getUTCHours(),n,2)}function Vv(t,n){return ev(t.getUTCHours()%12||12,n,2)}function Wv(t,n){return ev(1+by.count(By(t),t),n,3)}function Zv(t,n){return ev(t.getUTCMilliseconds(),n,3)}function Kv(t,n){return Zv(t,n)+"000"}function Qv(t,n){return ev(t.getUTCMonth()+1,n,2)}function Jv(t,n){return ev(t.getUTCMinutes(),n,2)}function t_(t,n){return ev(t.getUTCSeconds(),n,2)}function n_(t){var n=t.getUTCDay();return 0===n?7:n}function e_(t,n){return ev(wy.count(By(t)-1,t),n,2)}function r_(t){var n=t.getUTCDay();return n>=4||0===n?Sy(t):Sy.ceil(t)}function i_(t,n){return t=r_(t),ev(Sy.count(By(t),t)+(4===By(t).getUTCDay()),n,2)}function o_(t){return t.getUTCDay()}function a_(t,n){return ev(My.count(By(t)-1,t),n,2)}function u_(t,n){return ev(t.getUTCFullYear()%100,n,2)}function c_(t,n){return ev((t=r_(t)).getUTCFullYear()%100,n,2)}function f_(t,n){return ev(t.getUTCFullYear()%1e4,n,4)}function s_(t,n){var e=t.getUTCDay();return ev((t=e>=4||0===e?Sy(t):Sy.ceil(t)).getUTCFullYear()%1e4,n,4)}function l_(){return"+0000"}function h_(){return"%"}function d_(t){return+t}function p_(t){return Math.floor(+t/1e3)}function g_(n){return Ky=Zy(n),t.timeFormat=Ky.format,t.timeParse=Ky.parse,t.utcFormat=Ky.utcFormat,t.utcParse=Ky.utcParse,Ky}t.timeFormat=void 0,t.timeParse=void 0,t.utcFormat=void 0,t.utcParse=void 0,g_({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var y_="%Y-%m-%dT%H:%M:%S.%LZ";var v_=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat(y_),__=v_;var b_=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse(y_),m_=b_;function x_(t){return new Date(t)}function w_(t){return t instanceof Date?+t:+new Date(+t)}function M_(t,n,e,r,i,o,a,u,c,f){var s=Jp(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y");function x(t){return(c(t)<t?d:u(t)<t?p:a(t)<t?g:o(t)<t?y:r(t)<t?i(t)<t?v:_:e(t)<t?b:m)(t)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(Array.from(t,w_)):h().map(x_)},s.ticks=function(n){var e=h();return t(e[0],e[e.length-1],null==n?10:n)},s.tickFormat=function(t,n){return null==n?x:f(n)},s.nice=function(t){var e=h();return t&&"function"==typeof t.range||(t=n(e[0],e[e.length-1],null==t?10:t)),t?h(eg(e,t)):s},s.copy=function(){return Kp(s,M_(t,n,e,r,i,o,a,u,c,f))},s}function A_(){var t,n,e,r,i,o=0,a=1,u=Gp,c=!1;function f(n){return null==n||isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}function s(t){return function(n){var e,r;return arguments.length?([e,r]=n,u=t(e,r),f):[u(0),u(1)]}}return f.domain=function(i){return arguments.length?([o,a]=i,t=r(o=+o),n=r(a=+a),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.range=s(Hr),f.rangeRound=s(Xr),f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function T_(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function S_(){var t=yg(A_());return t.copy=function(){return T_(t,S_()).exponent(t.exponent())},Bp.apply(t,arguments)}function E_(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=1,l=Gp,h=!1;function d(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(s*t<s*n?r:i),l(h?Math.max(0,Math.min(1,t)):t))}function p(t){return function(n){var e,r,i;return arguments.length?([e,r,i]=n,l=li(t,[e,r,i]),d):[l(0),l(.5),l(1)]}}return d.domain=function(a){return arguments.length?([u,c,f]=a,t=o(u=+u),n=o(c=+c),e=o(f=+f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d):[u,c,f]},d.clamp=function(t){return arguments.length?(h=!!t,d):h},d.interpolator=function(t){return arguments.length?(l=t,d):l},d.range=p(Hr),d.rangeRound=p(Xr),d.unknown=function(t){return arguments.length?(a=t,d):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d}}function k_(){var t=yg(E_());return t.copy=function(){return T_(t,k_()).exponent(t.exponent())},Bp.apply(t,arguments)}function N_(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var C_=N_("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),P_=N_("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),z_=N_("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),D_=N_("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),R_=N_("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),F_=N_("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),q_=N_("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),I_=N_("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),O_=N_("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),U_=N_("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"),B_=t=>Rr(t[t.length-1]),Y_=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(N_),L_=B_(Y_),j_=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(N_),$_=B_(j_),H_=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(N_),X_=B_(H_),G_=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(N_),V_=B_(G_),W_=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(N_),Z_=B_(W_),K_=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(N_),Q_=B_(K_),J_=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(N_),tb=B_(J_),nb=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(N_),eb=B_(nb),rb=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(N_),ib=B_(rb),ob=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(N_),ab=B_(ob),ub=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(N_),cb=B_(ub),fb=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(N_),sb=B_(fb),lb=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(N_),hb=B_(lb),db=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(N_),pb=B_(db),gb=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(N_),yb=B_(gb),vb=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(N_),_b=B_(vb),bb=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(N_),mb=B_(bb),xb=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(N_),wb=B_(xb),Mb=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(N_),Ab=B_(Mb),Tb=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(N_),Sb=B_(Tb),Eb=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(N_),kb=B_(Eb),Nb=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(N_),Cb=B_(Nb),Pb=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(N_),zb=B_(Pb),Db=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(N_),Rb=B_(Db),Fb=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(N_),qb=B_(Fb),Ib=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(N_),Ob=B_(Ib),Ub=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(N_),Bb=B_(Ub);var Yb=si(wr(300,.5,0),wr(-240,.5,1)),Lb=si(wr(-100,.75,.35),wr(80,1.5,.8)),jb=si(wr(260,.75,.35),wr(80,1.5,.8)),$b=wr();var Hb=Fe(),Xb=Math.PI/3,Gb=2*Math.PI/3;function Vb(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var Wb=Vb(N_("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),Zb=Vb(N_("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),Kb=Vb(N_("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),Qb=Vb(N_("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function Jb(t){return function(){return t}}const tm=Math.abs,nm=Math.atan2,em=Math.cos,rm=Math.max,im=Math.min,om=Math.sin,am=Math.sqrt,um=1e-12,cm=Math.PI,fm=cm/2,sm=2*cm;function lm(t){return t>1?0:t<-1?cm:Math.acos(t)}function hm(t){return t>=1?fm:t<=-1?-fm:Math.asin(t)}function dm(t){return t.innerRadius}function pm(t){return t.outerRadius}function gm(t){return t.startAngle}function ym(t){return t.endAngle}function vm(t){return t&&t.padAngle}function _m(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<um))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}function bm(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/am(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*am(rm(0,x*x*m-w*w)),A=(w*b-_*M)/m,T=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,k=A-y,N=T-v,C=S-y,P=E-v;return k*k+N*N>C*C+P*P&&(A=S,T=E),{cx:A,cy:T,x01:-s,y01:-l,x11:A*(i/x-1),y11:T*(i/x-1)}}var mm=Array.prototype.slice;function xm(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function wm(t){this._context=t}function Mm(t){return new wm(t)}function Am(t){return t[0]}function Tm(t){return t[1]}function Sm(t,n){var e=Jb(!0),r=null,i=Mm,o=null;function a(a){var u,c,f,s=(a=xm(a)).length,l=!1;for(null==r&&(o=i(f=Pa())),u=0;u<=s;++u)!(u<s&&e(c=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(c,u,a),+n(c,u,a));if(f)return o=null,f+""||null}return t="function"==typeof t?t:void 0===t?Am:Jb(t),n="function"==typeof n?n:void 0===n?Tm:Jb(n),a.x=function(n){return arguments.length?(t="function"==typeof n?n:Jb(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:Jb(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:Jb(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function Em(t,n,e){var r=null,i=Jb(!0),o=null,a=Mm,u=null;function c(c){var f,s,l,h,d,p=(c=xm(c)).length,g=!1,y=new Array(p),v=new Array(p);for(null==o&&(u=a(d=Pa())),f=0;f<=p;++f){if(!(f<p&&i(h=c[f],f,c))===g)if(g=!g)s=f,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=f-1;l>=s;--l)u.point(y[l],v[l]);u.lineEnd(),u.areaEnd()}g&&(y[f]=+t(h,f,c),v[f]=+n(h,f,c),u.point(r?+r(h,f,c):y[f],e?+e(h,f,c):v[f]))}if(d)return u=null,d+""||null}function f(){return Sm().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Am:Jb(+t),n="function"==typeof n?n:Jb(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?Tm:Jb(+e),c.x=function(n){return arguments.length?(t="function"==typeof n?n:Jb(+n),r=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:Jb(+n),c):t},c.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Jb(+t),c):r},c.y=function(t){return arguments.length?(n="function"==typeof t?t:Jb(+t),e=null,c):n},c.y0=function(t){return arguments.length?(n="function"==typeof t?t:Jb(+t),c):n},c.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:Jb(+t),c):e},c.lineX0=c.lineY0=function(){return f().x(t).y(n)},c.lineY1=function(){return f().x(t).y(e)},c.lineX1=function(){return f().x(r).y(n)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:Jb(!!t),c):i},c.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),c):a},c.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),c):o},c}function km(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Nm(t){return t}wm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Cm=zm(Mm);function Pm(t){this._curve=t}function zm(t){function n(n){return new Pm(t(n))}return n._curve=t,n}function Dm(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(zm(t)):n()._curve},t}function Rm(){return Dm(Sm().curve(Cm))}function Fm(){var t=Em().curve(Cm),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Dm(e())},delete t.lineX0,t.lineEndAngle=function(){return Dm(r())},delete t.lineX1,t.lineInnerRadius=function(){return Dm(i())},delete t.lineY0,t.lineOuterRadius=function(){return Dm(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(zm(t)):n()._curve},t}function qm(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Pm.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class Im{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class Om{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0==this._point++)this._x0=t,this._y0=n;else{const e=qm(this._x0,this._y0),r=qm(this._x0,this._y0=(this._y0+n)/2),i=qm(t,this._y0),o=qm(t,n);this._context.moveTo(...e),this._context.bezierCurveTo(...r,...i,...o)}}}function Um(t){return new Im(t,!0)}function Bm(t){return new Im(t,!1)}function Ym(t){return new Om(t)}function Lm(t){return t.source}function jm(t){return t.target}function $m(t){let n=Lm,e=jm,r=Am,i=Tm,o=null,a=null;function u(){let u;const c=mm.call(arguments),f=n.apply(this,c),s=e.apply(this,c);if(null==o&&(a=t(u=Pa())),a.lineStart(),c[0]=f,a.point(+r.apply(this,c),+i.apply(this,c)),c[0]=s,a.point(+r.apply(this,c),+i.apply(this,c)),a.lineEnd(),u)return a=null,u+""||null}return u.source=function(t){return arguments.length?(n=t,u):n},u.target=function(t){return arguments.length?(e=t,u):e},u.x=function(t){return arguments.length?(r="function"==typeof t?t:Jb(+t),u):r},u.y=function(t){return arguments.length?(i="function"==typeof t?t:Jb(+t),u):i},u.context=function(n){return arguments.length?(null==n?o=a=null:a=t(o=n),u):o},u}const Hm=am(3);var Xm={draw(t,n){const e=.59436*am(n+im(n/28,.75)),r=e/2,i=r*Hm;t.moveTo(0,e),t.lineTo(0,-e),t.moveTo(-i,-r),t.lineTo(i,r),t.moveTo(-i,r),t.lineTo(i,-r)}},Gm={draw(t,n){const e=am(n/cm);t.moveTo(e,0),t.arc(0,0,e,0,sm)}},Vm={draw(t,n){const e=am(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}};const Wm=am(1/3),Zm=2*Wm;var Km={draw(t,n){const e=am(n/Zm),r=e*Wm;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Qm={draw(t,n){const e=.62625*am(n);t.moveTo(0,-e),t.lineTo(e,0),t.lineTo(0,e),t.lineTo(-e,0),t.closePath()}},Jm={draw(t,n){const e=.87559*am(n-im(n/7,2));t.moveTo(-e,0),t.lineTo(e,0),t.moveTo(0,e),t.lineTo(0,-e)}},tx={draw(t,n){const e=am(n),r=-e/2;t.rect(r,r,e,e)}},nx={draw(t,n){const e=.4431*am(n);t.moveTo(e,e),t.lineTo(e,-e),t.lineTo(-e,-e),t.lineTo(-e,e),t.closePath()}};const ex=om(cm/10)/om(7*cm/10),rx=om(sm/10)*ex,ix=-em(sm/10)*ex;var ox={draw(t,n){const e=am(.8908130915292852*n),r=rx*e,i=ix*e;t.moveTo(0,-e),t.lineTo(r,i);for(let n=1;n<5;++n){const o=sm*n/5,a=em(o),u=om(o);t.lineTo(u*e,-a*e),t.lineTo(a*r-u*i,u*r+a*i)}t.closePath()}};const ax=am(3);var ux={draw(t,n){const e=-am(n/(3*ax));t.moveTo(0,2*e),t.lineTo(-ax*e,-e),t.lineTo(ax*e,-e),t.closePath()}};const cx=am(3);var fx={draw(t,n){const e=.6824*am(n),r=e/2,i=e*cx/2;t.moveTo(0,-e),t.lineTo(i,r),t.lineTo(-i,r),t.closePath()}};const sx=-.5,lx=am(3)/2,hx=1/am(12),dx=3*(hx/2+1);var px={draw(t,n){const e=am(n/dx),r=e/2,i=e*hx,o=r,a=e*hx+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(sx*r-lx*i,lx*r+sx*i),t.lineTo(sx*o-lx*a,lx*o+sx*a),t.lineTo(sx*u-lx*c,lx*u+sx*c),t.lineTo(sx*r+lx*i,sx*i-lx*r),t.lineTo(sx*o+lx*a,sx*a-lx*o),t.lineTo(sx*u+lx*c,sx*c-lx*u),t.closePath()}},gx={draw(t,n){const e=.6189*am(n-im(n/6,1.7));t.moveTo(-e,-e),t.lineTo(e,e),t.moveTo(-e,e),t.lineTo(e,-e)}};const yx=[Gm,Vm,Km,tx,ox,ux,px],vx=[Gm,Jm,gx,fx,Xm,nx,Qm];function _x(){}function bx(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function mx(t){this._context=t}function xx(t){this._context=t}function wx(t){this._context=t}function Mx(t,n){this._basis=new mx(t),this._beta=n}mx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:bx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:bx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},xx.prototype={areaStart:_x,areaEnd:_x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:bx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},wx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:bx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Mx.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Ax=function t(n){function e(t){return 1===n?new mx(t):new Mx(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function Tx(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Sx(t,n){this._context=t,this._k=(1-n)/6}Sx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Tx(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Tx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Ex=function t(n){function e(t){return new Sx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function kx(t,n){this._context=t,this._k=(1-n)/6}kx.prototype={areaStart:_x,areaEnd:_x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Tx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Nx=function t(n){function e(t){return new kx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Cx(t,n){this._context=t,this._k=(1-n)/6}Cx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Tx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Px=function t(n){function e(t){return new Cx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function zx(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>um){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>um){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Dx(t,n){this._context=t,this._alpha=n}Dx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:zx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Rx=function t(n){function e(t){return n?new Dx(t,n):new Sx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Fx(t,n){this._context=t,this._alpha=n}Fx.prototype={areaStart:_x,areaEnd:_x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:zx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var qx=function t(n){function e(t){return n?new Fx(t,n):new kx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Ix(t,n){this._context=t,this._alpha=n}Ix.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:zx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Ox=function t(n){function e(t){return n?new Ix(t,n):new Cx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Ux(t){this._context=t}function Bx(t){return t<0?-1:1}function Yx(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(Bx(o)+Bx(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function Lx(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function jx(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function $x(t){this._context=t}function Hx(t){this._context=new Xx(t)}function Xx(t){this._context=t}function Gx(t){this._context=t}function Vx(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function Wx(t,n){this._context=t,this._t=n}function Zx(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function Kx(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function Qx(t,n){return t[n]}function Jx(t){const n=[];return n.key=t,n}function tw(t){var n=t.map(nw);return Kx(t).sort((function(t,e){return n[t]-n[e]}))}function nw(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function ew(t){var n=t.map(rw);return Kx(t).sort((function(t,e){return n[t]-n[e]}))}function rw(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}Ux.prototype={areaStart:_x,areaEnd:_x,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},$x.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:jx(this,this._t0,Lx(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,jx(this,Lx(this,e=Yx(this,t,n)),e);break;default:jx(this,this._t0,e=Yx(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Hx.prototype=Object.create($x.prototype)).point=function(t,n){$x.prototype.point.call(this,n,t)},Xx.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},Gx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=Vx(t),i=Vx(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},Wx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var iw=t=>()=>t;function ow(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function aw(t,n,e){this.k=t,this.x=n,this.y=e}aw.prototype={constructor:aw,scale:function(t){return 1===t?this:new aw(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new aw(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var uw=new aw(1,0,0);function cw(t){for(;!t.__zoom;)if(!(t=t.parentNode))return uw;return t.__zoom}function fw(t){t.stopImmediatePropagation()}function sw(t){t.preventDefault(),t.stopImmediatePropagation()}function lw(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function hw(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function dw(){return this.__zoom||uw}function pw(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function gw(){return navigator.maxTouchPoints||"ontouchstart"in this}function yw(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}cw.prototype=aw.prototype,t.Adder=T,t.Delaunay=ku,t.FormatSpecifier=Rc,t.InternMap=InternMap,t.InternSet=InternSet,t.Node=Ed,t.Voronoi=wu,t.ZoomTransform=aw,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>1&&e.name===n)return new lo([[t]],Bo,n,+r);return null},t.arc=function(){var t=dm,n=pm,e=Jb(0),r=null,i=gm,o=ym,a=vm,u=null;function c(){var c,f,s=+t.apply(this,arguments),l=+n.apply(this,arguments),h=i.apply(this,arguments)-fm,d=o.apply(this,arguments)-fm,p=tm(d-h),g=d>h;if(u||(u=c=Pa()),l<s&&(f=l,l=s,s=f),l>um)if(p>sm-um)u.moveTo(l*em(h),l*om(h)),u.arc(0,0,l,h,d,!g),s>um&&(u.moveTo(s*em(d),s*om(d)),u.arc(0,0,s,d,h,g));else{var y,v,_=h,b=d,m=h,x=d,w=p,M=p,A=a.apply(this,arguments)/2,T=A>um&&(r?+r.apply(this,arguments):am(s*s+l*l)),S=im(tm(l-s)/2,+e.apply(this,arguments)),E=S,k=S;if(T>um){var N=hm(T/s*om(A)),C=hm(T/l*om(A));(w-=2*N)>um?(m+=N*=g?1:-1,x-=N):(w=0,m=x=(h+d)/2),(M-=2*C)>um?(_+=C*=g?1:-1,b-=C):(M=0,_=b=(h+d)/2)}var P=l*em(_),z=l*om(_),D=s*em(x),R=s*om(x);if(S>um){var F,q=l*em(b),I=l*om(b),O=s*em(m),U=s*om(m);if(p<cm&&(F=_m(P,z,O,U,q,I,D,R))){var B=P-F[0],Y=z-F[1],L=q-F[0],j=I-F[1],$=1/om(lm((B*L+Y*j)/(am(B*B+Y*Y)*am(L*L+j*j)))/2),H=am(F[0]*F[0]+F[1]*F[1]);E=im(S,(s-H)/($-1)),k=im(S,(l-H)/($+1))}}M>um?k>um?(y=bm(O,U,P,z,l,k,g),v=bm(q,I,D,R,l,k,g),u.moveTo(y.cx+y.x01,y.cy+y.y01),k<S?u.arc(y.cx,y.cy,k,nm(y.y01,y.x01),nm(v.y01,v.x01),!g):(u.arc(y.cx,y.cy,k,nm(y.y01,y.x01),nm(y.y11,y.x11),!g),u.arc(0,0,l,nm(y.cy+y.y11,y.cx+y.x11),nm(v.cy+v.y11,v.cx+v.x11),!g),u.arc(v.cx,v.cy,k,nm(v.y11,v.x11),nm(v.y01,v.x01),!g))):(u.moveTo(P,z),u.arc(0,0,l,_,b,!g)):u.moveTo(P,z),s>um&&w>um?E>um?(y=bm(D,R,q,I,s,-E,g),v=bm(P,z,O,U,s,-E,g),u.lineTo(y.cx+y.x01,y.cy+y.y01),E<S?u.arc(y.cx,y.cy,E,nm(y.y01,y.x01),nm(v.y01,v.x01),!g):(u.arc(y.cx,y.cy,E,nm(y.y01,y.x01),nm(y.y11,y.x11),!g),u.arc(0,0,s,nm(y.cy+y.y11,y.cx+y.x11),nm(v.cy+v.y11,v.cx+v.x11),g),u.arc(v.cx,v.cy,E,nm(v.y11,v.x11),nm(v.y01,v.x01),!g))):u.arc(0,0,s,x,m,g):u.lineTo(D,R)}else u.moveTo(0,0);if(u.closePath(),c)return u=null,c+""||null}return c.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-cm/2;return[em(r)*e,om(r)*e]},c.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:Jb(+n),c):t},c.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:Jb(+t),c):n},c.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:Jb(+t),c):e},c.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Jb(+t),c):r},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:Jb(+t),c):i},c.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:Jb(+t),c):o},c.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:Jb(+t),c):a},c.context=function(t){return arguments.length?(u=null==t?null:t,c):u},c},t.area=Em,t.areaRadial=Fm,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;Qu&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return Et(3,t)},t.axisLeft=function(t){return Et(4,t)},t.axisRight=function(t){return Et(2,t)},t.axisTop=function(t){return Et(1,t)},t.bin=Q,t.bisect=l,t.bisectCenter=s,t.bisectLeft=f,t.bisectRight=c,t.bisector=r,t.blob=function(t,n){return fetch(t,n).then(Ju)},t.blur=function(t,n){if(!((n=+n)>=0))throw new RangeError("invalid r");let e=t.length;if(!((e=Math.floor(e))>=0))throw new RangeError("invalid length");if(!e||!n)return t;const r=v(n),i=t.slice();return r(t,i,0,e,1),r(i,t,0,e,1),r(t,i,0,e,1),t},t.blur2=h,t.blurImage=d,t.brush=function(){return pa(ea)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return pa(ta)},t.brushY=function(){return pa(na)},t.buffer=function(t,n){return fetch(t,n).then(tc)},t.chord=function(){return Ta(!1,!1)},t.chordDirected=function(){return Ta(!0,!1)},t.chordTranspose=function(){return Ta(!1,!0)},t.cluster=function(){var t=_d,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(bd,0)/t.length}(e),n.y=function(t){return 1+t.reduce(md,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=Pe,t.contourDensity=function(){var t=Ka,n=Qa,e=Ja,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=$a(20);function l(r){var i=new Float32Array(c*f),s=Math.pow(2,-a),l=-1;for(const o of r){var d=(t(o,++l,r)+u)*s,p=(n(o,l,r)+u)*s,g=+e(o,l,r);if(d>=0&&d<c&&p>=0&&p<f){var y=Math.floor(d),v=Math.floor(p),_=d-y-.5,b=p-v-.5;i[y+v*c]+=(1-_)*(1-b)*g,i[y+1+v*c]+=_*(1-b)*g,i[y+1+(v+1)*c]+=_*b*g,i[y+(v+1)*c]+=(1-_)*b*g}}return h({data:i,width:c,height:f},o*s),i}function d(t){var n=l(t),e=s(n),r=Math.pow(2,2*a);return Array.isArray(e)||(e=G(Number.MIN_VALUE,J(n)/r,e)),Za().size([c,f]).thresholds(e.map((t=>t*r)))(n).map(((t,n)=>(t.value=+e[n],p(t))))}function p(t){return t.coordinates.forEach(g),t}function g(t){t.forEach(y)}function y(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function _(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,d}return d.contours=function(t){var n=l(t),e=Za().size([c,f]),r=Math.pow(2,2*a),i=t=>{t=+t;var i=p(e.contour(n,t*r));return i.value=t,i};return Object.defineProperty(i,"max",{get:()=>J(n)/r}),i},d.x=function(n){return arguments.length?(t="function"==typeof n?n:$a(+n),d):t},d.y=function(t){return arguments.length?(n="function"==typeof t?t:$a(+t),d):n},d.weight=function(t){return arguments.length?(e="function"==typeof t?t:$a(+t),d):e},d.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,_()},d.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),_()},d.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?$a(La.call(t)):$a(t),d):s},d.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=(Math.sqrt(4*t*t+1)-1)/2,_()},d},t.contours=Za,t.count=_,t.create=function(t){return Wn(Ut(t).call(document.documentElement))},t.creator=Ut,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(x)).map(b),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(m))return o;for(;;){o.push(i.map(((n,e)=>t[e][n])));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=ic,t.csvFormat=Uu,t.csvFormatBody=Bu,t.csvFormatRow=Lu,t.csvFormatRows=Yu,t.csvFormatValue=ju,t.csvParse=Iu,t.csvParseRows=Ou,t.cubehelix=wr,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new mx(t)},t.curveBasisClosed=function(t){return new xx(t)},t.curveBasisOpen=function(t){return new wx(t)},t.curveBumpX=Um,t.curveBumpY=Bm,t.curveBundle=Ax,t.curveCardinal=Ex,t.curveCardinalClosed=Nx,t.curveCardinalOpen=Px,t.curveCatmullRom=Rx,t.curveCatmullRomClosed=qx,t.curveCatmullRomOpen=Ox,t.curveLinear=Mm,t.curveLinearClosed=function(t){return new Ux(t)},t.curveMonotoneX=function(t){return new $x(t)},t.curveMonotoneY=function(t){return new Hx(t)},t.curveNatural=function(t){return new Gx(t)},t.curveStep=function(t){return new Wx(t,.5)},t.curveStepAfter=function(t){return new Wx(t,1)},t.curveStepBefore=function(t){return new Wx(t,0)},t.descending=e,t.deviation=M,t.difference=function(t,...n){t=new InternSet(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new InternSet;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=Nt,t.drag=function(){var t,n,e,r,i=fe,o=se,a=le,u=he,c={},f=Nt("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,ne).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(Wn(a.view).on("mousemove.drag",p,ee).on("mouseup.drag",g,ee),oe(a.view),re(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(ie(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){Wn(t.view).on("mousemove.drag mouseup.drag",null),ae(t.view,e),ie(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e<c;++e)(r=b(this,u,t,n,a[e].identifier,a[e]))&&(re(t),r("start",t,a[e]))}}function v(t){var n,e,r=t.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(ie(t),e("drag",t,r[n]))}function _(t){var n,e,i=t.changedTouches,o=i.length;for(r&&clearTimeout(r),r=setTimeout((function(){r=null}),500),n=0;n<o;++n)(e=c[i[n].identifier])&&(re(t),e("end",t,i[n]))}function b(t,n,e,r,i,o){var u,l,d,p=f.copy(),g=te(o||e,n);if(null!=(d=a.call(t,new ce("beforestart",{sourceEvent:e,target:h,identifier:i,active:s,x:g[0],y:g[1],dx:0,dy:0,dispatch:p}),r)))return u=d.x-g[0]||0,l=d.y-g[1]||0,function e(o,a,f){var y,v=g;switch(o){case"start":c[i]=e,y=s++;break;case"end":delete c[i],--s;case"drag":g=te(f||a,n),y=s}p.call(o,t,new ce(o,{sourceEvent:a,subject:d,target:h,identifier:i,active:y,x:g[0]+u,y:g[1]+l,dx:g[0]-v[0],dy:g[1]-v[1],dispatch:p}),r)}}return h.filter=function(t){return arguments.length?(i="function"==typeof t?t:ue(!!t),h):i},h.container=function(t){return arguments.length?(o="function"==typeof t?t:ue(t),h):o},h.subject=function(t){return arguments.length?(a="function"==typeof t?t:ue(t),h):a},h.touchable=function(t){return arguments.length?(u="function"==typeof t?t:ue(!!t),h):u},h.on=function(){var t=f.on.apply(f,arguments);return t===f?h:t},h.clickDistance=function(t){return arguments.length?(l=(t=+t)*t,h):Math.sqrt(l)},h},t.dragDisable=oe,t.dragEnable=ae,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Fu(t);return ec(n,e).then((function(t){return i.parse(t,r)}))},t.dsvFormat=Fu,t.easeBack=Do,t.easeBackIn=Po,t.easeBackInOut=Do,t.easeBackOut=zo,t.easeBounce=No,t.easeBounceIn=function(t){return 1-No(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-No(1-t):No(t-1)+1)/2},t.easeBounceOut=No,t.easeCircle=So,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=So,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=vo,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=vo,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=qo,t.easeElasticIn=Fo,t.easeElasticInOut=Io,t.easeElasticOut=qo,t.easeExp=To,t.easeExpIn=function(t){return Ao(1-+t)},t.easeExpInOut=To,t.easeExpOut=function(t){return 1-Ao(t)},t.easeLinear=t=>+t,t.easePoly=mo,t.easePolyIn=_o,t.easePolyInOut=mo,t.easePolyOut=bo,t.easeQuad=yo,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=yo,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Mo,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*wo)},t.easeSinInOut=Mo,t.easeSinOut=function(t){return Math.sin(t*wo)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=A,t.fcumsum=function(t,n){const e=new T;let r=-1;return Float64Array.from(t,void 0===n?t=>e.add(+t||0):i=>e.add(+n(i,++r,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.flatGroup=function(t,...n){return D(z(t,...n),n)},t.flatRollup=function(t,n,...e){return D(F(t,n,...e),e)},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;i<a;++i)u+=(o=e[i]).x,c+=o.y;for(u=(u/a-t)*r,c=(c/a-n)*r,i=0;i<a;++i)(o=e[i]).x-=u,o.y-=c}return null==t&&(t=0),null==n&&(n=0),i.initialize=function(t){e=t},i.x=function(n){return arguments.length?(t=+n,i):t},i.y=function(t){return arguments.length?(n=+t,i):n},i.strength=function(t){return arguments.length?(r=+t,i):r},i},t.forceCollide=function(t){var n,e,r,i=1,o=1;function a(){for(var t,a,c,f,s,l,h,d=n.length,p=0;p<o;++p)for(a=gc(n,xc,wc).visitAfter(u),t=0;t<d;++t)c=n[t],l=e[c.index],h=l*l,f=c.x+c.vx,s=c.y+c.vy,a.visit(g);function g(t,n,e,o,a){var u=t.data,d=t.r,p=l+d;if(!u)return n>f+p||o<f-p||e>s+p||a<s-p;if(u.index>c.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;v<p*p&&(0===g&&(v+=(g=mc(r))*g),0===y&&(v+=(y=mc(r))*y),v=(p-(v=Math.sqrt(v)))/v*i,c.vx+=(g*=v)*(p=(d*=d)/(h+d)),c.vy+=(y*=v)*p,u.vx-=g*(p=1-p),u.vy-=y*p)}}}function u(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=bc(null==t?1:+t)),a.initialize=function(t,e){n=t,r=e,c()},a.iterations=function(t){return arguments.length?(o=+t,a):o},a.strength=function(t){return arguments.length?(i=+t,a):i},a.radius=function(n){return arguments.length?(t="function"==typeof n?n:bc(+n),c(),a):t},a},t.forceLink=function(t){var n,e,r,i,o,a,u=Mc,c=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=bc(30),s=1;function l(r){for(var i=0,u=t.length;i<s;++i)for(var c,f,l,h,d,p,g,y=0;y<u;++y)f=(c=t[y]).source,h=(l=c.target).x+l.vx-f.x-f.vx||mc(a),d=l.y+l.vy-f.y-f.vy||mc(a),h*=p=((p=Math.sqrt(h*h+d*d))-e[y])/p*r*n[y],d*=p,l.vx-=h*(g=o[y]),l.vy-=d*g,f.vx+=h*(g=1-g),f.vy+=d*g}function h(){if(r){var a,c,f=r.length,s=t.length,l=new Map(r.map(((t,n)=>[u(t,n,r),t])));for(a=0,i=new Array(f);a<s;++a)(c=t[a]).index=a,"object"!=typeof c.source&&(c.source=Ac(l,c.source)),"object"!=typeof c.target&&(c.target=Ac(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(a=0,o=new Array(s);a<s;++a)c=t[a],o[a]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),d(),e=new Array(s),p()}}function d(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+c(t[e],e,t)}function p(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),l.initialize=function(t,n){r=t,a=n,h()},l.links=function(n){return arguments.length?(t=n,h(),l):t},l.id=function(t){return arguments.length?(u=t,l):u},l.iterations=function(t){return arguments.length?(s=+t,l):s},l.strength=function(t){return arguments.length?(c="function"==typeof t?t:bc(+t),d(),l):c},l.distance=function(t){return arguments.length?(f="function"==typeof t?t:bc(+t),p(),l):f},l},t.forceManyBody=function(){var t,n,e,r,i,o=bc(-30),a=1,u=1/0,c=.81;function f(e){var i,o=t.length,a=gc(t,Sc,Ec).visitAfter(l);for(r=e,i=0;i<o;++i)n=t[i],a.visit(h)}function s(){if(t){var n,e,r=t.length;for(i=new Array(r),n=0;n<r;++n)e=t[n],i[e.index]=+o(e,n,t)}}function l(t){var n,e,r,o,a,u=0,c=0;if(t.length){for(r=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,r+=e*n.x,o+=e*n.y);t.x=r/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=i[n.data.index]}while(n=n.next)}t.value=u}function h(t,o,f,s){if(!t.value)return!0;var l=t.x-n.x,h=t.y-n.y,d=s-o,p=l*l+h*h;if(d*d/c<p)return p<u&&(0===l&&(p+=(l=mc(e))*l),0===h&&(p+=(h=mc(e))*h),p<a&&(p=Math.sqrt(a*p)),n.vx+=l*t.value*r/p,n.vy+=h*t.value*r/p),!0;if(!(t.length||p>=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=mc(e))*l),0===h&&(p+=(h=mc(e))*h),p<a&&(p=Math.sqrt(a*p)));do{t.data!==n&&(d=i[t.data.index]*r/p,n.vx+=l*d,n.vy+=h*d)}while(t=t.next)}}return f.initialize=function(n,r){t=n,e=r,s()},f.strength=function(t){return arguments.length?(o="function"==typeof t?t:bc(+t),s(),f):o},f.distanceMin=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.distanceMax=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f.theta=function(t){return arguments.length?(c=t*t,f):Math.sqrt(c)},f},t.forceRadial=function(t,n,e){var r,i,o,a=bc(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=bc(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:bc(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:bc(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=new Map,c=Ti(l),f=Nt("tick","end"),s=function(){let t=1;return()=>(t=(1664525*t+1013904223)%Tc)/Tc}();function l(){h(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function h(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.forEach((function(t){t(e)})),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function d(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=10*Math.sqrt(.5+e),o=e*kc;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function p(n){return n.initialize&&n.initialize(t,s),n}return null==t&&(t=[]),d(),n={tick:h,restart:function(){return c.restart(l),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,d(),u.forEach(p),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},randomSource:function(t){return arguments.length?(s=t,u.forEach(p),n):s},force:function(t,e){return arguments.length>1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=bc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=bc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:bc(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:bc(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=bc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=bc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:bc(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:bc(+n),a(),o):t},o},t.formatDefaultLocale=Lc,t.formatLocale=Yc,t.formatSpecifier=Dc,t.fsum=function(t,n){const e=new T;if(void 0===n)for(let n of t)(n=+n)&&e.add(n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&e.add(i)}return+e},t.geoAlbers=Zh,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=Zh(),u=Wh().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=Wh().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+Xc,s+.12*n+Xc],[o-.214*n-Xc,s+.234*n-Xc]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+Xc,s+.166*n+Xc],[o-.115*n-Xc,s+.234*n-Xc]]).stream(f),l()},s.fitExtent=function(t,n){return Ih(s,t,n)},s.fitSize=function(t,n){return Oh(s,t,n)},s.fitWidth=function(t,n){return Uh(s,t,n)},s.fitHeight=function(t,n){return Bh(s,t,n)},s.scale(1070)},t.geoArea=function(t){return Yf=new T,Mf(t,Lf),2*Yf},t.geoAzimuthalEqualArea=function(){return Hh(Jh).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Jh,t.geoAzimuthalEquidistant=function(){return Hh(td).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=td,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(zf=Pf=-(Nf=Cf=1/0),Of=[],Mf(t,ys),e=Of.length){for(Of.sort(Ts),n=1,o=[r=Of[0]];n<e;++n)Ss(r,(i=Of[n])[0])||Ss(r,i[1])?(As(r[0],i[1])>As(r[0],r[1])&&(r[1]=i[1]),As(i[0],r[1])>As(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=As(r[1],i[0]))>a&&(a=u,Nf=i[0],Pf=r[1])}return Of=Uf=null,Nf===1/0||Cf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Nf,Cf],[Pf,zf]]},t.geoCentroid=function(t){ts=ns=es=rs=is=os=as=us=0,cs=new T,fs=new T,ss=new T,Mf(t,Es);var n=+cs,e=+fs,r=+ss,i=uf(n,e,r);return i<Gc&&(n=os,e=as,r=us,ns<Xc&&(n=es,e=rs,r=is),(i=uf(n,e,r))<Gc)?[NaN,NaN]:[ef(e,n)*Qc,gf(r/i)*Qc]},t.geoCircle=function(){var t,n,e=Os([0,0]),r=Os(90),i=Os(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=Qc,e[1]*=Qc}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*Jc,c=i.apply(this,arguments)*Jc;return t=[],n=Ys(-a[0]*Jc,-a[1]*Jc,0).invert,Xs(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Os([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Os(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Os(+t),a):i},a},t.geoClipAntimeridian=il,t.geoClipCircle=ol,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=hl(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=hl,t.geoConicConformal=function(){return Gh(id).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=id,t.geoConicEqualArea=Wh,t.geoConicEqualAreaRaw=Vh,t.geoConicEquidistant=function(){return Gh(ad).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=ad,t.geoContains=function(t,n){return(t&&xl.hasOwnProperty(t.type)?xl[t.type]:Ml)(t,n)},t.geoDistance=ml,t.geoEqualEarth=function(){return Hh(hd).scale(177.158)},t.geoEqualEarthRaw=hd,t.geoEquirectangular=function(){return Hh(od).scale(152.63)},t.geoEquirectangularRaw=od,t.geoGnomonic=function(){return Hh(dd).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=dd,t.geoGraticule=Pl,t.geoGraticule10=function(){return Pl()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,g=1,y=Rh({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),v=ql;function _(){return p=u*s,g=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*g;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/g]},b.stream=function(t){return o&&a===t?o:o=y(v(a=t))},b.postclip=function(t){return arguments.length?(v=t,d=e=r=i=null,_()):v},b.clipExtent=function(t){return arguments.length?(v=null==t?(d=e=r=i=null,ql):hl(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=sf(h=e%360*Jc),t=rf(h),_()):h*Qc},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return Ih(b,t,n)},b.fitSize=function(t,n){return Oh(b,t,n)},b.fitWidth=function(t,n){return Uh(b,t,n)},b.fitHeight=function(t,n){return Bh(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*Jc,r=t[1]*Jc,i=n[0]*Jc,o=n[1]*Jc,a=rf(r),u=sf(r),c=rf(o),f=sf(o),s=a*rf(e),l=a*sf(e),h=c*rf(i),d=c*sf(i),p=2*gf(hf(yf(o-r)+a*c*yf(i-e))),g=sf(p),y=p?function(t){var n=sf(t*=p)/g,e=sf(p-t)/g,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[ef(i,r)*Qc,ef(o,hf(r*r+i*i))*Qc]}:function(){return[e*Qc,r*Qc]};return y.distance=p,y},t.geoLength=vl,t.geoMercator=function(){return ed(nd).scale(961/Kc)},t.geoMercatorRaw=nd,t.geoNaturalEarth1=function(){return Hh(pd).scale(175.295)},t.geoNaturalEarth1Raw=pd,t.geoOrthographic=function(){return Hh(gd).scale(249.5).clipAngle(90.000001)},t.geoOrthographicRaw=gd,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Mf(t,e(r))),r.result()}return o.area=function(t){return Mf(t,e($l)),$l.result()},o.measure=function(t){return Mf(t,e(Ph)),Ph.result()},o.bounds=function(t){return Mf(t,e(th)),th.result()},o.centroid=function(t){return Mf(t,e(mh)),mh.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,ql):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new zh):new xh(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoProjection=Hh,t.geoProjectionMutator=Xh,t.geoRotation=Hs,t.geoStereographic=function(){return Hh(yd).scale(250).clipAngle(142)},t.geoStereographicRaw=yd,t.geoStream=Mf,t.geoTransform=function(t){return{stream:Rh(t)}},t.geoTransverseMercator=function(){var t=ed(vd),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=vd,t.gray=function(t,n){return new ir(t,0,0,null==n?1:n)},t.greatest=ot,t.greatestIndex=function(t,e=n){if(1===e.length)return tt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=P,t.groupSort=function(t,e,r){return(2!==e.length?U(R(t,e,r),(([t,e],[r,i])=>n(e,i)||n(t,r))):U(P(t,r),(([t,r],[i,o])=>e(r,o)||n(t,i)))).map((([t])=>t))},t.groups=z,t.hcl=sr,t.hierarchy=wd,t.histogram=Q,t.hsl=$e,t.html=fc,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return I(t,C,q,n)},t.indexes=function(t,...n){return I(t,Array.from,q,n)},t.interpolate=Hr,t.interpolateArray=function(t,n){return(Ir(n)?qr:Or)(t,n)},t.interpolateBasis=Tr,t.interpolateBasisClosed=Sr,t.interpolateBlues=Cb,t.interpolateBrBG=L_,t.interpolateBuGn=ab,t.interpolateBuPu=cb,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=jb,t.interpolateCubehelix=fi,t.interpolateCubehelixDefault=Yb,t.interpolateCubehelixLong=si,t.interpolateDate=Ur,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=sb,t.interpolateGreens=zb,t.interpolateGreys=Rb,t.interpolateHcl=ai,t.interpolateHclLong=ui,t.interpolateHsl=ri,t.interpolateHslLong=ii,t.interpolateHue=function(t,n){var e=Nr(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=Kb,t.interpolateLab=function(t,n){var e=Pr((t=rr(t)).l,(n=rr(n)).l),r=Pr(t.a,n.a),i=Pr(t.b,n.b),o=Pr(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=Zb,t.interpolateNumber=Br,t.interpolateNumberArray=qr,t.interpolateObject=Yr,t.interpolateOrRd=hb,t.interpolateOranges=Bb,t.interpolatePRGn=$_,t.interpolatePiYG=X_,t.interpolatePlasma=Qb,t.interpolatePuBu=yb,t.interpolatePuBuGn=pb,t.interpolatePuOr=V_,t.interpolatePuRd=_b,t.interpolatePurples=qb,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return $b.h=360*t-100,$b.s=1.5-1.5*n,$b.l=.8-.9*n,$b+""},t.interpolateRdBu=Z_,t.interpolateRdGy=Q_,t.interpolateRdPu=mb,t.interpolateRdYlBu=tb,t.interpolateRdYlGn=eb,t.interpolateReds=Ob,t.interpolateRgb=zr,t.interpolateRgbBasis=Rr,t.interpolateRgbBasisClosed=Fr,t.interpolateRound=Xr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,Hb.r=255*(n=Math.sin(t))*n,Hb.g=255*(n=Math.sin(t+Xb))*n,Hb.b=255*(n=Math.sin(t+Gb))*n,Hb+""},t.interpolateSpectral=ib,t.interpolateString=$r,t.interpolateTransformCss=Qr,t.interpolateTransformSvg=Jr,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=Wb,t.interpolateWarm=Lb,t.interpolateYlGn=Ab,t.interpolateYlGnBu=wb,t.interpolateYlOrBr=Sb,t.interpolateYlOrRd=kb,t.interpolateZoom=ni,t.interrupt=Ii,t.intersection=function(t,...n){t=new InternSet(t),n=n.map(vt);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Ai,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?wi():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=__,t.isoParse=m_,t.json=function(t,n){return fetch(t,n).then(ac)},t.lab=rr,t.lch=function(t,n,e,r){return 1===arguments.length?fr(t):new lr(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=ht,t.line=Sm,t.lineRadial=Rm,t.link=$m,t.linkHorizontal=function(){return $m(Um)},t.linkRadial=function(){const t=$m(Ym);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return $m(Bm)},t.local=Kn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((e,r)=>n(e,r,t)))},t.matcher=Ht,t.max=J,t.maxIndex=tt,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return at(t,.5,n)},t.medianIndex=function(t,n){return ct(t,.5,n)},t.merge=ft,t.min=nt,t.minIndex=et,t.mode=function(t,n){const e=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&e.set(n,(e.get(n)||0)+1);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&i>=i&&e.set(i,(e.get(i)||0)+1)}let r,i=0;for(const[t,n]of e)n>i&&(i=n,r=t);return r},t.namespace=qt,t.namespaces=Ft,t.nice=Z,t.now=wi,t.pack=function(){var t=null,n=1,e=1,r=Cd;function i(i){const o=Dd();return i.x=n/2,i.y=e/2,t?i.eachBefore(Vd(t)).eachAfter(Wd(r,.5,o)).eachBefore(Zd(1)):i.eachBefore(Vd(Gd)).eachAfter(Wd(Cd,1,o)).eachAfter(Wd(r,i.r/Math.min(n,e),o)).eachBefore(Zd(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=kd(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:Pd(+t),i):r},i},t.packEnclose=function(t){return Rd(t,Dd())},t.packSiblings=function(t){return Xd(t,Dd()),t},t.pairs=function(t,n=st){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Qd(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Kd),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=Pa,t.permute=O,t.pie=function(){var t=Nm,n=km,e=null,r=Jb(0),i=Jb(sm),o=Jb(0);function a(a){var u,c,f,s,l,h=(a=xm(a)).length,d=0,p=new Array(h),g=new Array(h),y=+r.apply(this,arguments),v=Math.min(sm,Math.max(-sm,i.apply(this,arguments)-y)),_=Math.min(Math.abs(v)/h,o.apply(this,arguments)),b=_*(v<0?-1:1);for(u=0;u<h;++u)(l=g[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u<h;++u,y=s)c=p[u],s=y+((l=g[c])>0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:Jb(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Jb(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Jb(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:Jb(+t),a):o},a},t.piecewise=li,t.pointRadial=qm,t.pointer=te,t.pointers=function(t,n){return t.target&&(t=Jn(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,(t=>te(t,n)))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(_p),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=bp(r),a=bp(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.hypot(n,e);return c},t.precisionFixed=jc,t.precisionPrefix=$c,t.precisionRound=Hc,t.quadtree=gc,t.quantile=at,t.quantileIndex=ct,t.quantileSorted=ut,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.quickselect=rt,t.radialArea=Fm,t.radialLine=Rm,t.randomBates=Sp,t.randomBernoulli=Np,t.randomBeta=zp,t.randomBinomial=Dp,t.randomCauchy=Fp,t.randomExponential=Ep,t.randomGamma=Pp,t.randomGeometric=Cp,t.randomInt=wp,t.randomIrwinHall=Tp,t.randomLcg=function(t=Math.random()){let n=0|(0<=t&&t<1?t/Op:Math.abs(t));return()=>(n=1664525*n+1013904223|0,Op*(n>>>0))},t.randomLogNormal=Ap,t.randomLogistic=qp,t.randomNormal=Mp,t.randomPareto=kp,t.randomPoisson=Ip,t.randomUniform=xp,t.randomWeibull=Rp,t.range=lt,t.rank=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");let r=Array.from(t);const i=new Float64Array(r.length);2!==e.length&&(r=r.map(e),e=n);const o=(t,n)=>e(r[t],r[n]);let a,u;return Uint32Array.from(r,((t,n)=>n)).sort(e===n?(t,n)=>Y(r[t],r[n]):B(o)).forEach(((t,n)=>{const e=o(t,void 0===a?t:a);e>=0?((void 0===a||e>0)&&(a=t,u=n),i[t]=u):i[t]=NaN})),i},t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=Fe,t.ribbon=function(){return Ya()},t.ribbonArrow=function(){return Ya(Ba)},t.rollup=R,t.rollups=F,t.scaleBand=jp,t.scaleDiverging=function t(){var n=ng(E_()(Gp));return n.copy=function(){return T_(n,t())},Bp.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=fg(E_()).domain([.1,1,10]);return n.copy=function(){return T_(n,t()).base(n.base())},Bp.apply(n,arguments)},t.scaleDivergingPow=k_,t.scaleDivergingSqrt=function(){return k_.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=hg(E_());return n.copy=function(){return T_(n,t()).constant(n.constant())},Bp.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return null==t||isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,Hp),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,Hp):[0,1],ng(r)},t.scaleImplicit=Yp,t.scaleLinear=function t(){var n=Jp();return n.copy=function(){return Kp(n,t())},Up.apply(n,arguments),ng(n)},t.scaleLog=function t(){const n=fg(Qp()).domain([1,10]);return n.copy=()=>Kp(n,t()).base(n.base()),Up.apply(n,arguments),n},t.scaleOrdinal=Lp,t.scalePoint=function(){return $p(jp.apply(null,arguments).paddingInner(1))},t.scalePow=vg,t.scaleQuantile=function t(){var e,r=[],i=[],o=[];function a(){var t=0,n=Math.max(1,i.length);for(o=new Array(n-1);++t<n;)o[t-1]=ut(r,t/n);return u}function u(t){return null==t||isNaN(t=+t)?e:i[l(o,t)]}return u.invertExtent=function(t){var n=i.indexOf(t);return n<0?[NaN,NaN]:[n>0?o[n-1]:r[0],n<o.length?o[n]:r[r.length-1]]},u.domain=function(t){if(!arguments.length)return r.slice();r=[];for(let n of t)null==n||isNaN(n=+n)||r.push(n);return r.sort(n),a()},u.range=function(t){return arguments.length?(i=Array.from(t),a()):i.slice()},u.unknown=function(t){return arguments.length?(e=t,u):e},u.quantiles=function(){return o.slice()},u.copy=function(){return t().domain(r).range(i).unknown(e)},Up.apply(u,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,i=1,o=[.5],a=[0,1];function u(t){return null!=t&&t<=t?a[l(o,t,0,i)]:n}function c(){var t=-1;for(o=new Array(i);++t<i;)o[t]=((t+1)*r-(t-i)*e)/(i+1);return u}return u.domain=function(t){return arguments.length?([e,r]=t,e=+e,r=+r,c()):[e,r]},u.range=function(t){return arguments.length?(i=(a=Array.from(t)).length-1,c()):a.slice()},u.invertExtent=function(t){var n=a.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},u.unknown=function(t){return arguments.length?(n=t,u):u},u.thresholds=function(){return o.slice()},u.copy=function(){return t().domain([e,r]).range(a).unknown(n)},Up.apply(ng(u),arguments)},t.scaleRadial=function t(){var n,e=Jp(),r=[0,1],i=!1;function o(t){var r=bg(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(_g(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,Hp)).map(_g)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},Up.apply(o,arguments),ng(o)},t.scaleSequential=function t(){var n=ng(A_()(Gp));return n.copy=function(){return T_(n,t())},Bp.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=fg(A_()).domain([1,10]);return n.copy=function(){return T_(n,t()).base(n.base())},Bp.apply(n,arguments)},t.scaleSequentialPow=S_,t.scaleSequentialQuantile=function t(){var e=[],r=Gp;function i(t){if(null!=t&&!isNaN(t=+t))return r((l(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map(((t,n)=>r(n/(e.length-1))))},i.quantiles=function(t){return Array.from({length:t+1},((n,r)=>at(e,r/t)))},i.copy=function(){return t(r).domain(e)},Bp.apply(i,arguments)},t.scaleSequentialSqrt=function(){return S_.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=hg(A_());return n.copy=function(){return T_(n,t()).constant(n.constant())},Bp.apply(n,arguments)},t.scaleSqrt=function(){return vg.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=hg(Qp());return n.copy=function(){return Kp(n,t()).constant(n.constant())},Up.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function o(t){return null!=t&&t<=t?r[l(e,t,0,i)]:n}return o.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),o):e.slice()},o.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),o):r.slice()},o.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t().domain(e).range(r).unknown(n)},Up.apply(o,arguments)},t.scaleTime=function(){return Up.apply(M_(Hy,Xy,sy,uy,Xg,jg,Bg,Ig,Rg,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return Up.apply(M_(jy,$y,By,Iy,wy,by,yy,dy,Rg,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=ht(t,n);return e<0?void 0:e},t.schemeAccent=P_,t.schemeBlues=Nb,t.schemeBrBG=Y_,t.schemeBuGn=ob,t.schemeBuPu=ub,t.schemeCategory10=C_,t.schemeDark2=z_,t.schemeGnBu=fb,t.schemeGreens=Pb,t.schemeGreys=Db,t.schemeOrRd=lb,t.schemeOranges=Ub,t.schemePRGn=j_,t.schemePaired=D_,t.schemePastel1=R_,t.schemePastel2=F_,t.schemePiYG=H_,t.schemePuBu=gb,t.schemePuBuGn=db,t.schemePuOr=G_,t.schemePuRd=vb,t.schemePurples=Fb,t.schemeRdBu=W_,t.schemeRdGy=K_,t.schemeRdPu=bb,t.schemeRdYlBu=J_,t.schemeRdYlGn=nb,t.schemeReds=Ib,t.schemeSet1=q_,t.schemeSet2=I_,t.schemeSet3=O_,t.schemeSpectral=rb,t.schemeTableau10=U_,t.schemeYlGn=Mb,t.schemeYlGnBu=xb,t.schemeYlOrBr=Tb,t.schemeYlOrRd=Eb,t.select=Wn,t.selectAll=function(t){return"string"==typeof t?new Gn([document.querySelectorAll(t)],[document.documentElement]):new Gn([Lt(t)],Xn)},t.selection=Vn,t.selector=Yt,t.selectorAll=$t,t.shuffle=dt,t.shuffler=pt,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=U,t.stack=function(){var t=Jb([]),n=Kx,e=Zx,r=Qx;function i(i){var o,a,u=Array.from(t.apply(this,arguments),Jx),c=u.length,f=-1;for(const t of i)for(o=0,++f;o<c;++o)(u[o][f]=[0,+r(t,u[o].key,f,i)]).data=t;for(o=0,a=xm(n(u));o<c;++o)u[a[o]].index=o;return e(u,a),u}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:Jb(Array.from(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:Jb(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?Kx:"function"==typeof t?t:Jb(Array.from(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?Zx:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Zx(t,n)}},t.stackOffsetNone=Zx,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}Zx(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,Zx(t,n)}},t.stackOrderAppearance=tw,t.stackOrderAscending=ew,t.stackOrderDescending=function(t){return ew(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(rw),o=tw(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=Kx,t.stackOrderReverse=function(t){return Kx(t).reverse()},t.stratify=function(){var t,n=ep,e=rp;function r(r){var i,o,a,u,c,f,s,l,h=Array.from(r),d=n,p=e,g=new Map;if(null!=t){const n=h.map(((n,e)=>function(t){let n=(t=`${t}`).length;op(t,n-1)&&!op(t,n-2)&&(t=t.slice(0,-1));return"/"===t[0]?t:`/${t}`}(t(n,e,r)))),e=n.map(ip),i=new Set(n).add("");for(const t of e)i.has(t)||(i.add(t),n.push(t),e.push(ip(t)),h.push(np));d=(t,e)=>n[e],p=(t,n)=>e[n]}for(a=0,i=h.length;a<i;++a)o=h[a],f=h[a]=new Ed(o),null!=(s=d(o,a,r))&&(s+="")&&(l=f.id=s,g.set(l,g.has(l)?tp:f)),null!=(s=p(o,a,r))&&(s+="")&&(f.parent=s);for(a=0;a<i;++a)if(s=(f=h[a]).parent){if(!(c=g.get(s)))throw new Error("missing: "+s);if(c===tp)throw new Error("ambiguous: "+s);c.children?c.children.push(f):c.children=[f],f.parent=c}else{if(u)throw new Error("multiple roots");u=f}if(!u)throw new Error("no root");if(null!=t){for(;u.data===np&&1===u.children.length;)u=u.children[0],--i;for(let t=h.length-1;t>=0&&(f=h[t],f.data===np);--t)f.data=null}if(u.parent=Jd,u.eachBefore((function(t){t.depth=t.parent.depth+1,--i})).eachBefore(Sd),u.parent=null,i>0)throw new Error("cycle");return u}return r.id=function(t){return arguments.length?(n=kd(t),r):n},r.parentId=function(t){return arguments.length?(e=kd(t),r):e},r.path=function(n){return arguments.length?(t=kd(n),r):t},r},t.style=yn,t.subset=function(t,n){return _t(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=_t,t.svg=sc,t.symbol=function(t,n){let e=null;function r(){let r;if(e||(e=r=Pa()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return t="function"==typeof t?t:Jb(t||Gm),n="function"==typeof n?n:Jb(void 0===n?64:+n),r.type=function(n){return arguments.length?(t="function"==typeof n?n:Jb(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:Jb(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbolAsterisk=Xm,t.symbolCircle=Gm,t.symbolCross=Vm,t.symbolDiamond=Km,t.symbolDiamond2=Qm,t.symbolPlus=Jm,t.symbolSquare=tx,t.symbolSquare2=nx,t.symbolStar=ox,t.symbolTriangle=ux,t.symbolTriangle2=fx,t.symbolWye=px,t.symbolX=gx,t.symbols=yx,t.symbolsFill=yx,t.symbolsStroke=vx,t.text=ec,t.thresholdFreedmanDiaconis=function(t,n,e){return Math.ceil((e-n)/(2*(at(t,.75)-at(t,.25))*Math.pow(_(t),-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)*Math.cbrt(_(t))/(3.49*M(t)))},t.thresholdSturges=K,t.tickFormat=tg,t.tickIncrement=V,t.tickStep=W,t.ticks=G,t.timeDay=jg,t.timeDays=$g,t.timeFormatDefaultLocale=g_,t.timeFormatLocale=Zy,t.timeFriday=Kg,t.timeFridays=iy,t.timeHour=Bg,t.timeHours=Yg,t.timeInterval=wg,t.timeMillisecond=Ag,t.timeMilliseconds=Tg,t.timeMinute=Ig,t.timeMinutes=Og,t.timeMonday=Gg,t.timeMondays=ty,t.timeMonth=uy,t.timeMonths=cy,t.timeSaturday=Qg,t.timeSaturdays=oy,t.timeSecond=Rg,t.timeSeconds=Fg,t.timeSunday=Xg,t.timeSundays=Jg,t.timeThursday=Zg,t.timeThursdays=ry,t.timeTickInterval=Xy,t.timeTicks=Hy,t.timeTuesday=Vg,t.timeTuesdays=ny,t.timeWednesday=Wg,t.timeWednesdays=ey,t.timeWeek=Xg,t.timeWeeks=Jg,t.timeYear=sy,t.timeYears=ly,t.timeout=Ci,t.timer=Ti,t.timerFlush=Si,t.transition=ho,t.transpose=gt,t.tree=function(){var t=ap,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new lp(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new lp(r[i],i)),e.parent=n;return(a.parent=new lp(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=cp(u),o=up(o),u&&o;)c=up(c),(a=cp(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(fp(sp(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!cp(a)&&(a.t=u,a.m+=l-s),o&&!up(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=gp,n=!1,e=1,r=1,i=[0],o=Cd,a=Cd,u=Cd,c=Cd,f=Cd;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Kd),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=Nd(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:Pd(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:Pd(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:Pd(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:Pd(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:Pd(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d<p;){var g=d+p>>>1;f[g]<h?d=g+1:p=g}h-f[d-1]<f[d]-h&&n+1<d&&--d;var y=f[d]-l,v=r-y;if(a-i>c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Qd,t.treemapResquarify=yp,t.treemapSlice=hp,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?hp:Qd)(t,n,e,r,i)},t.treemapSquarify=gp,t.tsv=oc,t.tsvFormat=Gu,t.tsvFormatBody=Vu,t.tsvFormatRow=Zu,t.tsvFormatRows=Wu,t.tsvFormatValue=Ku,t.tsvParse=Hu,t.tsvParseRows=Xu,t.union=function(...t){const n=new InternSet;for(const e of t)for(const t of e)n.add(t);return n},t.utcDay=by,t.utcDays=my,t.utcFriday=Ey,t.utcFridays=Ry,t.utcHour=yy,t.utcHours=vy,t.utcMillisecond=Ag,t.utcMilliseconds=Tg,t.utcMinute=dy,t.utcMinutes=py,t.utcMonday=My,t.utcMondays=Cy,t.utcMonth=Iy,t.utcMonths=Oy,t.utcSaturday=ky,t.utcSaturdays=Fy,t.utcSecond=Rg,t.utcSeconds=Fg,t.utcSunday=wy,t.utcSundays=Ny,t.utcThursday=Sy,t.utcThursdays=Dy,t.utcTickInterval=$y,t.utcTicks=jy,t.utcTuesday=Ay,t.utcTuesdays=Py,t.utcWednesday=Ty,t.utcWednesdays=zy,t.utcWeek=wy,t.utcWeeks=Ny,t.utcYear=By,t.utcYears=Yy,t.variance=w,t.version="7.6.1",t.window=hn,t.xml=cc,t.zip=function(){return gt(arguments)},t.zoom=function(){var t,n,e,r=lw,i=hw,o=yw,a=pw,u=gw,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=ni,h=Nt("start","zoom","end"),d=500,p=0,g=10;function y(t){t.property("__zoom",dw).on("wheel.zoom",M,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",T).filter(u).on("touchstart.zoom",S).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function v(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new aw(n,t.x,t.y)}function _(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new aw(t.k,r,i)}function b(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function m(t,n,e,r){t.on("start.zoom",(function(){x(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){x(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=x(t,o).event(r),u=i.apply(t,o),c=null==e?b(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new aw(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function x(t,n,e){return!e&&t.__zooming||new w(t,n)}function w(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function M(t,...n){if(r.apply(this,arguments)){var e=x(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=te(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],Ii(this),e.start()}sw(t),e.wheel=setTimeout(l,150),e.zoom("mouse",o(_(v(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}function l(){e.wheel=null,e.end()}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=x(this,n,!0).event(t),u=Wn(t.view).on("mousemove.zoom",h,!0).on("mouseup.zoom",d,!0),c=te(t,i),s=t.clientX,l=t.clientY;oe(t.view),fw(t),a.mouse=[c,this.__zoom.invert(c)],Ii(this),a.start()}function h(t){if(sw(t),!a.moved){var n=t.clientX-s,e=t.clientY-l;a.moved=n*n+e*e>p}a.event(t).zoom("mouse",o(_(a.that.__zoom,a.mouse[0]=te(t,i),a.mouse[1]),a.extent,f))}function d(t){u.on("mousemove.zoom mouseup.zoom",null),ae(t.view,a.moved),sw(t),a.event(t).end()}}function T(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=te(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(_(v(e,c),a,u),i.apply(this,n),f);sw(t),s>0?Wn(this).transition().duration(s).call(m,l,a,t):Wn(this).call(y.transform,l,a,t)}}function S(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=x(this,i,e.changedTouches.length===s).event(e);for(fw(e),a=0;a<s;++a)c=[c=te(u=f[a],this),this.__zoom.invert(c),u.identifier],l.touch0?l.touch1||l.touch0[2]===c[2]||(l.touch1=c,l.taps=0):(l.touch0=c,o=!0,l.taps=1+!!t);t&&(t=clearTimeout(t)),o&&(l.taps<2&&(n=c[0],t=setTimeout((function(){t=null}),d)),Ii(this),l.start())}}function E(t,...n){if(this.__zooming){var e,r,i,a,u=x(this,n).event(t),c=t.changedTouches,s=c.length;for(sw(t),e=0;e<s;++e)i=te(r=c[e],this),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],g=(g=d[0]-l[0])*g+(g=d[1]-l[1])*g,y=(y=p[0]-h[0])*y+(y=p[1]-h[1])*y;r=v(r,Math.sqrt(g/y)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(_(r,i,a),u.extent,f))}}function k(t,...r){if(this.__zooming){var i,o,a=x(this,r).event(t),u=t.changedTouches,c=u.length;for(fw(t),e&&clearTimeout(e),e=setTimeout((function(){e=null}),d),i=0;i<c;++i)o=u[i],a.touch0&&a.touch0[2]===o.identifier?delete a.touch0:a.touch1&&a.touch1[2]===o.identifier&&delete a.touch1;if(a.touch1&&!a.touch0&&(a.touch0=a.touch1,delete a.touch1),a.touch0)a.touch0[1]=this.__zoom.invert(a.touch0[0]);else if(a.end(),2===a.taps&&(o=te(o,this),Math.hypot(n[0]-o[0],n[1]-o[1])<g)){var f=Wn(this).on("dblclick.zoom");f&&f.apply(this,arguments)}}}return y.transform=function(t,n,e,r){var i=t.selection?t.selection():t;i.property("__zoom",dw),t!==i?m(t,n,e,r):i.interrupt().each((function(){x(this,arguments).event(r).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()}))},y.scaleBy=function(t,n,e,r){y.scaleTo(t,(function(){var t=this.__zoom.k,e="function"==typeof n?n.apply(this,arguments):n;return t*e}),e,r)},y.scaleTo=function(t,n,e,r){y.transform(t,(function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?b(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(_(v(r,c),a,u),t,f)}),e,r)},y.translateBy=function(t,n,e,r){y.transform(t,(function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)}),null,r)},y.translateTo=function(t,n,e,r,a){y.transform(t,(function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?b(t):"function"==typeof r?r.apply(this,arguments):r;return o(uw.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)}),r,a)},w.prototype={event:function(t){return t&&(this.sourceEvent=t),this},start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){var n=Wn(this.that).datum();h.call(t,this.that,new ow(t,{sourceEvent:this.sourceEvent,target:y,type:t,transform:this.that.__zoom,dispatch:h}),n)}},y.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:iw(+t),y):a},y.filter=function(t){return arguments.length?(r="function"==typeof t?t:iw(!!t),y):r},y.touchable=function(t){return arguments.length?(u="function"==typeof t?t:iw(!!t),y):u},y.extent=function(t){return arguments.length?(i="function"==typeof t?t:iw([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),y):i},y.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],y):[c[0],c[1]]},y.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],y):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},y.constrain=function(t){return arguments.length?(o=t,y):o},y.duration=function(t){return arguments.length?(s=+t,y):s},y.interpolate=function(t){return arguments.length?(l=t,y):l},y.on=function(){var t=h.on.apply(h,arguments);return t===h?y:t},y.clickDistance=function(t){return arguments.length?(p=(t=+t)*t,y):Math.sqrt(p)},y.tapDistance=function(t){return arguments.length?(g=+t,y):g},y},t.zoomIdentity=uw,t.zoomTransform=cw,Object.defineProperty(t,"__esModule",{value:!0})}));
diff --git a/js/001-lib/lodash-4.17.15.min.js b/js/001-lib/lodash-4.17.15.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..13ec307dac5a6f5248312146f94d3a3ab84515e5
--- /dev/null
+++ b/js/001-lib/lodash-4.17.15.min.js
@@ -0,0 +1,137 @@
+/**
+ * @license
+ * Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
+ */
+;(function(){function n(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function t(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u<i;){var o=n[u];t(e,o,r(o),n)}return e}function r(n,t){for(var r=-1,e=null==n?0:n.length;++r<e&&false!==t(n[r],r,n););return n}function e(n,t){for(var r=null==n?0:n.length;r--&&false!==t(n[r],r,n););return n}function u(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(!t(n[r],r,n))return false;
+return true}function i(n,t){for(var r=-1,e=null==n?0:n.length,u=0,i=[];++r<e;){var o=n[r];t(o,r,n)&&(i[u++]=o)}return i}function o(n,t){return!(null==n||!n.length)&&-1<v(n,t,0)}function f(n,t,r){for(var e=-1,u=null==n?0:n.length;++e<u;)if(r(t,n[e]))return true;return false}function c(n,t){for(var r=-1,e=null==n?0:n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function a(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function l(n,t,r,e){var u=-1,i=null==n?0:n.length;for(e&&i&&(r=n[++u]);++u<i;)r=t(r,n[u],u,n);
+return r}function s(n,t,r,e){var u=null==n?0:n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function h(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(t(n[r],r,n))return true;return false}function p(n,t,r){var e;return r(n,function(n,r,u){if(t(n,r,u))return e=r,false}),e}function _(n,t,r,e){var u=n.length;for(r+=e?1:-1;e?r--:++r<u;)if(t(n[r],r,n))return r;return-1}function v(n,t,r){if(t===t)n:{--r;for(var e=n.length;++r<e;)if(n[r]===t){n=r;break n}n=-1}else n=_(n,d,r);return n}function g(n,t,r,e){
+--r;for(var u=n.length;++r<u;)if(e(n[r],t))return r;return-1}function d(n){return n!==n}function y(n,t){var r=null==n?0:n.length;return r?m(n,t)/r:F}function b(n){return function(t){return null==t?T:t[n]}}function x(n){return function(t){return null==n?T:n[t]}}function j(n,t,r,e,u){return u(n,function(n,u,i){r=e?(e=false,n):t(r,n,u,i)}),r}function w(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;return n}function m(n,t){for(var r,e=-1,u=n.length;++e<u;){var i=t(n[e]);i!==T&&(r=r===T?i:r+i)}return r;
+}function A(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function E(n,t){return c(t,function(t){return[t,n[t]]})}function k(n){return function(t){return n(t)}}function S(n,t){return c(t,function(t){return n[t]})}function O(n,t){return n.has(t)}function I(n,t){for(var r=-1,e=n.length;++r<e&&-1<v(t,n[r],0););return r}function R(n,t){for(var r=n.length;r--&&-1<v(t,n[r],0););return r}function z(n){return"\\"+Un[n]}function W(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n];
+}),r}function B(n,t){return function(r){return n(t(r))}}function L(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r];o!==t&&"__lodash_placeholder__"!==o||(n[r]="__lodash_placeholder__",i[u++]=r)}return i}function U(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function C(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=[n,n]}),r}function D(n){if(Rn.test(n)){for(var t=On.lastIndex=0;On.test(n);)++t;n=t}else n=Qn(n);return n}function M(n){return Rn.test(n)?n.match(On)||[]:n.split("");
+}var T,$=1/0,F=NaN,N=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],P=/\b__p\+='';/g,Z=/\b(__p\+=)''\+/g,q=/(__e\(.*?\)|\b__t\))\+'';/g,V=/&(?:amp|lt|gt|quot|#39);/g,K=/[&<>"']/g,G=RegExp(V.source),H=RegExp(K.source),J=/<%-([\s\S]+?)%>/g,Y=/<%([\s\S]+?)%>/g,Q=/<%=([\s\S]+?)%>/g,X=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,nn=/^\w*$/,tn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,rn=/[\\^$.*+?()[\]{}|]/g,en=RegExp(rn.source),un=/^\s+|\s+$/g,on=/^\s+/,fn=/\s+$/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,an=/\{\n\/\* \[wrapped with (.+)\] \*/,ln=/,? & /,sn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,hn=/\\(\\)?/g,pn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,_n=/\w*$/,vn=/^[-+]0x[0-9a-f]+$/i,gn=/^0b[01]+$/i,dn=/^\[object .+?Constructor\]$/,yn=/^0o[0-7]+$/i,bn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,wn=/['\n\r\u2028\u2029\\]/g,mn="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",An="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+mn,En="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",kn=RegExp("['\u2019]","g"),Sn=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),On=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+En+mn,"g"),In=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])|\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])|\\d+",An].join("|"),"g"),Rn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),zn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn="Array Buffer DataView Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Promise RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Bn={};
+Bn["[object Float32Array]"]=Bn["[object Float64Array]"]=Bn["[object Int8Array]"]=Bn["[object Int16Array]"]=Bn["[object Int32Array]"]=Bn["[object Uint8Array]"]=Bn["[object Uint8ClampedArray]"]=Bn["[object Uint16Array]"]=Bn["[object Uint32Array]"]=true,Bn["[object Arguments]"]=Bn["[object Array]"]=Bn["[object ArrayBuffer]"]=Bn["[object Boolean]"]=Bn["[object DataView]"]=Bn["[object Date]"]=Bn["[object Error]"]=Bn["[object Function]"]=Bn["[object Map]"]=Bn["[object Number]"]=Bn["[object Object]"]=Bn["[object RegExp]"]=Bn["[object Set]"]=Bn["[object String]"]=Bn["[object WeakMap]"]=false;
+var Ln={};Ln["[object Arguments]"]=Ln["[object Array]"]=Ln["[object ArrayBuffer]"]=Ln["[object DataView]"]=Ln["[object Boolean]"]=Ln["[object Date]"]=Ln["[object Float32Array]"]=Ln["[object Float64Array]"]=Ln["[object Int8Array]"]=Ln["[object Int16Array]"]=Ln["[object Int32Array]"]=Ln["[object Map]"]=Ln["[object Number]"]=Ln["[object Object]"]=Ln["[object RegExp]"]=Ln["[object Set]"]=Ln["[object String]"]=Ln["[object Symbol]"]=Ln["[object Uint8Array]"]=Ln["[object Uint8ClampedArray]"]=Ln["[object Uint16Array]"]=Ln["[object Uint32Array]"]=true,
+Ln["[object Error]"]=Ln["[object Function]"]=Ln["[object WeakMap]"]=false;var Un={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Cn=parseFloat,Dn=parseInt,Mn=typeof global=="object"&&global&&global.Object===Object&&global,Tn=typeof self=="object"&&self&&self.Object===Object&&self,$n=Mn||Tn||Function("return this")(),Fn=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Nn=Fn&&typeof module=="object"&&module&&!module.nodeType&&module,Pn=Nn&&Nn.exports===Fn,Zn=Pn&&Mn.process,qn=function(){
+try{var n=Nn&&Nn.f&&Nn.f("util").types;return n?n:Zn&&Zn.binding&&Zn.binding("util")}catch(n){}}(),Vn=qn&&qn.isArrayBuffer,Kn=qn&&qn.isDate,Gn=qn&&qn.isMap,Hn=qn&&qn.isRegExp,Jn=qn&&qn.isSet,Yn=qn&&qn.isTypedArray,Qn=b("length"),Xn=x({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I",
+"\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C",
+"\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i",
+"\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r",
+"\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij",
+"\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),nt=x({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}),tt=x({"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'"}),rt=function x(mn){function An(n){if(yu(n)&&!ff(n)&&!(n instanceof Un)){if(n instanceof On)return n;if(oi.call(n,"__wrapped__"))return Fe(n)}return new On(n)}function En(){}function On(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=T}function Un(n){this.__wrapped__=n,
+this.__actions__=[],this.__dir__=1,this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Mn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Tn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Fn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Nn(n){var t=-1,r=null==n?0:n.length;for(this.__data__=new Fn;++t<r;)this.add(n[t]);
+}function Zn(n){this.size=(this.__data__=new Tn(n)).size}function qn(n,t){var r,e=ff(n),u=!e&&of(n),i=!e&&!u&&af(n),o=!e&&!u&&!i&&_f(n),u=(e=e||u||i||o)?A(n.length,ni):[],f=u.length;for(r in n)!t&&!oi.call(n,r)||e&&("length"==r||i&&("offset"==r||"parent"==r)||o&&("buffer"==r||"byteLength"==r||"byteOffset"==r)||Se(r,f))||u.push(r);return u}function Qn(n){var t=n.length;return t?n[ir(0,t-1)]:T}function et(n,t){return De(Ur(n),pt(t,0,n.length))}function ut(n){return De(Ur(n))}function it(n,t,r){(r===T||lu(n[t],r))&&(r!==T||t in n)||st(n,t,r);
+}function ot(n,t,r){var e=n[t];oi.call(n,t)&&lu(e,r)&&(r!==T||t in n)||st(n,t,r)}function ft(n,t){for(var r=n.length;r--;)if(lu(n[r][0],t))return r;return-1}function ct(n,t,r,e){return uo(n,function(n,u,i){t(e,n,r(n),i)}),e}function at(n,t){return n&&Cr(t,Wu(t),n)}function lt(n,t){return n&&Cr(t,Bu(t),n)}function st(n,t,r){"__proto__"==t&&Ai?Ai(n,t,{configurable:true,enumerable:true,value:r,writable:true}):n[t]=r}function ht(n,t){for(var r=-1,e=t.length,u=Ku(e),i=null==n;++r<e;)u[r]=i?T:Ru(n,t[r]);return u;
+}function pt(n,t,r){return n===n&&(r!==T&&(n=n<=r?n:r),t!==T&&(n=n>=t?n:t)),n}function _t(n,t,e,u,i,o){var f,c=1&t,a=2&t,l=4&t;if(e&&(f=i?e(n,u,i,o):e(n)),f!==T)return f;if(!du(n))return n;if(u=ff(n)){if(f=me(n),!c)return Ur(n,f)}else{var s=vo(n),h="[object Function]"==s||"[object GeneratorFunction]"==s;if(af(n))return Ir(n,c);if("[object Object]"==s||"[object Arguments]"==s||h&&!i){if(f=a||h?{}:Ae(n),!c)return a?Mr(n,lt(f,n)):Dr(n,at(f,n))}else{if(!Ln[s])return i?n:{};f=Ee(n,s,c)}}if(o||(o=new Zn),
+i=o.get(n))return i;o.set(n,f),pf(n)?n.forEach(function(r){f.add(_t(r,t,e,r,n,o))}):sf(n)&&n.forEach(function(r,u){f.set(u,_t(r,t,e,u,n,o))});var a=l?a?ve:_e:a?Bu:Wu,p=u?T:a(n);return r(p||n,function(r,u){p&&(u=r,r=n[u]),ot(f,u,_t(r,t,e,u,n,o))}),f}function vt(n){var t=Wu(n);return function(r){return gt(r,n,t)}}function gt(n,t,r){var e=r.length;if(null==n)return!e;for(n=Qu(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===T&&!(u in n)||!i(o))return false}return true}function dt(n,t,r){if(typeof n!="function")throw new ti("Expected a function");
+return bo(function(){n.apply(T,r)},t)}function yt(n,t,r,e){var u=-1,i=o,a=true,l=n.length,s=[],h=t.length;if(!l)return s;r&&(t=c(t,k(r))),e?(i=f,a=false):200<=t.length&&(i=O,a=false,t=new Nn(t));n:for(;++u<l;){var p=n[u],_=null==r?p:r(p),p=e||0!==p?p:0;if(a&&_===_){for(var v=h;v--;)if(t[v]===_)continue n;s.push(p)}else i(t,_,e)||s.push(p)}return s}function bt(n,t){var r=true;return uo(n,function(n,e,u){return r=!!t(n,e,u)}),r}function xt(n,t,r){for(var e=-1,u=n.length;++e<u;){var i=n[e],o=t(i);if(null!=o&&(f===T?o===o&&!wu(o):r(o,f)))var f=o,c=i;
+}return c}function jt(n,t){var r=[];return uo(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function wt(n,t,r,e,u){var i=-1,o=n.length;for(r||(r=ke),u||(u=[]);++i<o;){var f=n[i];0<t&&r(f)?1<t?wt(f,t-1,r,e,u):a(u,f):e||(u[u.length]=f)}return u}function mt(n,t){return n&&oo(n,t,Wu)}function At(n,t){return n&&fo(n,t,Wu)}function Et(n,t){return i(t,function(t){return _u(n[t])})}function kt(n,t){t=Sr(t,n);for(var r=0,e=t.length;null!=n&&r<e;)n=n[Me(t[r++])];return r&&r==e?n:T}function St(n,t,r){return t=t(n),
+ff(n)?t:a(t,r(n))}function Ot(n){if(null==n)n=n===T?"[object Undefined]":"[object Null]";else if(mi&&mi in Qu(n)){var t=oi.call(n,mi),r=n[mi];try{n[mi]=T;var e=true}catch(n){}var u=ai.call(n);e&&(t?n[mi]=r:delete n[mi]),n=u}else n=ai.call(n);return n}function It(n,t){return n>t}function Rt(n,t){return null!=n&&oi.call(n,t)}function zt(n,t){return null!=n&&t in Qu(n)}function Wt(n,t,r){for(var e=r?f:o,u=n[0].length,i=n.length,a=i,l=Ku(i),s=1/0,h=[];a--;){var p=n[a];a&&t&&(p=c(p,k(t))),s=Ci(p.length,s),
+l[a]=!r&&(t||120<=u&&120<=p.length)?new Nn(a&&p):T}var p=n[0],_=-1,v=l[0];n:for(;++_<u&&h.length<s;){var g=p[_],d=t?t(g):g,g=r||0!==g?g:0;if(v?!O(v,d):!e(h,d,r)){for(a=i;--a;){var y=l[a];if(y?!O(y,d):!e(n[a],d,r))continue n}v&&v.push(d),h.push(g)}}return h}function Bt(n,t,r){var e={};return mt(n,function(n,u,i){t(e,r(n),u,i)}),e}function Lt(t,r,e){return r=Sr(r,t),t=2>r.length?t:kt(t,hr(r,0,-1)),r=null==t?t:t[Me(Ve(r))],null==r?T:n(r,t,e)}function Ut(n){return yu(n)&&"[object Arguments]"==Ot(n)}function Ct(n){
+return yu(n)&&"[object ArrayBuffer]"==Ot(n)}function Dt(n){return yu(n)&&"[object Date]"==Ot(n)}function Mt(n,t,r,e,u){if(n===t)t=true;else if(null==n||null==t||!yu(n)&&!yu(t))t=n!==n&&t!==t;else n:{var i=ff(n),o=ff(t),f=i?"[object Array]":vo(n),c=o?"[object Array]":vo(t),f="[object Arguments]"==f?"[object Object]":f,c="[object Arguments]"==c?"[object Object]":c,a="[object Object]"==f,o="[object Object]"==c;if((c=f==c)&&af(n)){if(!af(t)){t=false;break n}i=true,a=false}if(c&&!a)u||(u=new Zn),t=i||_f(n)?se(n,t,r,e,Mt,u):he(n,t,f,r,e,Mt,u);else{
+if(!(1&r)&&(i=a&&oi.call(n,"__wrapped__"),f=o&&oi.call(t,"__wrapped__"),i||f)){n=i?n.value():n,t=f?t.value():t,u||(u=new Zn),t=Mt(n,t,r,e,u);break n}if(c)t:if(u||(u=new Zn),i=1&r,f=_e(n),o=f.length,c=_e(t).length,o==c||i){for(a=o;a--;){var l=f[a];if(!(i?l in t:oi.call(t,l))){t=false;break t}}if((c=u.get(n))&&u.get(t))t=c==t;else{c=true,u.set(n,t),u.set(t,n);for(var s=i;++a<o;){var l=f[a],h=n[l],p=t[l];if(e)var _=i?e(p,h,l,t,n,u):e(h,p,l,n,t,u);if(_===T?h!==p&&!Mt(h,p,r,e,u):!_){c=false;break}s||(s="constructor"==l);
+}c&&!s&&(r=n.constructor,e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(c=false)),u.delete(n),u.delete(t),t=c}}else t=false;else t=false}}return t}function Tt(n){return yu(n)&&"[object Map]"==vo(n)}function $t(n,t,r,e){var u=r.length,i=u,o=!e;if(null==n)return!i;for(n=Qu(n);u--;){var f=r[u];if(o&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return false}for(;++u<i;){var f=r[u],c=f[0],a=n[c],l=f[1];if(o&&f[2]){if(a===T&&!(c in n))return false;
+}else{if(f=new Zn,e)var s=e(a,l,c,n,t,f);if(s===T?!Mt(l,a,3,e,f):!s)return false}}return true}function Ft(n){return!(!du(n)||ci&&ci in n)&&(_u(n)?hi:dn).test(Te(n))}function Nt(n){return yu(n)&&"[object RegExp]"==Ot(n)}function Pt(n){return yu(n)&&"[object Set]"==vo(n)}function Zt(n){return yu(n)&&gu(n.length)&&!!Bn[Ot(n)]}function qt(n){return typeof n=="function"?n:null==n?$u:typeof n=="object"?ff(n)?Jt(n[0],n[1]):Ht(n):Zu(n)}function Vt(n){if(!ze(n))return Li(n);var t,r=[];for(t in Qu(n))oi.call(n,t)&&"constructor"!=t&&r.push(t);
+return r}function Kt(n,t){return n<t}function Gt(n,t){var r=-1,e=su(n)?Ku(n.length):[];return uo(n,function(n,u,i){e[++r]=t(n,u,i)}),e}function Ht(n){var t=xe(n);return 1==t.length&&t[0][2]?We(t[0][0],t[0][1]):function(r){return r===n||$t(r,n,t)}}function Jt(n,t){return Ie(n)&&t===t&&!du(t)?We(Me(n),t):function(r){var e=Ru(r,n);return e===T&&e===t?zu(r,n):Mt(t,e,3)}}function Yt(n,t,r,e,u){n!==t&&oo(t,function(i,o){if(u||(u=new Zn),du(i)){var f=u,c=Le(n,o),a=Le(t,o),l=f.get(a);if(l)it(n,o,l);else{
+var l=e?e(c,a,o+"",n,t,f):T,s=l===T;if(s){var h=ff(a),p=!h&&af(a),_=!h&&!p&&_f(a),l=a;h||p||_?ff(c)?l=c:hu(c)?l=Ur(c):p?(s=false,l=Ir(a,true)):_?(s=false,l=zr(a,true)):l=[]:xu(a)||of(a)?(l=c,of(c)?l=Ou(c):du(c)&&!_u(c)||(l=Ae(a))):s=false}s&&(f.set(a,l),Yt(l,a,r,e,f),f.delete(a)),it(n,o,l)}}else f=e?e(Le(n,o),i,o+"",n,t,u):T,f===T&&(f=i),it(n,o,f)},Bu)}function Qt(n,t){var r=n.length;if(r)return t+=0>t?r:0,Se(t,r)?n[t]:T}function Xt(n,t,r){var e=-1;return t=c(t.length?t:[$u],k(ye())),n=Gt(n,function(n){return{
+a:c(t,function(t){return t(n)}),b:++e,c:n}}),w(n,function(n,t){var e;n:{e=-1;for(var u=n.a,i=t.a,o=u.length,f=r.length;++e<o;){var c=Wr(u[e],i[e]);if(c){e=e>=f?c:c*("desc"==r[e]?-1:1);break n}}e=n.b-t.b}return e})}function nr(n,t){return tr(n,t,function(t,r){return zu(n,r)})}function tr(n,t,r){for(var e=-1,u=t.length,i={};++e<u;){var o=t[e],f=kt(n,o);r(f,o)&&lr(i,Sr(o,n),f)}return i}function rr(n){return function(t){return kt(t,n)}}function er(n,t,r,e){var u=e?g:v,i=-1,o=t.length,f=n;for(n===t&&(t=Ur(t)),
+r&&(f=c(n,k(r)));++i<o;)for(var a=0,l=t[i],l=r?r(l):l;-1<(a=u(f,l,a,e));)f!==n&&xi.call(f,a,1),xi.call(n,a,1);return n}function ur(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;Se(u)?xi.call(n,u,1):xr(n,u)}}}function ir(n,t){return n+Ii(Ti()*(t-n+1))}function or(n,t){var r="";if(!n||1>t||9007199254740991<t)return r;do t%2&&(r+=n),(t=Ii(t/2))&&(n+=n);while(t);return r}function fr(n,t){return xo(Be(n,t,$u),n+"")}function cr(n){return Qn(Uu(n))}function ar(n,t){var r=Uu(n);
+return De(r,pt(t,0,r.length))}function lr(n,t,r,e){if(!du(n))return n;t=Sr(t,n);for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++u<i;){var c=Me(t[u]),a=r;if(u!=o){var l=f[c],a=e?e(l,c,f):T;a===T&&(a=du(l)?l:Se(t[u+1])?[]:{})}ot(f,c,a),f=f[c]}return n}function sr(n){return De(Uu(n))}function hr(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Ku(u);++e<u;)r[e]=n[e+t];return r}function pr(n,t){var r;return uo(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}
+function _r(n,t,r){var e=0,u=null==n?e:n.length;if(typeof t=="number"&&t===t&&2147483647>=u){for(;e<u;){var i=e+u>>>1,o=n[i];null!==o&&!wu(o)&&(r?o<=t:o<t)?e=i+1:u=i}return u}return vr(n,t,$u,r)}function vr(n,t,r,e){t=r(t);for(var u=0,i=null==n?0:n.length,o=t!==t,f=null===t,c=wu(t),a=t===T;u<i;){var l=Ii((u+i)/2),s=r(n[l]),h=s!==T,p=null===s,_=s===s,v=wu(s);(o?e||_:a?_&&(e||h):f?_&&h&&(e||!p):c?_&&h&&!p&&(e||!v):p||v?0:e?s<=t:s<t)?u=l+1:i=l}return Ci(i,4294967294)}function gr(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){
+var o=n[r],f=t?t(o):o;if(!r||!lu(f,c)){var c=f;i[u++]=0===o?0:o}}return i}function dr(n){return typeof n=="number"?n:wu(n)?F:+n}function yr(n){if(typeof n=="string")return n;if(ff(n))return c(n,yr)+"";if(wu(n))return ro?ro.call(n):"";var t=n+"";return"0"==t&&1/n==-$?"-0":t}function br(n,t,r){var e=-1,u=o,i=n.length,c=true,a=[],l=a;if(r)c=false,u=f;else if(200<=i){if(u=t?null:so(n))return U(u);c=false,u=O,l=new Nn}else l=t?[]:a;n:for(;++e<i;){var s=n[e],h=t?t(s):s,s=r||0!==s?s:0;if(c&&h===h){for(var p=l.length;p--;)if(l[p]===h)continue n;
+t&&l.push(h),a.push(s)}else u(l,h,r)||(l!==a&&l.push(h),a.push(s))}return a}function xr(n,t){return t=Sr(t,n),n=2>t.length?n:kt(n,hr(t,0,-1)),null==n||delete n[Me(Ve(t))]}function jr(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++i<u)&&t(n[i],i,n););return r?hr(n,e?0:i,e?i+1:u):hr(n,e?i+1:0,e?u:i)}function wr(n,t){var r=n;return r instanceof Un&&(r=r.value()),l(t,function(n,t){return t.func.apply(t.thisArg,a([n],t.args))},r)}function mr(n,t,r){var e=n.length;if(2>e)return e?br(n[0]):[];for(var u=-1,i=Ku(e);++u<e;)for(var o=n[u],f=-1;++f<e;)f!=u&&(i[u]=yt(i[u]||o,n[f],t,r));
+return br(wt(i,1),t,r)}function Ar(n,t,r){for(var e=-1,u=n.length,i=t.length,o={};++e<u;)r(o,n[e],e<i?t[e]:T);return o}function Er(n){return hu(n)?n:[]}function kr(n){return typeof n=="function"?n:$u}function Sr(n,t){return ff(n)?n:Ie(n,t)?[n]:jo(Iu(n))}function Or(n,t,r){var e=n.length;return r=r===T?e:r,!t&&r>=e?n:hr(n,t,r)}function Ir(n,t){if(t)return n.slice();var r=n.length,r=gi?gi(r):new n.constructor(r);return n.copy(r),r}function Rr(n){var t=new n.constructor(n.byteLength);return new vi(t).set(new vi(n)),
+t}function zr(n,t){return new n.constructor(t?Rr(n.buffer):n.buffer,n.byteOffset,n.length)}function Wr(n,t){if(n!==t){var r=n!==T,e=null===n,u=n===n,i=wu(n),o=t!==T,f=null===t,c=t===t,a=wu(t);if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n<t||a&&r&&u&&!e&&!i||f&&r&&u||!o&&u||!c)return-1}return 0}function Br(n,t,r,e){var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Ui(i-o,0),l=Ku(c+a);for(e=!e;++f<c;)l[f]=t[f];for(;++u<o;)(e||u<i)&&(l[r[u]]=n[u]);for(;a--;)l[f++]=n[u++];
+return l}function Lr(n,t,r,e){var u=-1,i=n.length,o=-1,f=r.length,c=-1,a=t.length,l=Ui(i-f,0),s=Ku(l+a);for(e=!e;++u<l;)s[u]=n[u];for(l=u;++c<a;)s[l+c]=t[c];for(;++o<f;)(e||u<i)&&(s[l+r[o]]=n[u++]);return s}function Ur(n,t){var r=-1,e=n.length;for(t||(t=Ku(e));++r<e;)t[r]=n[r];return t}function Cr(n,t,r,e){var u=!r;r||(r={});for(var i=-1,o=t.length;++i<o;){var f=t[i],c=e?e(r[f],n[f],f,r,n):T;c===T&&(c=n[f]),u?st(r,f,c):ot(r,f,c)}return r}function Dr(n,t){return Cr(n,po(n),t)}function Mr(n,t){return Cr(n,_o(n),t);
+}function Tr(n,r){return function(e,u){var i=ff(e)?t:ct,o=r?r():{};return i(e,n,ye(u,2),o)}}function $r(n){return fr(function(t,r){var e=-1,u=r.length,i=1<u?r[u-1]:T,o=2<u?r[2]:T,i=3<n.length&&typeof i=="function"?(u--,i):T;for(o&&Oe(r[0],r[1],o)&&(i=3>u?T:i,u=1),t=Qu(t);++e<u;)(o=r[e])&&n(t,o,e,i);return t})}function Fr(n,t){return function(r,e){if(null==r)return r;if(!su(r))return n(r,e);for(var u=r.length,i=t?u:-1,o=Qu(r);(t?i--:++i<u)&&false!==e(o[i],i,o););return r}}function Nr(n){return function(t,r,e){
+var u=-1,i=Qu(t);e=e(t);for(var o=e.length;o--;){var f=e[n?o:++u];if(false===r(i[f],f,i))break}return t}}function Pr(n,t,r){function e(){return(this&&this!==$n&&this instanceof e?i:n).apply(u?r:this,arguments)}var u=1&t,i=Vr(n);return e}function Zr(n){return function(t){t=Iu(t);var r=Rn.test(t)?M(t):T,e=r?r[0]:t.charAt(0);return t=r?Or(r,1).join(""):t.slice(1),e[n]()+t}}function qr(n){return function(t){return l(Mu(Du(t).replace(kn,"")),n,"")}}function Vr(n){return function(){var t=arguments;switch(t.length){
+case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=eo(n.prototype),t=n.apply(r,t);return du(t)?t:r}}function Kr(t,r,e){function u(){for(var o=arguments.length,f=Ku(o),c=o,a=de(u);c--;)f[c]=arguments[c];return c=3>o&&f[0]!==a&&f[o-1]!==a?[]:L(f,a),
+o-=c.length,o<e?ue(t,r,Jr,u.placeholder,T,f,c,T,T,e-o):n(this&&this!==$n&&this instanceof u?i:t,this,f)}var i=Vr(t);return u}function Gr(n){return function(t,r,e){var u=Qu(t);if(!su(t)){var i=ye(r,3);t=Wu(t),r=function(n){return i(u[n],n,u)}}return r=n(t,r,e),-1<r?u[i?t[r]:r]:T}}function Hr(n){return pe(function(t){var r=t.length,e=r,u=On.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if(typeof i!="function")throw new ti("Expected a function");if(u&&!o&&"wrapper"==ge(i))var o=new On([],true)}for(e=o?e:r;++e<r;)var i=t[e],u=ge(i),f="wrapper"==u?ho(i):T,o=f&&Re(f[0])&&424==f[1]&&!f[4].length&&1==f[9]?o[ge(f[0])].apply(o,f[3]):1==i.length&&Re(i)?o[u]():o.thru(i);
+return function(){var n=arguments,e=n[0];if(o&&1==n.length&&ff(e))return o.plant(e).value();for(var u=0,n=r?t[u].apply(this,n):e;++u<r;)n=t[u].call(this,n);return n}})}function Jr(n,t,r,e,u,i,o,f,c,a){function l(){for(var d=arguments.length,y=Ku(d),b=d;b--;)y[b]=arguments[b];if(_){var x,j=de(l),b=y.length;for(x=0;b--;)y[b]===j&&++x}if(e&&(y=Br(y,e,u,_)),i&&(y=Lr(y,i,o,_)),d-=x,_&&d<a)return j=L(y,j),ue(n,t,Jr,l.placeholder,r,y,j,f,c,a-d);if(j=h?r:this,b=p?j[n]:n,d=y.length,f){x=y.length;for(var w=Ci(f.length,x),m=Ur(y);w--;){
+var A=f[w];y[w]=Se(A,x)?m[A]:T}}else v&&1<d&&y.reverse();return s&&c<d&&(y.length=c),this&&this!==$n&&this instanceof l&&(b=g||Vr(b)),b.apply(j,y)}var s=128&t,h=1&t,p=2&t,_=24&t,v=512&t,g=p?T:Vr(n);return l}function Yr(n,t){return function(r,e){return Bt(r,n,t(e))}}function Qr(n,t){return function(r,e){var u;if(r===T&&e===T)return t;if(r!==T&&(u=r),e!==T){if(u===T)return e;typeof r=="string"||typeof e=="string"?(r=yr(r),e=yr(e)):(r=dr(r),e=dr(e)),u=n(r,e)}return u}}function Xr(t){return pe(function(r){
+return r=c(r,k(ye())),fr(function(e){var u=this;return t(r,function(t){return n(t,u,e)})})})}function ne(n,t){t=t===T?" ":yr(t);var r=t.length;return 2>r?r?or(t,n):t:(r=or(t,Oi(n/D(t))),Rn.test(t)?Or(M(r),0,n).join(""):r.slice(0,n))}function te(t,r,e,u){function i(){for(var r=-1,c=arguments.length,a=-1,l=u.length,s=Ku(l+c),h=this&&this!==$n&&this instanceof i?f:t;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++r];return n(h,o?e:this,s)}var o=1&r,f=Vr(t);return i}function re(n){return function(t,r,e){
+e&&typeof e!="number"&&Oe(t,r,e)&&(r=e=T),t=Au(t),r===T?(r=t,t=0):r=Au(r),e=e===T?t<r?1:-1:Au(e);var u=-1;r=Ui(Oi((r-t)/(e||1)),0);for(var i=Ku(r);r--;)i[n?r:++u]=t,t+=e;return i}}function ee(n){return function(t,r){return typeof t=="string"&&typeof r=="string"||(t=Su(t),r=Su(r)),n(t,r)}}function ue(n,t,r,e,u,i,o,f,c,a){var l=8&t,s=l?o:T;o=l?T:o;var h=l?i:T;return i=l?T:i,t=(t|(l?32:64))&~(l?64:32),4&t||(t&=-4),u=[n,t,u,h,s,i,o,f,c,a],r=r.apply(T,u),Re(n)&&yo(r,u),r.placeholder=e,Ue(r,n,t)}function ie(n){
+var t=Yu[n];return function(n,r){if(n=Su(n),(r=null==r?0:Ci(Eu(r),292))&&Wi(n)){var e=(Iu(n)+"e").split("e"),e=t(e[0]+"e"+(+e[1]+r)),e=(Iu(e)+"e").split("e");return+(e[0]+"e"+(+e[1]-r))}return t(n)}}function oe(n){return function(t){var r=vo(t);return"[object Map]"==r?W(t):"[object Set]"==r?C(t):E(t,n(t))}}function fe(n,t,r,e,u,i,o,f){var c=2&t;if(!c&&typeof n!="function")throw new ti("Expected a function");var a=e?e.length:0;if(a||(t&=-97,e=u=T),o=o===T?o:Ui(Eu(o),0),f=f===T?f:Eu(f),a-=u?u.length:0,
+64&t){var l=e,s=u;e=u=T}var h=c?T:ho(n);return i=[n,t,r,e,u,l,s,i,o,f],h&&(r=i[1],n=h[1],t=r|n,e=128==n&&8==r||128==n&&256==r&&i[7].length<=h[8]||384==n&&h[7].length<=h[8]&&8==r,131>t||e)&&(1&n&&(i[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=i[3],i[3]=e?Br(e,r,h[4]):r,i[4]=e?L(i[3],"__lodash_placeholder__"):h[4]),(r=h[5])&&(e=i[5],i[5]=e?Lr(e,r,h[6]):r,i[6]=e?L(i[5],"__lodash_placeholder__"):h[6]),(r=h[7])&&(i[7]=r),128&n&&(i[8]=null==i[8]?h[8]:Ci(i[8],h[8])),null==i[9]&&(i[9]=h[9]),i[0]=h[0],i[1]=t),n=i[0],
+t=i[1],r=i[2],e=i[3],u=i[4],f=i[9]=i[9]===T?c?0:n.length:Ui(i[9]-a,0),!f&&24&t&&(t&=-25),Ue((h?co:yo)(t&&1!=t?8==t||16==t?Kr(n,t,f):32!=t&&33!=t||u.length?Jr.apply(T,i):te(n,t,r,e):Pr(n,t,r),i),n,t)}function ce(n,t,r,e){return n===T||lu(n,ei[r])&&!oi.call(e,r)?t:n}function ae(n,t,r,e,u,i){return du(n)&&du(t)&&(i.set(t,n),Yt(n,t,T,ae,i),i.delete(t)),n}function le(n){return xu(n)?T:n}function se(n,t,r,e,u,i){var o=1&r,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return false;if((c=i.get(n))&&i.get(t))return c==t;
+var c=-1,a=true,l=2&r?new Nn:T;for(i.set(n,t),i.set(t,n);++c<f;){var s=n[c],p=t[c];if(e)var _=o?e(p,s,c,t,n,i):e(s,p,c,n,t,i);if(_!==T){if(_)continue;a=false;break}if(l){if(!h(t,function(n,t){if(!O(l,t)&&(s===n||u(s,n,r,e,i)))return l.push(t)})){a=false;break}}else if(s!==p&&!u(s,p,r,e,i)){a=false;break}}return i.delete(n),i.delete(t),a}function he(n,t,r,e,u,i,o){switch(r){case"[object DataView]":if(n.byteLength!=t.byteLength||n.byteOffset!=t.byteOffset)break;n=n.buffer,t=t.buffer;case"[object ArrayBuffer]":
+if(n.byteLength!=t.byteLength||!i(new vi(n),new vi(t)))break;return true;case"[object Boolean]":case"[object Date]":case"[object Number]":return lu(+n,+t);case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object RegExp]":case"[object String]":return n==t+"";case"[object Map]":var f=W;case"[object Set]":if(f||(f=U),n.size!=t.size&&!(1&e))break;return(r=o.get(n))?r==t:(e|=2,o.set(n,t),t=se(f(n),f(t),e,u,i,o),o.delete(n),t);case"[object Symbol]":if(to)return to.call(n)==to.call(t)}
+return false}function pe(n){return xo(Be(n,T,Ze),n+"")}function _e(n){return St(n,Wu,po)}function ve(n){return St(n,Bu,_o)}function ge(n){for(var t=n.name+"",r=Gi[t],e=oi.call(Gi,t)?r.length:0;e--;){var u=r[e],i=u.func;if(null==i||i==n)return u.name}return t}function de(n){return(oi.call(An,"placeholder")?An:n).placeholder}function ye(){var n=An.iteratee||Fu,n=n===Fu?qt:n;return arguments.length?n(arguments[0],arguments[1]):n}function be(n,t){var r=n.__data__,e=typeof t;return("string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t)?r[typeof t=="string"?"string":"hash"]:r.map;
+}function xe(n){for(var t=Wu(n),r=t.length;r--;){var e=t[r],u=n[e];t[r]=[e,u,u===u&&!du(u)]}return t}function je(n,t){var r=null==n?T:n[t];return Ft(r)?r:T}function we(n,t,r){t=Sr(t,n);for(var e=-1,u=t.length,i=false;++e<u;){var o=Me(t[e]);if(!(i=null!=n&&r(n,o)))break;n=n[o]}return i||++e!=u?i:(u=null==n?0:n.length,!!u&&gu(u)&&Se(o,u)&&(ff(n)||of(n)))}function me(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&oi.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Ae(n){
+return typeof n.constructor!="function"||ze(n)?{}:eo(di(n))}function Ee(n,t,r){var e=n.constructor;switch(t){case"[object ArrayBuffer]":return Rr(n);case"[object Boolean]":case"[object Date]":return new e(+n);case"[object DataView]":return t=r?Rr(n.buffer):n.buffer,new n.constructor(t,n.byteOffset,n.byteLength);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":
+case"[object Uint16Array]":case"[object Uint32Array]":return zr(n,r);case"[object Map]":return new e;case"[object Number]":case"[object String]":return new e(n);case"[object RegExp]":return t=new n.constructor(n.source,_n.exec(n)),t.lastIndex=n.lastIndex,t;case"[object Set]":return new e;case"[object Symbol]":return to?Qu(to.call(n)):{}}}function ke(n){return ff(n)||of(n)||!!(ji&&n&&n[ji])}function Se(n,t){var r=typeof n;return t=null==t?9007199254740991:t,!!t&&("number"==r||"symbol"!=r&&bn.test(n))&&-1<n&&0==n%1&&n<t;
+}function Oe(n,t,r){if(!du(r))return false;var e=typeof t;return!!("number"==e?su(r)&&Se(t,r.length):"string"==e&&t in r)&&lu(r[t],n)}function Ie(n,t){if(ff(n))return false;var r=typeof n;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=n&&!wu(n))||(nn.test(n)||!X.test(n)||null!=t&&n in Qu(t))}function Re(n){var t=ge(n),r=An[t];return typeof r=="function"&&t in Un.prototype&&(n===r||(t=ho(r),!!t&&n===t[0]))}function ze(n){var t=n&&n.constructor;return n===(typeof t=="function"&&t.prototype||ei)}function We(n,t){
+return function(r){return null!=r&&(r[n]===t&&(t!==T||n in Qu(r)))}}function Be(t,r,e){return r=Ui(r===T?t.length-1:r,0),function(){for(var u=arguments,i=-1,o=Ui(u.length-r,0),f=Ku(o);++i<o;)f[i]=u[r+i];for(i=-1,o=Ku(r+1);++i<r;)o[i]=u[i];return o[r]=e(f),n(t,this,o)}}function Le(n,t){if(("constructor"!==t||"function"!=typeof n[t])&&"__proto__"!=t)return n[t]}function Ue(n,t,r){var e=t+"";t=xo;var u,i=$e;return u=(u=e.match(an))?u[1].split(ln):[],r=i(u,r),(i=r.length)&&(u=i-1,r[u]=(1<i?"& ":"")+r[u],
+r=r.join(2<i?", ":" "),e=e.replace(cn,"{\n/* [wrapped with "+r+"] */\n")),t(n,e)}function Ce(n){var t=0,r=0;return function(){var e=Di(),u=16-(e-r);if(r=e,0<u){if(800<=++t)return arguments[0]}else t=0;return n.apply(T,arguments)}}function De(n,t){var r=-1,e=n.length,u=e-1;for(t=t===T?e:t;++r<t;){var e=ir(r,u),i=n[e];n[e]=n[r],n[r]=i}return n.length=t,n}function Me(n){if(typeof n=="string"||wu(n))return n;var t=n+"";return"0"==t&&1/n==-$?"-0":t}function Te(n){if(null!=n){try{return ii.call(n)}catch(n){}
+return n+""}return""}function $e(n,t){return r(N,function(r){var e="_."+r[0];t&r[1]&&!o(n,e)&&n.push(e)}),n.sort()}function Fe(n){if(n instanceof Un)return n.clone();var t=new On(n.__wrapped__,n.__chain__);return t.__actions__=Ur(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function Ne(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Eu(r),0>r&&(r=Ui(e+r,0)),_(n,ye(t,3),r)):-1}function Pe(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==T&&(u=Eu(r),u=0>r?Ui(e+u,0):Ci(u,e-1)),
+_(n,ye(t,3),u,true)}function Ze(n){return(null==n?0:n.length)?wt(n,1):[]}function qe(n){return n&&n.length?n[0]:T}function Ve(n){var t=null==n?0:n.length;return t?n[t-1]:T}function Ke(n,t){return n&&n.length&&t&&t.length?er(n,t):n}function Ge(n){return null==n?n:$i.call(n)}function He(n){if(!n||!n.length)return[];var t=0;return n=i(n,function(n){if(hu(n))return t=Ui(n.length,t),true}),A(t,function(t){return c(n,b(t))})}function Je(t,r){if(!t||!t.length)return[];var e=He(t);return null==r?e:c(e,function(t){
+return n(r,T,t)})}function Ye(n){return n=An(n),n.__chain__=true,n}function Qe(n,t){return t(n)}function Xe(){return this}function nu(n,t){return(ff(n)?r:uo)(n,ye(t,3))}function tu(n,t){return(ff(n)?e:io)(n,ye(t,3))}function ru(n,t){return(ff(n)?c:Gt)(n,ye(t,3))}function eu(n,t,r){return t=r?T:t,t=n&&null==t?n.length:t,fe(n,128,T,T,T,T,t)}function uu(n,t){var r;if(typeof t!="function")throw new ti("Expected a function");return n=Eu(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=T),
+r}}function iu(n,t,r){return t=r?T:t,n=fe(n,8,T,T,T,T,T,t),n.placeholder=iu.placeholder,n}function ou(n,t,r){return t=r?T:t,n=fe(n,16,T,T,T,T,T,t),n.placeholder=ou.placeholder,n}function fu(n,t,r){function e(t){var r=c,e=a;return c=a=T,_=t,s=n.apply(e,r)}function u(n){var r=n-p;return n-=_,p===T||r>=t||0>r||g&&n>=l}function i(){var n=Go();if(u(n))return o(n);var r,e=bo;r=n-_,n=t-(n-p),r=g?Ci(n,l-r):n,h=e(i,r)}function o(n){return h=T,d&&c?e(n):(c=a=T,s)}function f(){var n=Go(),r=u(n);if(c=arguments,
+a=this,p=n,r){if(h===T)return _=n=p,h=bo(i,t),v?e(n):s;if(g)return lo(h),h=bo(i,t),e(p)}return h===T&&(h=bo(i,t)),s}var c,a,l,s,h,p,_=0,v=false,g=false,d=true;if(typeof n!="function")throw new ti("Expected a function");return t=Su(t)||0,du(r)&&(v=!!r.leading,l=(g="maxWait"in r)?Ui(Su(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),f.cancel=function(){h!==T&&lo(h),_=0,c=p=a=h=T},f.flush=function(){return h===T?s:o(Go())},f}function cu(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;
+return i.has(u)?i.get(u):(e=n.apply(this,e),r.cache=i.set(u,e)||i,e)}if(typeof n!="function"||null!=t&&typeof t!="function")throw new ti("Expected a function");return r.cache=new(cu.Cache||Fn),r}function au(n){if(typeof n!="function")throw new ti("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function lu(n,t){return n===t||n!==n&&t!==t;
+}function su(n){return null!=n&&gu(n.length)&&!_u(n)}function hu(n){return yu(n)&&su(n)}function pu(n){if(!yu(n))return false;var t=Ot(n);return"[object Error]"==t||"[object DOMException]"==t||typeof n.message=="string"&&typeof n.name=="string"&&!xu(n)}function _u(n){return!!du(n)&&(n=Ot(n),"[object Function]"==n||"[object GeneratorFunction]"==n||"[object AsyncFunction]"==n||"[object Proxy]"==n)}function vu(n){return typeof n=="number"&&n==Eu(n)}function gu(n){return typeof n=="number"&&-1<n&&0==n%1&&9007199254740991>=n;
+}function du(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function yu(n){return null!=n&&typeof n=="object"}function bu(n){return typeof n=="number"||yu(n)&&"[object Number]"==Ot(n)}function xu(n){return!(!yu(n)||"[object Object]"!=Ot(n))&&(n=di(n),null===n||(n=oi.call(n,"constructor")&&n.constructor,typeof n=="function"&&n instanceof n&&ii.call(n)==li))}function ju(n){return typeof n=="string"||!ff(n)&&yu(n)&&"[object String]"==Ot(n)}function wu(n){return typeof n=="symbol"||yu(n)&&"[object Symbol]"==Ot(n);
+}function mu(n){if(!n)return[];if(su(n))return ju(n)?M(n):Ur(n);if(wi&&n[wi]){n=n[wi]();for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}return t=vo(n),("[object Map]"==t?W:"[object Set]"==t?U:Uu)(n)}function Au(n){return n?(n=Su(n),n===$||n===-$?1.7976931348623157e308*(0>n?-1:1):n===n?n:0):0===n?n:0}function Eu(n){n=Au(n);var t=n%1;return n===n?t?n-t:n:0}function ku(n){return n?pt(Eu(n),0,4294967295):0}function Su(n){if(typeof n=="number")return n;if(wu(n))return F;if(du(n)&&(n=typeof n.valueOf=="function"?n.valueOf():n,
+n=du(n)?n+"":n),typeof n!="string")return 0===n?n:+n;n=n.replace(un,"");var t=gn.test(n);return t||yn.test(n)?Dn(n.slice(2),t?2:8):vn.test(n)?F:+n}function Ou(n){return Cr(n,Bu(n))}function Iu(n){return null==n?"":yr(n)}function Ru(n,t,r){return n=null==n?T:kt(n,t),n===T?r:n}function zu(n,t){return null!=n&&we(n,t,zt)}function Wu(n){return su(n)?qn(n):Vt(n)}function Bu(n){if(su(n))n=qn(n,true);else if(du(n)){var t,r=ze(n),e=[];for(t in n)("constructor"!=t||!r&&oi.call(n,t))&&e.push(t);n=e}else{if(t=[],
+null!=n)for(r in Qu(n))t.push(r);n=t}return n}function Lu(n,t){if(null==n)return{};var r=c(ve(n),function(n){return[n]});return t=ye(t),tr(n,r,function(n,r){return t(n,r[0])})}function Uu(n){return null==n?[]:S(n,Wu(n))}function Cu(n){return $f(Iu(n).toLowerCase())}function Du(n){return(n=Iu(n))&&n.replace(xn,Xn).replace(Sn,"")}function Mu(n,t,r){return n=Iu(n),t=r?T:t,t===T?zn.test(n)?n.match(In)||[]:n.match(sn)||[]:n.match(t)||[]}function Tu(n){return function(){return n}}function $u(n){return n;
+}function Fu(n){return qt(typeof n=="function"?n:_t(n,1))}function Nu(n,t,e){var u=Wu(t),i=Et(t,u);null!=e||du(t)&&(i.length||!u.length)||(e=t,t=n,n=this,i=Et(t,Wu(t)));var o=!(du(e)&&"chain"in e&&!e.chain),f=_u(n);return r(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Ur(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,a([this.value()],arguments))})}),n}function Pu(){}
+function Zu(n){return Ie(n)?b(Me(n)):rr(n)}function qu(){return[]}function Vu(){return false}mn=null==mn?$n:rt.defaults($n.Object(),mn,rt.pick($n,Wn));var Ku=mn.Array,Gu=mn.Date,Hu=mn.Error,Ju=mn.Function,Yu=mn.Math,Qu=mn.Object,Xu=mn.RegExp,ni=mn.String,ti=mn.TypeError,ri=Ku.prototype,ei=Qu.prototype,ui=mn["__core-js_shared__"],ii=Ju.prototype.toString,oi=ei.hasOwnProperty,fi=0,ci=function(){var n=/[^.]+$/.exec(ui&&ui.keys&&ui.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),ai=ei.toString,li=ii.call(Qu),si=$n._,hi=Xu("^"+ii.call(oi).replace(rn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),pi=Pn?mn.Buffer:T,_i=mn.Symbol,vi=mn.Uint8Array,gi=pi?pi.g:T,di=B(Qu.getPrototypeOf,Qu),yi=Qu.create,bi=ei.propertyIsEnumerable,xi=ri.splice,ji=_i?_i.isConcatSpreadable:T,wi=_i?_i.iterator:T,mi=_i?_i.toStringTag:T,Ai=function(){
+try{var n=je(Qu,"defineProperty");return n({},"",{}),n}catch(n){}}(),Ei=mn.clearTimeout!==$n.clearTimeout&&mn.clearTimeout,ki=Gu&&Gu.now!==$n.Date.now&&Gu.now,Si=mn.setTimeout!==$n.setTimeout&&mn.setTimeout,Oi=Yu.ceil,Ii=Yu.floor,Ri=Qu.getOwnPropertySymbols,zi=pi?pi.isBuffer:T,Wi=mn.isFinite,Bi=ri.join,Li=B(Qu.keys,Qu),Ui=Yu.max,Ci=Yu.min,Di=Gu.now,Mi=mn.parseInt,Ti=Yu.random,$i=ri.reverse,Fi=je(mn,"DataView"),Ni=je(mn,"Map"),Pi=je(mn,"Promise"),Zi=je(mn,"Set"),qi=je(mn,"WeakMap"),Vi=je(Qu,"create"),Ki=qi&&new qi,Gi={},Hi=Te(Fi),Ji=Te(Ni),Yi=Te(Pi),Qi=Te(Zi),Xi=Te(qi),no=_i?_i.prototype:T,to=no?no.valueOf:T,ro=no?no.toString:T,eo=function(){
+function n(){}return function(t){return du(t)?yi?yi(t):(n.prototype=t,t=new n,n.prototype=T,t):{}}}();An.templateSettings={escape:J,evaluate:Y,interpolate:Q,variable:"",imports:{_:An}},An.prototype=En.prototype,An.prototype.constructor=An,On.prototype=eo(En.prototype),On.prototype.constructor=On,Un.prototype=eo(En.prototype),Un.prototype.constructor=Un,Mn.prototype.clear=function(){this.__data__=Vi?Vi(null):{},this.size=0},Mn.prototype.delete=function(n){return n=this.has(n)&&delete this.__data__[n],
+this.size-=n?1:0,n},Mn.prototype.get=function(n){var t=this.__data__;return Vi?(n=t[n],"__lodash_hash_undefined__"===n?T:n):oi.call(t,n)?t[n]:T},Mn.prototype.has=function(n){var t=this.__data__;return Vi?t[n]!==T:oi.call(t,n)},Mn.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=Vi&&t===T?"__lodash_hash_undefined__":t,this},Tn.prototype.clear=function(){this.__data__=[],this.size=0},Tn.prototype.delete=function(n){var t=this.__data__;return n=ft(t,n),!(0>n)&&(n==t.length-1?t.pop():xi.call(t,n,1),
+--this.size,true)},Tn.prototype.get=function(n){var t=this.__data__;return n=ft(t,n),0>n?T:t[n][1]},Tn.prototype.has=function(n){return-1<ft(this.__data__,n)},Tn.prototype.set=function(n,t){var r=this.__data__,e=ft(r,n);return 0>e?(++this.size,r.push([n,t])):r[e][1]=t,this},Fn.prototype.clear=function(){this.size=0,this.__data__={hash:new Mn,map:new(Ni||Tn),string:new Mn}},Fn.prototype.delete=function(n){return n=be(this,n).delete(n),this.size-=n?1:0,n},Fn.prototype.get=function(n){return be(this,n).get(n);
+},Fn.prototype.has=function(n){return be(this,n).has(n)},Fn.prototype.set=function(n,t){var r=be(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Nn.prototype.add=Nn.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Nn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.clear=function(){this.__data__=new Tn,this.size=0},Zn.prototype.delete=function(n){var t=this.__data__;return n=t.delete(n),this.size=t.size,n},Zn.prototype.get=function(n){
+return this.__data__.get(n)},Zn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Tn){var e=r.__data__;if(!Ni||199>e.length)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Fn(e)}return r.set(n,t),this.size=r.size,this};var uo=Fr(mt),io=Fr(At,true),oo=Nr(),fo=Nr(true),co=Ki?function(n,t){return Ki.set(n,t),n}:$u,ao=Ai?function(n,t){return Ai(n,"toString",{configurable:true,enumerable:false,value:Tu(t),writable:true})}:$u,lo=Ei||function(n){
+return $n.clearTimeout(n)},so=Zi&&1/U(new Zi([,-0]))[1]==$?function(n){return new Zi(n)}:Pu,ho=Ki?function(n){return Ki.get(n)}:Pu,po=Ri?function(n){return null==n?[]:(n=Qu(n),i(Ri(n),function(t){return bi.call(n,t)}))}:qu,_o=Ri?function(n){for(var t=[];n;)a(t,po(n)),n=di(n);return t}:qu,vo=Ot;(Fi&&"[object DataView]"!=vo(new Fi(new ArrayBuffer(1)))||Ni&&"[object Map]"!=vo(new Ni)||Pi&&"[object Promise]"!=vo(Pi.resolve())||Zi&&"[object Set]"!=vo(new Zi)||qi&&"[object WeakMap]"!=vo(new qi))&&(vo=function(n){
+var t=Ot(n);if(n=(n="[object Object]"==t?n.constructor:T)?Te(n):"")switch(n){case Hi:return"[object DataView]";case Ji:return"[object Map]";case Yi:return"[object Promise]";case Qi:return"[object Set]";case Xi:return"[object WeakMap]"}return t});var go=ui?_u:Vu,yo=Ce(co),bo=Si||function(n,t){return $n.setTimeout(n,t)},xo=Ce(ao),jo=function(n){n=cu(n,function(n){return 500===t.size&&t.clear(),n});var t=n.cache;return n}(function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(tn,function(n,r,e,u){
+t.push(e?u.replace(hn,"$1"):r||n)}),t}),wo=fr(function(n,t){return hu(n)?yt(n,wt(t,1,hu,true)):[]}),mo=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),ye(r,2)):[]}),Ao=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),T,r):[]}),Eo=fr(function(n){var t=c(n,Er);return t.length&&t[0]===n[0]?Wt(t):[]}),ko=fr(function(n){var t=Ve(n),r=c(n,Er);return t===Ve(r)?t=T:r.pop(),r.length&&r[0]===n[0]?Wt(r,ye(t,2)):[]}),So=fr(function(n){var t=Ve(n),r=c(n,Er);return(t=typeof t=="function"?t:T)&&r.pop(),
+r.length&&r[0]===n[0]?Wt(r,T,t):[]}),Oo=fr(Ke),Io=pe(function(n,t){var r=null==n?0:n.length,e=ht(n,t);return ur(n,c(t,function(n){return Se(n,r)?+n:n}).sort(Wr)),e}),Ro=fr(function(n){return br(wt(n,1,hu,true))}),zo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T),br(wt(n,1,hu,true),ye(t,2))}),Wo=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return br(wt(n,1,hu,true),T,t)}),Bo=fr(function(n,t){return hu(n)?yt(n,t):[]}),Lo=fr(function(n){return mr(i(n,hu))}),Uo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T),
+mr(i(n,hu),ye(t,2))}),Co=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return mr(i(n,hu),T,t)}),Do=fr(He),Mo=fr(function(n){var t=n.length,t=1<t?n[t-1]:T,t=typeof t=="function"?(n.pop(),t):T;return Je(n,t)}),To=pe(function(n){function t(t){return ht(t,n)}var r=n.length,e=r?n[0]:0,u=this.__wrapped__;return!(1<r||this.__actions__.length)&&u instanceof Un&&Se(e)?(u=u.slice(e,+e+(r?1:0)),u.__actions__.push({func:Qe,args:[t],thisArg:T}),new On(u,this.__chain__).thru(function(n){return r&&!n.length&&n.push(T),
+n})):this.thru(t)}),$o=Tr(function(n,t,r){oi.call(n,r)?++n[r]:st(n,r,1)}),Fo=Gr(Ne),No=Gr(Pe),Po=Tr(function(n,t,r){oi.call(n,r)?n[r].push(t):st(n,r,[t])}),Zo=fr(function(t,r,e){var u=-1,i=typeof r=="function",o=su(t)?Ku(t.length):[];return uo(t,function(t){o[++u]=i?n(r,t,e):Lt(t,r,e)}),o}),qo=Tr(function(n,t,r){st(n,r,t)}),Vo=Tr(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Ko=fr(function(n,t){if(null==n)return[];var r=t.length;return 1<r&&Oe(n,t[0],t[1])?t=[]:2<r&&Oe(t[0],t[1],t[2])&&(t=[t[0]]),
+Xt(n,wt(t,1),[])}),Go=ki||function(){return $n.Date.now()},Ho=fr(function(n,t,r){var e=1;if(r.length)var u=L(r,de(Ho)),e=32|e;return fe(n,e,t,r,u)}),Jo=fr(function(n,t,r){var e=3;if(r.length)var u=L(r,de(Jo)),e=32|e;return fe(t,e,n,r,u)}),Yo=fr(function(n,t){return dt(n,1,t)}),Qo=fr(function(n,t,r){return dt(n,Su(t)||0,r)});cu.Cache=Fn;var Xo=fr(function(t,r){r=1==r.length&&ff(r[0])?c(r[0],k(ye())):c(wt(r,1),k(ye()));var e=r.length;return fr(function(u){for(var i=-1,o=Ci(u.length,e);++i<o;)u[i]=r[i].call(this,u[i]);
+return n(t,this,u)})}),nf=fr(function(n,t){return fe(n,32,T,t,L(t,de(nf)))}),tf=fr(function(n,t){return fe(n,64,T,t,L(t,de(tf)))}),rf=pe(function(n,t){return fe(n,256,T,T,T,t)}),ef=ee(It),uf=ee(function(n,t){return n>=t}),of=Ut(function(){return arguments}())?Ut:function(n){return yu(n)&&oi.call(n,"callee")&&!bi.call(n,"callee")},ff=Ku.isArray,cf=Vn?k(Vn):Ct,af=zi||Vu,lf=Kn?k(Kn):Dt,sf=Gn?k(Gn):Tt,hf=Hn?k(Hn):Nt,pf=Jn?k(Jn):Pt,_f=Yn?k(Yn):Zt,vf=ee(Kt),gf=ee(function(n,t){return n<=t}),df=$r(function(n,t){
+if(ze(t)||su(t))Cr(t,Wu(t),n);else for(var r in t)oi.call(t,r)&&ot(n,r,t[r])}),yf=$r(function(n,t){Cr(t,Bu(t),n)}),bf=$r(function(n,t,r,e){Cr(t,Bu(t),n,e)}),xf=$r(function(n,t,r,e){Cr(t,Wu(t),n,e)}),jf=pe(ht),wf=fr(function(n,t){n=Qu(n);var r=-1,e=t.length,u=2<e?t[2]:T;for(u&&Oe(t[0],t[1],u)&&(e=1);++r<e;)for(var u=t[r],i=Bu(u),o=-1,f=i.length;++o<f;){var c=i[o],a=n[c];(a===T||lu(a,ei[c])&&!oi.call(n,c))&&(n[c]=u[c])}return n}),mf=fr(function(t){return t.push(T,ae),n(Of,T,t)}),Af=Yr(function(n,t,r){
+null!=t&&typeof t.toString!="function"&&(t=ai.call(t)),n[t]=r},Tu($u)),Ef=Yr(function(n,t,r){null!=t&&typeof t.toString!="function"&&(t=ai.call(t)),oi.call(n,t)?n[t].push(r):n[t]=[r]},ye),kf=fr(Lt),Sf=$r(function(n,t,r){Yt(n,t,r)}),Of=$r(function(n,t,r,e){Yt(n,t,r,e)}),If=pe(function(n,t){var r={};if(null==n)return r;var e=false;t=c(t,function(t){return t=Sr(t,n),e||(e=1<t.length),t}),Cr(n,ve(n),r),e&&(r=_t(r,7,le));for(var u=t.length;u--;)xr(r,t[u]);return r}),Rf=pe(function(n,t){return null==n?{}:nr(n,t);
+}),zf=oe(Wu),Wf=oe(Bu),Bf=qr(function(n,t,r){return t=t.toLowerCase(),n+(r?Cu(t):t)}),Lf=qr(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Uf=qr(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Cf=Zr("toLowerCase"),Df=qr(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),Mf=qr(function(n,t,r){return n+(r?" ":"")+$f(t)}),Tf=qr(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),$f=Zr("toUpperCase"),Ff=fr(function(t,r){try{return n(t,T,r)}catch(n){return pu(n)?n:new Hu(n)}}),Nf=pe(function(n,t){
+return r(t,function(t){t=Me(t),st(n,t,Ho(n[t],n))}),n}),Pf=Hr(),Zf=Hr(true),qf=fr(function(n,t){return function(r){return Lt(r,n,t)}}),Vf=fr(function(n,t){return function(r){return Lt(n,r,t)}}),Kf=Xr(c),Gf=Xr(u),Hf=Xr(h),Jf=re(),Yf=re(true),Qf=Qr(function(n,t){return n+t},0),Xf=ie("ceil"),nc=Qr(function(n,t){return n/t},1),tc=ie("floor"),rc=Qr(function(n,t){return n*t},1),ec=ie("round"),uc=Qr(function(n,t){return n-t},0);return An.after=function(n,t){if(typeof t!="function")throw new ti("Expected a function");
+return n=Eu(n),function(){if(1>--n)return t.apply(this,arguments)}},An.ary=eu,An.assign=df,An.assignIn=yf,An.assignInWith=bf,An.assignWith=xf,An.at=jf,An.before=uu,An.bind=Ho,An.bindAll=Nf,An.bindKey=Jo,An.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return ff(n)?n:[n]},An.chain=Ye,An.chunk=function(n,t,r){if(t=(r?Oe(n,t,r):t===T)?1:Ui(Eu(t),0),r=null==n?0:n.length,!r||1>t)return[];for(var e=0,u=0,i=Ku(Oi(r/t));e<r;)i[u++]=hr(n,e,e+=t);return i},An.compact=function(n){for(var t=-1,r=null==n?0:n.length,e=0,u=[];++t<r;){
+var i=n[t];i&&(u[e++]=i)}return u},An.concat=function(){var n=arguments.length;if(!n)return[];for(var t=Ku(n-1),r=arguments[0];n--;)t[n-1]=arguments[n];return a(ff(r)?Ur(r):[r],wt(t,1))},An.cond=function(t){var r=null==t?0:t.length,e=ye();return t=r?c(t,function(n){if("function"!=typeof n[1])throw new ti("Expected a function");return[e(n[0]),n[1]]}):[],fr(function(e){for(var u=-1;++u<r;){var i=t[u];if(n(i[0],this,e))return n(i[1],this,e)}})},An.conforms=function(n){return vt(_t(n,1))},An.constant=Tu,
+An.countBy=$o,An.create=function(n,t){var r=eo(n);return null==t?r:at(r,t)},An.curry=iu,An.curryRight=ou,An.debounce=fu,An.defaults=wf,An.defaultsDeep=mf,An.defer=Yo,An.delay=Qo,An.difference=wo,An.differenceBy=mo,An.differenceWith=Ao,An.drop=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),hr(n,0>t?0:t,e)):[]},An.dropRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0,0>t?0:t)):[]},An.dropRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true,true):[];
+},An.dropWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true):[]},An.fill=function(n,t,r,e){var u=null==n?0:n.length;if(!u)return[];for(r&&typeof r!="number"&&Oe(n,t,r)&&(r=0,e=u),u=n.length,r=Eu(r),0>r&&(r=-r>u?0:u+r),e=e===T||e>u?u:Eu(e),0>e&&(e+=u),e=r>e?0:ku(e);r<e;)n[r++]=t;return n},An.filter=function(n,t){return(ff(n)?i:jt)(n,ye(t,3))},An.flatMap=function(n,t){return wt(ru(n,t),1)},An.flatMapDeep=function(n,t){return wt(ru(n,t),$)},An.flatMapDepth=function(n,t,r){return r=r===T?1:Eu(r),
+wt(ru(n,t),r)},An.flatten=Ze,An.flattenDeep=function(n){return(null==n?0:n.length)?wt(n,$):[]},An.flattenDepth=function(n,t){return null!=n&&n.length?(t=t===T?1:Eu(t),wt(n,t)):[]},An.flip=function(n){return fe(n,512)},An.flow=Pf,An.flowRight=Zf,An.fromPairs=function(n){for(var t=-1,r=null==n?0:n.length,e={};++t<r;){var u=n[t];e[u[0]]=u[1]}return e},An.functions=function(n){return null==n?[]:Et(n,Wu(n))},An.functionsIn=function(n){return null==n?[]:Et(n,Bu(n))},An.groupBy=Po,An.initial=function(n){
+return(null==n?0:n.length)?hr(n,0,-1):[]},An.intersection=Eo,An.intersectionBy=ko,An.intersectionWith=So,An.invert=Af,An.invertBy=Ef,An.invokeMap=Zo,An.iteratee=Fu,An.keyBy=qo,An.keys=Wu,An.keysIn=Bu,An.map=ru,An.mapKeys=function(n,t){var r={};return t=ye(t,3),mt(n,function(n,e,u){st(r,t(n,e,u),n)}),r},An.mapValues=function(n,t){var r={};return t=ye(t,3),mt(n,function(n,e,u){st(r,e,t(n,e,u))}),r},An.matches=function(n){return Ht(_t(n,1))},An.matchesProperty=function(n,t){return Jt(n,_t(t,1))},An.memoize=cu,
+An.merge=Sf,An.mergeWith=Of,An.method=qf,An.methodOf=Vf,An.mixin=Nu,An.negate=au,An.nthArg=function(n){return n=Eu(n),fr(function(t){return Qt(t,n)})},An.omit=If,An.omitBy=function(n,t){return Lu(n,au(ye(t)))},An.once=function(n){return uu(2,n)},An.orderBy=function(n,t,r,e){return null==n?[]:(ff(t)||(t=null==t?[]:[t]),r=e?T:r,ff(r)||(r=null==r?[]:[r]),Xt(n,t,r))},An.over=Kf,An.overArgs=Xo,An.overEvery=Gf,An.overSome=Hf,An.partial=nf,An.partialRight=tf,An.partition=Vo,An.pick=Rf,An.pickBy=Lu,An.property=Zu,
+An.propertyOf=function(n){return function(t){return null==n?T:kt(n,t)}},An.pull=Oo,An.pullAll=Ke,An.pullAllBy=function(n,t,r){return n&&n.length&&t&&t.length?er(n,t,ye(r,2)):n},An.pullAllWith=function(n,t,r){return n&&n.length&&t&&t.length?er(n,t,T,r):n},An.pullAt=Io,An.range=Jf,An.rangeRight=Yf,An.rearg=rf,An.reject=function(n,t){return(ff(n)?i:jt)(n,au(ye(t,3)))},An.remove=function(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],i=n.length;for(t=ye(t,3);++e<i;){var o=n[e];t(o,e,n)&&(r.push(o),
+u.push(e))}return ur(n,u),r},An.rest=function(n,t){if(typeof n!="function")throw new ti("Expected a function");return t=t===T?t:Eu(t),fr(n,t)},An.reverse=Ge,An.sampleSize=function(n,t,r){return t=(r?Oe(n,t,r):t===T)?1:Eu(t),(ff(n)?et:ar)(n,t)},An.set=function(n,t,r){return null==n?n:lr(n,t,r)},An.setWith=function(n,t,r,e){return e=typeof e=="function"?e:T,null==n?n:lr(n,t,r,e)},An.shuffle=function(n){return(ff(n)?ut:sr)(n)},An.slice=function(n,t,r){var e=null==n?0:n.length;return e?(r&&typeof r!="number"&&Oe(n,t,r)?(t=0,
+r=e):(t=null==t?0:Eu(t),r=r===T?e:Eu(r)),hr(n,t,r)):[]},An.sortBy=Ko,An.sortedUniq=function(n){return n&&n.length?gr(n):[]},An.sortedUniqBy=function(n,t){return n&&n.length?gr(n,ye(t,2)):[]},An.split=function(n,t,r){return r&&typeof r!="number"&&Oe(n,t,r)&&(t=r=T),r=r===T?4294967295:r>>>0,r?(n=Iu(n))&&(typeof t=="string"||null!=t&&!hf(t))&&(t=yr(t),!t&&Rn.test(n))?Or(M(n),0,r):n.split(t,r):[]},An.spread=function(t,r){if(typeof t!="function")throw new ti("Expected a function");return r=null==r?0:Ui(Eu(r),0),
+fr(function(e){var u=e[r];return e=Or(e,0,r),u&&a(e,u),n(t,this,e)})},An.tail=function(n){var t=null==n?0:n.length;return t?hr(n,1,t):[]},An.take=function(n,t,r){return n&&n.length?(t=r||t===T?1:Eu(t),hr(n,0,0>t?0:t)):[]},An.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0>t?0:t,e)):[]},An.takeRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),false,true):[]},An.takeWhile=function(n,t){return n&&n.length?jr(n,ye(t,3)):[]},An.tap=function(n,t){return t(n),
+n},An.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new ti("Expected a function");return du(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),fu(n,t,{leading:e,maxWait:t,trailing:u})},An.thru=Qe,An.toArray=mu,An.toPairs=zf,An.toPairsIn=Wf,An.toPath=function(n){return ff(n)?c(n,Me):wu(n)?[n]:Ur(jo(Iu(n)))},An.toPlainObject=Ou,An.transform=function(n,t,e){var u=ff(n),i=u||af(n)||_f(n);if(t=ye(t,4),null==e){var o=n&&n.constructor;e=i?u?new o:[]:du(n)&&_u(o)?eo(di(n)):{};
+}return(i?r:mt)(n,function(n,r,u){return t(e,n,r,u)}),e},An.unary=function(n){return eu(n,1)},An.union=Ro,An.unionBy=zo,An.unionWith=Wo,An.uniq=function(n){return n&&n.length?br(n):[]},An.uniqBy=function(n,t){return n&&n.length?br(n,ye(t,2)):[]},An.uniqWith=function(n,t){return t=typeof t=="function"?t:T,n&&n.length?br(n,T,t):[]},An.unset=function(n,t){return null==n||xr(n,t)},An.unzip=He,An.unzipWith=Je,An.update=function(n,t,r){return null==n?n:lr(n,t,kr(r)(kt(n,t)),void 0)},An.updateWith=function(n,t,r,e){
+return e=typeof e=="function"?e:T,null!=n&&(n=lr(n,t,kr(r)(kt(n,t)),e)),n},An.values=Uu,An.valuesIn=function(n){return null==n?[]:S(n,Bu(n))},An.without=Bo,An.words=Mu,An.wrap=function(n,t){return nf(kr(t),n)},An.xor=Lo,An.xorBy=Uo,An.xorWith=Co,An.zip=Do,An.zipObject=function(n,t){return Ar(n||[],t||[],ot)},An.zipObjectDeep=function(n,t){return Ar(n||[],t||[],lr)},An.zipWith=Mo,An.entries=zf,An.entriesIn=Wf,An.extend=yf,An.extendWith=bf,Nu(An,An),An.add=Qf,An.attempt=Ff,An.camelCase=Bf,An.capitalize=Cu,
+An.ceil=Xf,An.clamp=function(n,t,r){return r===T&&(r=t,t=T),r!==T&&(r=Su(r),r=r===r?r:0),t!==T&&(t=Su(t),t=t===t?t:0),pt(Su(n),t,r)},An.clone=function(n){return _t(n,4)},An.cloneDeep=function(n){return _t(n,5)},An.cloneDeepWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,5,t)},An.cloneWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,4,t)},An.conformsTo=function(n,t){return null==t||gt(n,t,Wu(t))},An.deburr=Du,An.defaultTo=function(n,t){return null==n||n!==n?t:n},An.divide=nc,An.endsWith=function(n,t,r){
+n=Iu(n),t=yr(t);var e=n.length,e=r=r===T?e:pt(Eu(r),0,e);return r-=t.length,0<=r&&n.slice(r,e)==t},An.eq=lu,An.escape=function(n){return(n=Iu(n))&&H.test(n)?n.replace(K,nt):n},An.escapeRegExp=function(n){return(n=Iu(n))&&en.test(n)?n.replace(rn,"\\$&"):n},An.every=function(n,t,r){var e=ff(n)?u:bt;return r&&Oe(n,t,r)&&(t=T),e(n,ye(t,3))},An.find=Fo,An.findIndex=Ne,An.findKey=function(n,t){return p(n,ye(t,3),mt)},An.findLast=No,An.findLastIndex=Pe,An.findLastKey=function(n,t){return p(n,ye(t,3),At);
+},An.floor=tc,An.forEach=nu,An.forEachRight=tu,An.forIn=function(n,t){return null==n?n:oo(n,ye(t,3),Bu)},An.forInRight=function(n,t){return null==n?n:fo(n,ye(t,3),Bu)},An.forOwn=function(n,t){return n&&mt(n,ye(t,3))},An.forOwnRight=function(n,t){return n&&At(n,ye(t,3))},An.get=Ru,An.gt=ef,An.gte=uf,An.has=function(n,t){return null!=n&&we(n,t,Rt)},An.hasIn=zu,An.head=qe,An.identity=$u,An.includes=function(n,t,r,e){return n=su(n)?n:Uu(n),r=r&&!e?Eu(r):0,e=n.length,0>r&&(r=Ui(e+r,0)),ju(n)?r<=e&&-1<n.indexOf(t,r):!!e&&-1<v(n,t,r);
+},An.indexOf=function(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Eu(r),0>r&&(r=Ui(e+r,0)),v(n,t,r)):-1},An.inRange=function(n,t,r){return t=Au(t),r===T?(r=t,t=0):r=Au(r),n=Su(n),n>=Ci(t,r)&&n<Ui(t,r)},An.invoke=kf,An.isArguments=of,An.isArray=ff,An.isArrayBuffer=cf,An.isArrayLike=su,An.isArrayLikeObject=hu,An.isBoolean=function(n){return true===n||false===n||yu(n)&&"[object Boolean]"==Ot(n)},An.isBuffer=af,An.isDate=lf,An.isElement=function(n){return yu(n)&&1===n.nodeType&&!xu(n)},An.isEmpty=function(n){
+if(null==n)return true;if(su(n)&&(ff(n)||typeof n=="string"||typeof n.splice=="function"||af(n)||_f(n)||of(n)))return!n.length;var t=vo(n);if("[object Map]"==t||"[object Set]"==t)return!n.size;if(ze(n))return!Vt(n).length;for(var r in n)if(oi.call(n,r))return false;return true},An.isEqual=function(n,t){return Mt(n,t)},An.isEqualWith=function(n,t,r){var e=(r=typeof r=="function"?r:T)?r(n,t):T;return e===T?Mt(n,t,T,r):!!e},An.isError=pu,An.isFinite=function(n){return typeof n=="number"&&Wi(n)},An.isFunction=_u,
+An.isInteger=vu,An.isLength=gu,An.isMap=sf,An.isMatch=function(n,t){return n===t||$t(n,t,xe(t))},An.isMatchWith=function(n,t,r){return r=typeof r=="function"?r:T,$t(n,t,xe(t),r)},An.isNaN=function(n){return bu(n)&&n!=+n},An.isNative=function(n){if(go(n))throw new Hu("Unsupported core-js use. Try https://npms.io/search?q=ponyfill.");return Ft(n)},An.isNil=function(n){return null==n},An.isNull=function(n){return null===n},An.isNumber=bu,An.isObject=du,An.isObjectLike=yu,An.isPlainObject=xu,An.isRegExp=hf,
+An.isSafeInteger=function(n){return vu(n)&&-9007199254740991<=n&&9007199254740991>=n},An.isSet=pf,An.isString=ju,An.isSymbol=wu,An.isTypedArray=_f,An.isUndefined=function(n){return n===T},An.isWeakMap=function(n){return yu(n)&&"[object WeakMap]"==vo(n)},An.isWeakSet=function(n){return yu(n)&&"[object WeakSet]"==Ot(n)},An.join=function(n,t){return null==n?"":Bi.call(n,t)},An.kebabCase=Lf,An.last=Ve,An.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;if(r!==T&&(u=Eu(r),u=0>u?Ui(e+u,0):Ci(u,e-1)),
+t===t){for(r=u+1;r--&&n[r]!==t;);n=r}else n=_(n,d,u,true);return n},An.lowerCase=Uf,An.lowerFirst=Cf,An.lt=vf,An.lte=gf,An.max=function(n){return n&&n.length?xt(n,$u,It):T},An.maxBy=function(n,t){return n&&n.length?xt(n,ye(t,2),It):T},An.mean=function(n){return y(n,$u)},An.meanBy=function(n,t){return y(n,ye(t,2))},An.min=function(n){return n&&n.length?xt(n,$u,Kt):T},An.minBy=function(n,t){return n&&n.length?xt(n,ye(t,2),Kt):T},An.stubArray=qu,An.stubFalse=Vu,An.stubObject=function(){return{}},An.stubString=function(){
+return""},An.stubTrue=function(){return true},An.multiply=rc,An.nth=function(n,t){return n&&n.length?Qt(n,Eu(t)):T},An.noConflict=function(){return $n._===this&&($n._=si),this},An.noop=Pu,An.now=Go,An.pad=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return!t||e>=t?n:(t=(t-e)/2,ne(Ii(t),r)+n+ne(Oi(t),r))},An.padEnd=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return t&&e<t?n+ne(t-e,r):n},An.padStart=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return t&&e<t?ne(t-e,r)+n:n},An.parseInt=function(n,t,r){
+return r||null==t?t=0:t&&(t=+t),Mi(Iu(n).replace(on,""),t||0)},An.random=function(n,t,r){if(r&&typeof r!="boolean"&&Oe(n,t,r)&&(t=r=T),r===T&&(typeof t=="boolean"?(r=t,t=T):typeof n=="boolean"&&(r=n,n=T)),n===T&&t===T?(n=0,t=1):(n=Au(n),t===T?(t=n,n=0):t=Au(t)),n>t){var e=n;n=t,t=e}return r||n%1||t%1?(r=Ti(),Ci(n+r*(t-n+Cn("1e-"+((r+"").length-1))),t)):ir(n,t)},An.reduce=function(n,t,r){var e=ff(n)?l:j,u=3>arguments.length;return e(n,ye(t,4),r,u,uo)},An.reduceRight=function(n,t,r){var e=ff(n)?s:j,u=3>arguments.length;
+return e(n,ye(t,4),r,u,io)},An.repeat=function(n,t,r){return t=(r?Oe(n,t,r):t===T)?1:Eu(t),or(Iu(n),t)},An.replace=function(){var n=arguments,t=Iu(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},An.result=function(n,t,r){t=Sr(t,n);var e=-1,u=t.length;for(u||(u=1,n=T);++e<u;){var i=null==n?T:n[Me(t[e])];i===T&&(e=u,i=r),n=_u(i)?i.call(n):i}return n},An.round=ec,An.runInContext=x,An.sample=function(n){return(ff(n)?Qn:cr)(n)},An.size=function(n){if(null==n)return 0;if(su(n))return ju(n)?D(n):n.length;
+var t=vo(n);return"[object Map]"==t||"[object Set]"==t?n.size:Vt(n).length},An.snakeCase=Df,An.some=function(n,t,r){var e=ff(n)?h:pr;return r&&Oe(n,t,r)&&(t=T),e(n,ye(t,3))},An.sortedIndex=function(n,t){return _r(n,t)},An.sortedIndexBy=function(n,t,r){return vr(n,t,ye(r,2))},An.sortedIndexOf=function(n,t){var r=null==n?0:n.length;if(r){var e=_r(n,t);if(e<r&&lu(n[e],t))return e}return-1},An.sortedLastIndex=function(n,t){return _r(n,t,true)},An.sortedLastIndexBy=function(n,t,r){return vr(n,t,ye(r,2),true);
+},An.sortedLastIndexOf=function(n,t){if(null==n?0:n.length){var r=_r(n,t,true)-1;if(lu(n[r],t))return r}return-1},An.startCase=Mf,An.startsWith=function(n,t,r){return n=Iu(n),r=null==r?0:pt(Eu(r),0,n.length),t=yr(t),n.slice(r,r+t.length)==t},An.subtract=uc,An.sum=function(n){return n&&n.length?m(n,$u):0},An.sumBy=function(n,t){return n&&n.length?m(n,ye(t,2)):0},An.template=function(n,t,r){var e=An.templateSettings;r&&Oe(n,t,r)&&(t=T),n=Iu(n),t=bf({},t,e,ce),r=bf({},t.imports,e.imports,ce);var u,i,o=Wu(r),f=S(r,o),c=0;
+r=t.interpolate||jn;var a="__p+='";r=Xu((t.escape||jn).source+"|"+r.source+"|"+(r===Q?pn:jn).source+"|"+(t.evaluate||jn).source+"|$","g");var l=oi.call(t,"sourceURL")?"//# sourceURL="+(t.sourceURL+"").replace(/[\r\n]/g," ")+"\n":"";if(n.replace(r,function(t,r,e,o,f,l){return e||(e=o),a+=n.slice(c,l).replace(wn,z),r&&(u=true,a+="'+__e("+r+")+'"),f&&(i=true,a+="';"+f+";\n__p+='"),e&&(a+="'+((__t=("+e+"))==null?'':__t)+'"),c=l+t.length,t}),a+="';",(t=oi.call(t,"variable")&&t.variable)||(a="with(obj){"+a+"}"),
+a=(i?a.replace(P,""):a).replace(Z,"$1").replace(q,"$1;"),a="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(u?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+a+"return __p}",t=Ff(function(){return Ju(o,l+"return "+a).apply(T,f)}),t.source=a,pu(t))throw t;return t},An.times=function(n,t){if(n=Eu(n),1>n||9007199254740991<n)return[];var r=4294967295,e=Ci(n,4294967295);for(t=ye(t),n-=4294967295,e=A(e,t);++r<n;)t(r);return e},An.toFinite=Au,
+An.toInteger=Eu,An.toLength=ku,An.toLower=function(n){return Iu(n).toLowerCase()},An.toNumber=Su,An.toSafeInteger=function(n){return n?pt(Eu(n),-9007199254740991,9007199254740991):0===n?n:0},An.toString=Iu,An.toUpper=function(n){return Iu(n).toUpperCase()},An.trim=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(un,""):n&&(t=yr(t))?(n=M(n),r=M(t),t=I(n,r),r=R(n,r)+1,Or(n,t,r).join("")):n},An.trimEnd=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(fn,""):n&&(t=yr(t))?(n=M(n),t=R(n,M(t))+1,
+Or(n,0,t).join("")):n},An.trimStart=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(on,""):n&&(t=yr(t))?(n=M(n),t=I(n,M(t)),Or(n,t).join("")):n},An.truncate=function(n,t){var r=30,e="...";if(du(t))var u="separator"in t?t.separator:u,r="length"in t?Eu(t.length):r,e="omission"in t?yr(t.omission):e;n=Iu(n);var i=n.length;if(Rn.test(n))var o=M(n),i=o.length;if(r>=i)return n;if(i=r-D(e),1>i)return e;if(r=o?Or(o,0,i).join(""):n.slice(0,i),u===T)return r+e;if(o&&(i+=r.length-i),hf(u)){if(n.slice(i).search(u)){
+var f=r;for(u.global||(u=Xu(u.source,Iu(_n.exec(u))+"g")),u.lastIndex=0;o=u.exec(f);)var c=o.index;r=r.slice(0,c===T?i:c)}}else n.indexOf(yr(u),i)!=i&&(u=r.lastIndexOf(u),-1<u&&(r=r.slice(0,u)));return r+e},An.unescape=function(n){return(n=Iu(n))&&G.test(n)?n.replace(V,tt):n},An.uniqueId=function(n){var t=++fi;return Iu(n)+t},An.upperCase=Tf,An.upperFirst=$f,An.each=nu,An.eachRight=tu,An.first=qe,Nu(An,function(){var n={};return mt(An,function(t,r){oi.call(An.prototype,r)||(n[r]=t)}),n}(),{chain:false
+}),An.VERSION="4.17.15",r("bind bindKey curry curryRight partial partialRight".split(" "),function(n){An[n].placeholder=An}),r(["drop","take"],function(n,t){Un.prototype[n]=function(r){r=r===T?1:Ui(Eu(r),0);var e=this.__filtered__&&!t?new Un(this):this.clone();return e.__filtered__?e.__takeCount__=Ci(r,e.__takeCount__):e.__views__.push({size:Ci(r,4294967295),type:n+(0>e.__dir__?"Right":"")}),e},Un.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){
+var r=t+1,e=1==r||3==r;Un.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ye(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){var r="take"+(t?"Right":"");Un.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Un.prototype[n]=function(){return this.__filtered__?new Un(this):this[r](1)}}),Un.prototype.compact=function(){return this.filter($u)},Un.prototype.find=function(n){
+return this.filter(n).head()},Un.prototype.findLast=function(n){return this.reverse().find(n)},Un.prototype.invokeMap=fr(function(n,t){return typeof n=="function"?new Un(this):this.map(function(r){return Lt(r,n,t)})}),Un.prototype.reject=function(n){return this.filter(au(ye(n)))},Un.prototype.slice=function(n,t){n=Eu(n);var r=this;return r.__filtered__&&(0<n||0>t)?new Un(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==T&&(t=Eu(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},Un.prototype.takeRightWhile=function(n){
+return this.reverse().takeWhile(n).reverse()},Un.prototype.toArray=function(){return this.take(4294967295)},mt(Un.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=An[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);u&&(An.prototype[t]=function(){function t(n){return n=u.apply(An,a([n],f)),e&&h?n[0]:n}var o=this.__wrapped__,f=e?[1]:arguments,c=o instanceof Un,l=f[0],s=c||ff(o);s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false);var h=this.__chain__,p=!!this.__actions__.length,l=i&&!h,c=c&&!p;
+return!i&&s?(o=c?o:new Un(this),o=n.apply(o,f),o.__actions__.push({func:Qe,args:[t],thisArg:T}),new On(o,h)):l&&c?n.apply(this,f):(o=this.thru(t),l?e?o.value()[0]:o.value():o)})}),r("pop push shift sort splice unshift".split(" "),function(n){var t=ri[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);An.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(ff(u)?u:[],n)}return this[r](function(r){return t.apply(ff(r)?r:[],n)});
+}}),mt(Un.prototype,function(n,t){var r=An[t];if(r){var e=r.name+"";oi.call(Gi,e)||(Gi[e]=[]),Gi[e].push({name:t,func:r})}}),Gi[Jr(T,2).name]=[{name:"wrapper",func:T}],Un.prototype.clone=function(){var n=new Un(this.__wrapped__);return n.__actions__=Ur(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ur(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ur(this.__views__),n},Un.prototype.reverse=function(){if(this.__filtered__){var n=new Un(this);
+n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},Un.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=ff(t),u=0>r,i=e?t.length:0;n=i;for(var o=this.__views__,f=0,c=-1,a=o.length;++c<a;){var l=o[c],s=l.size;switch(l.type){case"drop":f+=s;break;case"dropRight":n-=s;break;case"take":n=Ci(n,f+s);break;case"takeRight":f=Ui(f,n-s)}}if(n={start:f,end:n},o=n.start,f=n.end,n=f-o,o=u?f:o-1,f=this.__iteratees__,c=f.length,a=0,l=Ci(n,this.__takeCount__),!e||!u&&i==n&&l==n)return wr(t,this.__actions__);
+e=[];n:for(;n--&&a<l;){for(o+=r,u=-1,i=t[o];++u<c;){var h=f[u],s=h.type,h=(0,h.iteratee)(i);if(2==s)i=h;else if(!h){if(1==s)continue n;break n}}e[a++]=i}return e},An.prototype.at=To,An.prototype.chain=function(){return Ye(this)},An.prototype.commit=function(){return new On(this.value(),this.__chain__)},An.prototype.next=function(){this.__values__===T&&(this.__values__=mu(this.value()));var n=this.__index__>=this.__values__.length;return{done:n,value:n?T:this.__values__[this.__index__++]}},An.prototype.plant=function(n){
+for(var t,r=this;r instanceof En;){var e=Fe(r);e.__index__=0,e.__values__=T,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},An.prototype.reverse=function(){var n=this.__wrapped__;return n instanceof Un?(this.__actions__.length&&(n=new Un(this)),n=n.reverse(),n.__actions__.push({func:Qe,args:[Ge],thisArg:T}),new On(n,this.__chain__)):this.thru(Ge)},An.prototype.toJSON=An.prototype.valueOf=An.prototype.value=function(){return wr(this.__wrapped__,this.__actions__)},An.prototype.first=An.prototype.head,
+wi&&(An.prototype[wi]=Xe),An}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?($n._=rt, define(function(){return rt})):Nn?((Nn.exports=rt)._=rt,Fn._=rt):$n._=rt}).call(this);
\ No newline at end of file
diff --git a/js/002-config/fc-js-init.js b/js/002-config/fc-js-init.js
index 79e7657b20008568c8090beab826957790bd692d..bd683646b919f39d86776a6b1b84f46c2012c15a 100644
--- a/js/002-config/fc-js-init.js
+++ b/js/002-config/fc-js-init.js
@@ -76,6 +76,7 @@ App.Mods.SecExp = {};
 App.Mods.SF = {};
 App.Neighbor = {};
 App.PersonalAttention = {};
+App.Porn = {};
 App.RA = {};
 App.RA.Activation = {};
 App.Ratings = {};
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index 1a6212f6130eaa15a1081a807ce4d89f0a6eee58..1874d1b207d26bf6737679f236fcfa76d1f50197 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -470,7 +470,7 @@ App.Data.resetOnNGPlus = {
 
 	reminderEntry: "",
 	reminderWeek: "",
-	currentRule: {},
+	currentRule: null, // {},
 	costs: 0,
 	seeBuilding: 0,
 	purchasedSagBGone: 0,
@@ -514,6 +514,7 @@ App.Data.resetOnNGPlus = {
 	defaultRules: [],
 	/** @type {Object.<string, number[]>} */
 	rulesToApplyOnce: {},
+	raDefaultMode : 0,
 
 	REFeminizationCheckinIDs: [],
 	REMILFCheckinIDs: [],
@@ -1355,11 +1356,6 @@ App.Data.resetOnNGPlus = {
 		slave: 0
 	},
 	tempEventToggle: 0,
-	/**
-	 * Assignments texts for slaves who choose their own assignment, set at during the first pass in App.SlaveAssignment.choosesOwnJob()
-	 * @type {Object.<number, string>}
-	 */
-	choosesOwnAssignmentText: {},
 	favorites: [],
 	/**
 	 * Any loans the player has taken out.
diff --git a/js/003-data/policiesData.js b/js/003-data/policiesData.js
index e5ad057b92a9668ef6d673aae539d1d86617b485..88c7ab163c78a4472c8dbfd5f971518cefc4d168 100644
--- a/js/003-data/policiesData.js
+++ b/js/003-data/policiesData.js
@@ -1237,6 +1237,7 @@ App.Data.Policies.Selection = {
 						V.seeDicks !== 0 &&
 						V.arcologies[0].FSGenderRadicalist > 60 &&
 						V.arcologies[0].FSSlimnessEnthusiastLaw === 0 &&
+						V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 0 &&
 						V.arcologies[0].FSGenderRadicalistLawFuta === 0
 					);
 				},
@@ -1582,6 +1583,25 @@ App.Data.Policies.Selection = {
 				note: `Flat slaves will enjoy increased attractiveness to citizens`
 			}
 		],
+		"arcologies[0].FSSlimnessEnthusiastFoodLaw": [
+			{
+				title: "Asset Slimming Food",
+				titleClass: "lime",
+				text: "slave food production will be required to follow a recipe that keeps chattel nice and trim, reducing the growth of disgusting flesh on their T&A.",
+				activatedText: "you have standardized a slave food recipe to keep your chattel nice and trim, reducing the amount of oversized T&A in the arcology.",
+				get requirements() {
+					return (
+						V.arcologies[0].FSGenderRadicalistLawBeauty === 0 &&
+						V.arcologies[0].FSGenderFundamentalistLawBeauty === 0 &&
+						V.arcologies[0].FSGenderRadicalistLawFuta !== 3 &&
+						V.arcologies[0].FSHedonisticDecadenceLaw2 === 0 &&
+						V.arcologies[0].FSPhysicalIdealistLaw === 0 &&
+						V.arcologies[0].FSSlimnessEnthusiast > 20
+					);
+				},
+				note: `Slaves will struggle to grow beyond the ideal amount of T&A. `
+			}
+		],
 	},
 	FSAssetExpansionist: {
 		"arcologies[0].FSAssetExpansionistSMR": [
@@ -1693,6 +1713,7 @@ App.Data.Policies.Selection = {
 				get requirements() {
 					return (
 						V.arcologies[0].FSSlimnessEnthusiastLaw === 0 &&
+						V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 0 &&
 						V.arcologies[0].FSGenderRadicalistLawBeauty === 0 &&
 						V.arcologies[0].FSGenderFundamentalistLawBeauty === 0 &&
 						V.arcologies[0].FSPhysicalIdealistLaw === 0 &&
diff --git a/js/003-data/slaveMods.js b/js/003-data/slaveMods.js
index 7489c5bdec378b87002d512904cbb7dcafc7e807..31300e639686def408fe55c2bebb4b98d31a4598 100644
--- a/js/003-data/slaveMods.js
+++ b/js/003-data/slaveMods.js
@@ -506,7 +506,7 @@ App.Medicine.Modification.faceShape = new Map([
 		desc: `faces are moderately bad for attractiveness`
 	}],
 	["masculine", {
-		desc: ``,
+		// TODO desc: ``,
 		get requirements() { return V.seeDicks !== 0; }
 	}]
 ]);
@@ -530,7 +530,7 @@ App.Medicine.Modification.teeth = new Map([
 		desc: `have a negative impact on attractiveness, but less than crooked teeth, and will eventually straighten the slave's teeth. They can be applied to straight teeth or left on after they are no longer useful, if desired.`
 	}],
 	["cosmetic braces", {
-		desc: ``
+		// TODO desc: ``
 	}],
 	["removable", {
 		desc: `teeth can pass as normal teeth and thus have no attractiveness impact, but do alter some sex scenes.`,
@@ -548,18 +548,18 @@ App.Medicine.Modification.teeth = new Map([
 		sharp: true
 	}],
 	["fangs", {
-		desc: ``,
+		// TODO desc: ``,
 		sharp: true
 	}],
 	["fang", {
-		desc: ``,
+		// TODO desc: ``,
 		sharp: true
 	}],
 	["baby", {
-		desc: ``,
+		// TODO desc: ``,
 	}],
 	["mixed", {
-		desc: ``,
+		// TODO desc: ``,
 	}],
 ]);
 /**
diff --git a/js/medicine/surgery/exotic/race.js b/js/medicine/surgery/exotic/race.js
index 9f0b2b01327d7a87a5f5549e475a757ad044e8ce..282e39be85573527a1c48ef7b493bcdb1d67bc6a 100644
--- a/js/medicine/surgery/exotic/race.js
+++ b/js/medicine/surgery/exotic/race.js
@@ -21,7 +21,7 @@ App.Medicine.Surgery.Reactions.Race = class extends App.Medicine.Surgery.SimpleR
 				r.push(`gets a feel for the changes to ${his} body`);
 			}
 			r.push(`with approval.`);
-			if (slave.race === slave.origRace) {
+			if (diff.race === slave.origRace) {
 				r.push(`${He} recognizes ${himself} as ${he} was, and`);
 			} else {
 				r.push(`${He} doesn't recognize ${himself} quite yet, but`);
@@ -38,7 +38,7 @@ App.Medicine.Surgery.Reactions.Race = class extends App.Medicine.Surgery.SimpleR
 				r.push(`gets a feel for the changes to ${his} body`);
 			}
 			r.push(`with hesitation.`);
-			if (slave.race === slave.origRace) {
+			if (diff.race === slave.origRace) {
 				r.push(`${He} recognizes ${himself} as ${he} was, and`);
 			} else {
 				r.push(`${He} doesn't recognize ${himself} quite yet, but`);
@@ -55,13 +55,13 @@ App.Medicine.Surgery.Reactions.Race = class extends App.Medicine.Surgery.SimpleR
 				r.push(`gets a feel for the changes to ${his} body`);
 			}
 			r.push(`with revulsion.`);
-			if (slave.race === slave.origRace) {
+			if (diff.race === slave.origRace) {
 				r.push(`${He} recognizes ${himself} as ${he} was, which ${he} loves, and`);
 			} else {
 				r.push(`${He} doesn't recognize ${himself} quite yet, which ${he} hates, though`);
 			}
 			r.push(`${he} hopes you'll like ${his} new appearance better and punish ${him} less cruelly as a result. For now, <span class="devotion dec">${he} seems to view this`);
-			if (slave.race !== slave.origRace) {
+			if (diff.race !== slave.origRace) {
 				r.push(`fake`);
 			}
 			r.push(`racial appearance as a cruel imposition.</span> As with all invasive surgery <span class="health dec">${his} health has been affected.</span> ${He} is <span class="trust dec">terribly afraid</span> of your total power over ${his} body.`);
diff --git a/js/medicine/surgery/face/lips.js b/js/medicine/surgery/face/lips.js
index 0883d4039f9eee0079580fbe88bfbea02946c37e..2cb29c85885a1c623572e542bd283017754079d5 100644
--- a/js/medicine/surgery/face/lips.js
+++ b/js/medicine/surgery/face/lips.js
@@ -59,10 +59,6 @@ App.Medicine.Surgery.Procedures.lipImplantProcedure = function() {
 		get name() {
 			return "Replace with the next size up";
 		}
-
-		get description() {
-			return '';
-		}
 	}
 
 	/**
diff --git a/js/medicine/surgery/structural/amputation.js b/js/medicine/surgery/structural/amputation.js
index c63759897847efdc40f3312f0898ebb30cef3b1a..efc3f2b4a56183fe70725f0b4cd522fb46b20f6a 100644
--- a/js/medicine/surgery/structural/amputation.js
+++ b/js/medicine/surgery/structural/amputation.js
@@ -217,8 +217,13 @@ App.Medicine.Surgery.Reactions.Amputate = class extends App.Medicine.Surgery.Sim
 		const {He, him} = getPronouns(slave);
 
 		if (slave.behavioralFlaw === "arrogant") {
-			reaction.longReaction.last()
-				.push(`<span class="flaw break">${He} can hardly be arrogant relying on others to feed, bathe and carry ${him}.</span>`);
+			const r = `<span class="flaw break">${He} can hardly be arrogant relying on others to feed, bathe and carry ${him}.</span>`;
+			if (reaction.longReaction.length > 0) {
+				reaction.longReaction.last()
+					.push(r);
+			} else {
+				reaction.longReaction.push([r]);
+			}
 			slave.behavioralFlaw = "none";
 		}
 
diff --git a/js/medicine/surgery/teeth/braces.js b/js/medicine/surgery/teeth/braces.js
index ed3dd85ade487819d2811a6c9424d1e5aa7b8b70..f8c3dfc57aec21f5077ab38dd7a5f3495935a585 100644
--- a/js/medicine/surgery/teeth/braces.js
+++ b/js/medicine/surgery/teeth/braces.js
@@ -14,7 +14,7 @@ App.Medicine.Surgery.Reactions.Braces = class extends App.Medicine.Surgery.Simpl
 
 		if (slave.fetish === Fetish.MINDBROKEN) {
 			r.push(`${He} is quite quick to realize ${his} teeth now have something on them. What its purpose is is beyond ${him}, though.`);
-		} else if (slave.teeth === "straightening braces") {
+		} else if (diff.teeth === "straightening braces") {
 			r.push(`Quite aware that ${his} crooked, aching teeth are now in braces,`);
 			if (slave.devotion > 50) {
 				r.push(`${He} smiles tentatively at`);
@@ -43,7 +43,7 @@ App.Medicine.Surgery.Reactions.Braces = class extends App.Medicine.Surgery.Simpl
 				}
 				r.push(`${He}'s experiencing considerable discomfort, and ${his} feelings are mixed. ${He} knows that straightening teeth is expensive, and in different circumstances ${he} would probably be glad to be given free braces. However, ${he}'s very aware that ${he}'s being beautified because ${he}'s a sex slave.`);
 			}
-		} else if (slave.teeth === "cosmetic braces") {
+		} else if (diff.teeth === "cosmetic braces") {
 			r.push(`Quite aware that ${his} aching teeth are now in braces,`);
 			if (slave.devotion > 50) {
 				r.push(`${he} smiles tentatively at`);
diff --git a/js/medicine/surgery/voice/mute.js b/js/medicine/surgery/voice/mute.js
index 6d1f5195f891d7815f95f21d25a2fed34ba53080..ba9062fcb60448e6ece070de6e36f46001eee4dc 100644
--- a/js/medicine/surgery/voice/mute.js
+++ b/js/medicine/surgery/voice/mute.js
@@ -40,8 +40,13 @@ App.Medicine.Surgery.Reactions.Mute = class extends App.Medicine.Surgery.SimpleR
 		const {He} = getPronouns(slave);
 
 		if (slave.behavioralFlaw === "bitchy") {
-			reaction.longReaction.last()
-				.push(`<span class="green">${He} can hardly make sharp remarks without a voice.</span>`);
+			const r = `<span class="green">${He} can hardly make sharp remarks without a voice.</span>`;
+			if (reaction.longReaction.length > 0) {
+				reaction.longReaction.last()
+					.push(r);
+			} else {
+				reaction.longReaction.push([r]);
+			}
 			slave.behavioralFlaw = "none";
 		}
 
diff --git a/js/medicine/surgery/voice/voiceLower.js b/js/medicine/surgery/voice/voiceLower.js
index b4b0280d9ede3d6f0c5d72102ea9ad9c3c5a984b..ee6c97e9a45f96f77693459971aeacf312734ecd 100644
--- a/js/medicine/surgery/voice/voiceLower.js
+++ b/js/medicine/surgery/voice/voiceLower.js
@@ -8,32 +8,32 @@ App.Medicine.Surgery.Reactions.VoiceLower = class extends App.Medicine.Surgery.S
 			r.push(`The autosurgery instructed ${him} in no uncertain terms not to speak during recovery, but ${he} fails to recall that. ${He} doesn't notice anything different. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 		} else if (slave.devotion > 50) {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 1) {
+			if (diff.voice === 1) {
 				r.push(`far`);
 			}
 			r.push(`lower and more manly than it was before, and ${he} laughs at ${himself} as ${he} gets used to it. <span class="devotion inc">${He} has become more dominant,</span> since this allows ${him} to think of ${himself} as`);
-			if (slave.voice === 1) {
+			if (diff.voice === 1) {
 				r.push(`an action movie hero.`);
-			} else if (slave.voice === 2) {
+			} else if (diff.voice === 2) {
 				r.push(`a mature career woman.`);
 			}
 			r.push(`As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 			reaction.devotion += 4;
 		} else if (slave.devotion > 20) {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 1) {
+			if (diff.voice === 1) {
 				r.push(`far`);
 			}
 			r.push(`lower and more manly than it was before, and ${he} laughs grimly at ${himself} as ${he} gets used to it. ${He} carries on regardless, accepting it as one more thing to learn to accept. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 		} else {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 1) {
+			if (diff.voice === 1) {
 				r.push(`far`);
 			}
 			r.push(`lower and more manly than it was before. For now, <span class="devotion dec">${he} feels this`);
-			if (slave.voice === 1) {
+			if (diff.voice === 1) {
 				r.push(`gravelly`);
-			} else if (slave.voice === 2) {
+			} else if (diff.voice === 2) {
 				r.push(`subdued`);
 			}
 			r.push(`voice is not ${hers}, a cruel mockery.</span> As with all surgery <span class="health dec">${his} health has been slightly affected.</span> ${He} is now <span class="trust dec">terribly afraid</span> of your total power over ${his} body.`);
diff --git a/js/medicine/surgery/voice/voiceRaise.js b/js/medicine/surgery/voice/voiceRaise.js
index e8251b4c99bc8b8c71dfc32bc5c128966b3d811a..550d7359eacad89a78017abfde8ecb08095b14ac 100644
--- a/js/medicine/surgery/voice/voiceRaise.js
+++ b/js/medicine/surgery/voice/voiceRaise.js
@@ -8,11 +8,11 @@ App.Medicine.Surgery.Reactions.VoiceRaise = class extends App.Medicine.Surgery.S
 			r.push(`The autosurgery instructed ${him} in no uncertain terms not to speak during recovery, but ${he} fails to recall that. ${He} doesn't notice anything different. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 		} else if (slave.devotion > 50) {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 3) {
+			if (diff.voice === 3) {
 				r.push(`far`);
 			}
 			r.push(`higher and more girly than it was before, and ${he} laughs at ${himself} as ${he} gets used to it. <span class="devotion inc">${He} has become more submissive,</span> since this helps ${him} to think of ${himself} as a`);
-			if (slave.voice === 3) {
+			if (diff.voice === 3) {
 				r.push(`bimbo slut.`);
 			} else {
 				r.push(`real woman.`);
@@ -21,17 +21,17 @@ App.Medicine.Surgery.Reactions.VoiceRaise = class extends App.Medicine.Surgery.S
 			reaction.devotion += 4;
 		} else if (slave.devotion > 20) {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 3) {
+			if (diff.voice === 3) {
 				r.push(`far`);
 			}
 			r.push(`higher and more girly than it was before, and ${he} laughs grimly at ${himself} as ${he} gets used to it. ${He} carries on regardless, accepting it as one more thing to learn to accept. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 		} else {
 			r.push(`Before surgery, ${he} was warned repeatedly not to try talking for a while, and ${he} obeys. When ${he} finally does, ${his} voice is raspy and weak, but it gains strength gradually. It comes out`);
-			if (slave.voice === 3) {
+			if (diff.voice === 3) {
 				r.push(`far`);
 			}
 			r.push(`higher and more girly than it was before. For now, <span class="devotion dec">${he} feels this`);
-			if (slave.voice === 3) {
+			if (diff.voice === 3) {
 				r.push(`bimbo`);
 			} else {
 				r.push(`feminine`);
diff --git a/js/rulesAssistant/conditionEditorSimple.js b/js/rulesAssistant/conditionEditorSimple.js
index e3c64a81518d93fc0feb9204178fc52235a8129b..2384dc9d021c315f23681650b755995b47469e76 100644
--- a/js/rulesAssistant/conditionEditorSimple.js
+++ b/js/rulesAssistant/conditionEditorSimple.js
@@ -377,6 +377,9 @@ App.RA.Activation.SimpleEditor = (function() {
 		if (ruleState.assignmentMode !== "ignore" && ruleState.assignments.length > 0) {
 			rule.push(...ruleState.assignments);
 			rule.push(ruleState.assignments.length, "or");
+			if (ruleState.assignmentMode === "exclude") {
+				rule.push("not");
+			}
 			counter++;
 		}
 
diff --git a/package.json b/package.json
index 8597ed95c2aef8be7a4022b1bcf317a0e1b8ce43..7a0c99af1660088612e905c08ef2de5dcbc7fb8e 100644
--- a/package.json
+++ b/package.json
@@ -12,9 +12,9 @@
 	},
 	"license": "GPL-3.0-only",
 	"devDependencies": {
-		"@types/d3": "^5.7.2",
+		"@types/d3": "^7.4.0",
 		"@types/jquery": "^3.5.1",
-		"@types/lodash": "^4.14.159",
+		"@types/lodash": "^4.14.185",
 		"@types/mousetrap": "^1.6.3",
 		"@types/twine-sugarcube": "^2.36.1",
 		"eslint": "^8.0.0",
@@ -35,6 +35,7 @@
 		"gulp-sort": "^2.0.0",
 		"gulp-sourcemaps": "^3.0.0",
 		"gulp-strip-comments": "^2.5.2",
+		"postcss": "^8.1.0",
 		"which": "^2.0.2",
 		"yargs": "^16.0.0"
 	}
diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js
index 365517ed20f620088261e42e5a94ea2b65484bf3..e250f41827234b907e1f19b6689a1635ad67d689 100644
--- a/src/002-config/fc-version.js
+++ b/src/002-config/fc-version.js
@@ -1,6 +1,6 @@
 App.Version = {
 	base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed.
-	pmod: "4.0.0-alpha.19",
+	pmod: "4.0.0-alpha.21",
 	commitHash: null,
-	release: 1178, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js.
+	release: 1181, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js.
 };
diff --git a/src/004-base/facilityFramework.js b/src/004-base/facilityFramework.js
index 3b28365077a1b1ed3128866a9bdca8ec52bd309f..afc7c72f6e102bc11edd27bd4893c9f3c4e32d0d 100644
--- a/src/004-base/facilityFramework.js
+++ b/src/004-base/facilityFramework.js
@@ -161,20 +161,22 @@ App.Facilities.Facility = class Facility {
 				} else {
 					const link = document.createElement("span");
 					const baseCost = cost;
-					const array = [];
-					for (const expand of [10, 25, 50, 100].filter(s => capacity - occupancy >= s)) {
+					const upgrades = [10, 25, 50, 100];
+					const available = maximum ? upgrades.filter(s => maximum - occupancy >= s) : upgrades;
+					const options = [];
+					for (const expand of available) {
 						cost = baseCost * (expand / 5);
-						array.push(
+						options.push(
 							App.UI.DOM.link(`x${expand}`, () => { expandFacility(expand, cost); }, [], '', `An additional ${num(expand)} slots will cost ${cashFormat(Math.trunc(cost))}.`)
 						);
 					}
-					link.append(App.UI.DOM.generateLinksStrip(array));
+					link.append(App.UI.DOM.generateLinksStrip(options));
 
 					const linkArray = [];
 					App.UI.DOM.appendNewElement("div", div);
 					div.append(`Expanding ${this.facility.name} by ${num(5)} slots will cost ${cashFormat(Math.trunc(baseCost))}: `);
 					linkArray.push(App.UI.DOM.link(`x5`, () => { expandFacility(5, baseCost); }));
-					if (capacity - occupancy >= 10) {
+					if (!maximum || maximum - occupancy >= 10) {
 						linkArray.push(App.UI.DOM.linkReplace(`Additional options`, link));
 					}
 					div.append(App.UI.DOM.generateLinksStrip(linkArray));
diff --git a/src/005-passages/managePassages.js b/src/005-passages/managePassages.js
index 1a7f9fe228ad7c753de85a2ac43a285d6f6fdaed..e7f53b6ad1e7b89389f04e923a266c91108bf817 100644
--- a/src/005-passages/managePassages.js
+++ b/src/005-passages/managePassages.js
@@ -239,3 +239,12 @@ new App.DomPassage("edicts",
 		return App.Mods.SecExp.edicts();
 	}, ["jump-to-safe", "jump-from-safe"]
 );
+
+new App.DomPassage("Media Studio",
+	() => {
+		V.nextButton = "Back";
+		V.nextLink = "Manage Penthouse";
+		V.encyclopedia = "Media Hub";
+		return App.UI.mediaStudio();
+	}, ["jump-to-safe", "jump-from-safe"]
+);
diff --git a/src/Mods/SecExp/buildings/riotControlCenter.js b/src/Mods/SecExp/buildings/riotControlCenter.js
index b7b9dc39025d0c794e21f93e6ee41feb65854fe0..428a4352280136372cd6adbb11065cfa2466d21d 100644
--- a/src/Mods/SecExp/buildings/riotControlCenter.js
+++ b/src/Mods/SecExp/buildings/riotControlCenter.js
@@ -200,18 +200,11 @@ App.Mods.SecExp.riotCenter = (function() {
 
 		if (V.SF.Toggle && V.SF.Active >= 1) {
 			if (V.SecExp.edicts.SFSupportLevel >= 4 && V.SF.Squad.Armoury >= 8 && !V.SecExp.rebellions.sfArmor) {
-				App.UI.DOM.appendNewElement("div", node);
 				const cost = Math.ceil(500000 * App.Mods.SF.env() * (1.15 + (V.SF.Squad.Armoury/10) ));
-				App.UI.DOM.appendNewElement("span", node,
-					App.UI.DOM.link(
-						`Give the riot unit access to the combat armor suits of ${V.SF.Lower}.`,
-						() => {
-							V.SecExp.rebellions.sfArmor = 1;
-							cashX(-cost, "capEx");
-						}
-					)
-				);
-				App.UI.DOM.appendNewElement("span", node, `Costs ${cashFormat(cost)}.`, "note");
+				App.UI.DOM.appendNewElement("div", node, makePurchase(
+					`Give the riot unit access to the combat armor suits of ${V.SF.Lower}.`, cost, "capEx",
+					{handler: () => { V.SecExp.rebellions.sfArmor = 1; }}
+				));
 			} else {
 				App.UI.DOM.appendNewElement("div", node, `You have given the riot unit access to the combat armor suits of ${V.SF.Lower}.`);
 			}
diff --git a/src/Mods/SpecialForce/SpecialForceFS.js b/src/Mods/SpecialForce/SpecialForceFS.js
index 60370fc2c0289d4a5f23b539b01fc6aac677dad1..68730d1423126596e5fa2efaa6f8cca61d5816bd 100644
--- a/src/Mods/SpecialForce/SpecialForceFS.js
+++ b/src/Mods/SpecialForce/SpecialForceFS.js
@@ -282,7 +282,7 @@ App.Mods.SF.fsIntegration = (function() {
 				dec = `Slimness Enthusiasm: a fashion for slaves with girlish figures.`;
 				gift = `In celebration of Slimness Enthusiasm, you've gifted The Colonel with her very own fleet of small single-seater reconnaissance buggies, all made from extremely lightweight-yet-durable alloys, and precisely engineered miniature nuclear reactors meant to allow each vehicle in the fleet to achieve obscene speeds in the field in all terrains. They even come with roof hardpoint mounts for mounting light remote-operated weapons. Thanks to their stellar support systems they also ensure driver safety and orientation during use, reliably absorbing and redistributing the energy received from the multitude of shocks, bounces, g-forces, jolts, jumps, and other maneuverability hiccups that would make these vehicles impossible to handle without them. All that being said, they are very fun to drive and eventually master. Also, their extreme mobility, tiny target profiles, quiet engines, and ease of camouflage all make them excellent recon vehicles for The Colonel and her friends to use for races, scouting missions, and raids whenever things in the Firebase get too boring.`;
 				foods = `The meals are prepared and presented as low-calorie or even calorie-free, stripping fatty content wherever possible. Smaller portions and slices than market standard are not uncommon either.`;
-				media = `Much of the movies and porn videos the troops receive prominently feature glamorous model-thin actors and actresses alike, with tiny tits and asses, and usually very little bodyfat. With bodies so light and thin, every endeavor onscreen, from fight scenes to sex scenes, is usually very intense and fast paced.`;
+				media = `Much of the movies and porn videos the troops receive prominently feature glamorous model-thin actors and actresses alike, with tiny tits and asses, and usually very little body fat. With bodies so light and thin, every endeavor onscreen, from fight scenes to sex scenes, is usually very intense and fast paced.`;
 				slaves = `A good portion of the slaves in the Firebase are quite skinny. They have slim assets on their bodies and are generally lightweight. A few discerning troops are seen checking them out from afar, from time to time.`;
 				cages = `The new slaves kept in the processing cages are aggressively slimmed down. They are given only one medium-sized meal at midday, and yet they are required to work and train for their new lives just as hard as any other slave.`;
 				commonArea = `Along the greatest length of the common area, there is a full proper running track, complete with laid tarmac and white paint. It is comparable to the tracks used by any modern sports team, and even has a tiny booth staffed by in-house bookies, where troopers go to place their bets or collect their prizes for the weekly slave Races and monthly Coursing games. This track also has a feature you wouldn't find on most tracks, which are the compact wheeled cages on either end, for owners to store their prized runner slaves, or collect a runner slave they just won through their bets. Aside from concession stands, raised seats are lined up on the sides of the racetrack, for spectators and judges to observe and film the footraces themselves.`;
diff --git a/src/arcologyBuilding/ManageArcology.js b/src/arcologyBuilding/ManageArcology.js
index aade904d9b3ed2e927567213b2e4db42561a2ea2..b6420c1088fa5de4820038dd0fb28f80760110e0 100644
--- a/src/arcologyBuilding/ManageArcology.js
+++ b/src/arcologyBuilding/ManageArcology.js
@@ -154,7 +154,7 @@ App.UI.manageArcology = function() {
 		const text = [];
 
 		if (V.weatherCladding === 0) {
-			text.push(`Extreme weather is becoming common worldwide. The arcology's exterior can be hardened to reduce damage in case of heavy weather, but this will reduce its beauty somewhat and will cost ${cashFormat(50000 * V.upgradeMultiplierArcology)}. Your citizens are`);
+			text.push(`Extreme weather is becoming common worldwide. The arcology's exterior can be hardened to reduce damage in case of heavy weather, but this will reduce its beauty somewhat. Your citizens are`);
 
 			if (V.weatherAwareness === 0) {
 				text.push(`likely to disapprove of this measure as alarmism.`);
@@ -176,11 +176,9 @@ App.UI.manageArcology = function() {
 			App.Events.addNode(div, text, "div");
 
 			if (V.weatherCladding === 1 && V.building.sections.length > 0) {
-				const cost = 3_500_000 * V.upgradeMultiplierArcology;
-
 				div.append(
-					`Your arcology is so prosperous that remodeling the cladding into something beautiful is within the realm of possibility. This massive project will cost ${cashFormat(cost)} and without a doubt render your arcology one of the wonders of the world.`,
-					makePurchase(`Remodel weather cladding`, cost, "capEx", {
+					`Your arcology is so prosperous that remodeling the cladding into something beautiful is within the realm of possibility. This massive project without a doubt render your arcology one of the wonders of the world.`,
+					makePurchase(`Remodel weather cladding`, 3_500_000 * V.upgradeMultiplierArcology, "capEx", {
 						handler: () => {
 							V.weatherCladding++;
 							V.PC.skill.engineering++;
@@ -201,7 +199,6 @@ App.UI.manageArcology = function() {
 						V.FCTV.weekEnabled = V.week;
 						FCTV.initChannels();
 
-
 						repX(500, "capEx");
 					},
 				}),
diff --git a/src/arcologyBuilding/presets.js b/src/arcologyBuilding/presets.js
index 711c2c265026f5e8586e64270e95cd2240e12df3..c364817abba774cb752645ff17f1b239592d6f03 100644
--- a/src/arcologyBuilding/presets.js
+++ b/src/arcologyBuilding/presets.js
@@ -293,7 +293,6 @@ App.Arcology.upgrades = function(building) {
 			const cost = upgrade.cost * V.upgradeMultiplierArcology;
 			div.append(
 				makePurchase(`...${upgrade.desc}`, cost, "capEx", {
-					notes: [`This huge project will cost ${cashFormat(cost)}`],
 					handler: () => {
 						if (building.usedUpgrades.length === 0) {
 							// the first major upgrade gives skill, successive ones not, mainly because there might be a
@@ -302,8 +301,6 @@ App.Arcology.upgrades = function(building) {
 						}
 						building.usedUpgrades.push(upgrade.id);
 						upgrade.apply();
-						cashX(-cost, "capEx");
-
 						App.UI.reload();
 					},
 				}),
diff --git a/src/art/artJS.js b/src/art/artJS.js
index 238adda296666bae66c79106e8ce4fdd5362a074..2a8dab1c1b9bc28400c259014e4f5abd82a997a9 100644
--- a/src/art/artJS.js
+++ b/src/art/artJS.js
@@ -265,11 +265,11 @@ App.Art.webglInitialize = function() {
 }();
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {App.Entity.SlaveState} inSlave
  * @param {number} artSize
  * @returns {HTMLElement}
  */
-App.Art.webglArtElement = function(slave, artSize) {
+App.Art.webglArtElement = function(inSlave, artSize) {
 	let container = document.createElement("div");
 	container.setAttribute("class", "artContainer");
 	container.style.fontSize = "large";
@@ -279,6 +279,9 @@ App.Art.webglArtElement = function(slave, artSize) {
 	container.style.height = sz[1] + "px";
 	// container.innerText = "Loading...";
 
+	// we're being asked to render this slave at this snapshot in time, but we're doing so asynchronously, so clone her first
+	// it's common for e.g. events to make alterations to a slave just before rendering and revert them afterwards
+	const slave = clone(inSlave);
 	container.addEventListener("engineLoaded", function() {
 		 new IntersectionObserver(function(entries) {
 			if (entries.some(e => e.isIntersecting)) {
diff --git a/src/art/webgl/ui.js b/src/art/webgl/ui.js
index 194607bf37ef98c0aaea0d54dd1a8824e0112f16..dc05e3d74ce13541843a2d20b7185a47323927b9 100644
--- a/src/art/webgl/ui.js
+++ b/src/art/webgl/ui.js
@@ -280,7 +280,7 @@ App.Art.createWebglUI = function(container, slave, artSize, scene, p) {
 	} else {
 		// default
 		updateLinkedButtons();
-		if (artSize < 3) {
+		if (!V.seeAnimation || artSize < 3) {
 			render();
 		}
 	}
diff --git a/src/budget/repBudget.js b/src/budget/repBudget.js
index d7df45658b2ebf65a2b5461b374754704e1cceea..f3a1be735b4c0eee337340735e5f31cb08134efb 100644
--- a/src/budget/repBudget.js
+++ b/src/budget/repBudget.js
@@ -31,7 +31,7 @@ App.Budget.rep = function() {
 	 */
 	function settings() {
 		const p = document.createElement("p");
-		App.UI.DOM.appendNewElement("div", p, "Your weekly reputation changes are as follows:", "detail");
+		App.UI.DOM.appendNewElement("div", p, "Your weekly reputation changes are as follows:", ["detail"]);
 
 		let options = new App.UI.OptionsGroup();
 		options.addOption("", "repBudget", V.showAllEntries)
diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js
index 2d86ff9fbff1504d74b24d3a442dcc5f2e504812..c6cdac06ce129c3c1b327e12c92bcddda968d3f3 100644
--- a/src/data/backwardsCompatibility/backwardsCompatibility.js
+++ b/src/data/backwardsCompatibility/backwardsCompatibility.js
@@ -171,6 +171,14 @@ App.Update.globalVariables = function(node) {
 	if (V.rivalOwnerEnslaved) {
 		V.rival.state = 5;
 	}
+	if (V.releaseID < 1180) {
+		const rivalEnslaved = V.slaves.filter(s => s.newGamePlus === 0 && s.origin.includes("$He was once an arcology owner like yourself.")).length > 0;
+		if (V.rival.state === 1 && rivalEnslaved) {
+			V.rival.state = 5;
+		} else if (V.rival.state === 1 && !rivalEnslaved && V.arcologies.find(a => a.direction !== 0 && a.rival !== 1)) {
+			V.rival.state = 4;
+		}
+	}
 	if (V.rivalGender) {
 		V.rival.gender = V.rivalGender;
 	}
@@ -707,6 +715,9 @@ App.Update.globalVariables = function(node) {
 			} else if (typeof V.arcologies[0].FSSlimnessEnthusiastSMR === "undefined") {
 				V.arcologies[0].FSSlimnessEnthusiastSMR = 0;
 			}
+			if (typeof V.arcologies[0].FSSlimnessEnthusiastFoodLaw === "undefined") {
+				V.arcologies[0].FSSlimnessEnthusiastFoodLaw = 0;
+			}
 			if ((typeof V.FSMaturityPreferentialist !== "undefined") && V.FSMaturityPreferentialist !== "unset") {
 				V.arcologies[0].FSMaturityPreferentialist = V.FSMaturityPreferentialist;
 			} else if (typeof V.arcologies[0].FSMaturityPreferentialist === "undefined") {
diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js
index 7f5e6e93a66d015c75e400d5b2be3f0406cf9ca5..dbccd3d3c04dc8082f0e7f17414d63de36f25648 100644
--- a/src/data/backwardsCompatibility/datatypeCleanup.js
+++ b/src/data/backwardsCompatibility/datatypeCleanup.js
@@ -1234,17 +1234,9 @@ globalThis.PCDatatypeCleanup = (function PCDatatypeCleanup() {
 			PC.health = {};
 			PC.health.condition = condition;
 		}
+		PC.majorInjury = Math.max(+PC.majorInjury, 0) || 0;
 		PC.health.condition = Math.clamp(PC.health.condition, -100, 100) || 0;
-		if (PC.majorInjury !== undefined) {
-			if (PC.majorInjury > 0) {
-				PC.health.shortDamage = Math.max(PC.majorInjury * 20, 30);
-			} else {
-				PC.health.shortDamage = 0;
-			}
-			delete PC.majorInjury;
-		} else {
-			PC.health.shortDamage = Math.max(+PC.health.shortDamage, 0) || 0;
-		}
+		PC.health.shortDamage = Math.max(+PC.health.shortDamage, 0) || 0;
 		PC.health.longDamage = Math.max(+PC.health.longDamage, 0) || 0;
 		PC.health.illness = Math.max(+PC.health.illness, 0) || 0;
 		PC.health.tired = Math.clamp(+PC.health.tired, 0, 100) || 0;
diff --git a/src/data/backwardsCompatibility/updateSlaveObject.js b/src/data/backwardsCompatibility/updateSlaveObject.js
index 4664267c46e08735c49beee98fc21d8e01868009..55b9ee0ba6f8f687cb169d7cbe662894fc479f09 100644
--- a/src/data/backwardsCompatibility/updateSlaveObject.js
+++ b/src/data/backwardsCompatibility/updateSlaveObject.js
@@ -766,17 +766,16 @@ App.Update.Slave = function(slave, genepool = false) {
 		}
 	}
 
-	let backwardsCompatibility;
 	if (slave.rivalry !== 0) {
-		backwardsCompatibility = V.slaveIndices[slave.rivalryTarget];
-		if (backwardsCompatibility === undefined) {
+		const test = getSlave(slave.rivalryTarget);
+		if (!test) {
 			slave.rivalry = 0;
 			slave.rivalryTarget = 0;
 		}
 	}
 	if (slave.relationship > 0) {
-		backwardsCompatibility = V.slaveIndices[slave.relationshipTarget];
-		if (backwardsCompatibility === undefined) {
+		const test = getSlave(slave.relationshipTarget);
+		if (!test) {
 			slave.relationship = 0;
 			slave.relationshipTarget = 0;
 		}
diff --git a/src/descriptions/familySummaries.js b/src/descriptions/familySummaries.js
index cc11db585a1b8429e5afd93bdf6032d9c20de198..3f3082a8cea168cc284eea94dc82ec663e5baa8e 100644
--- a/src/descriptions/familySummaries.js
+++ b/src/descriptions/familySummaries.js
@@ -1,27 +1,36 @@
 App.Desc.family = (function() {
 	/** From a list of slaves, return their names, comma-separated and appended with "and" if necessary
 	 * @param {Array<App.Entity.SlaveState>} slaveList
-	 * @returns {string}
+	 * @param {boolean} links Should slave names be links
+	 * @returns {DocumentFragment|HTMLElement|string}
 	 */
-	function slaveListToText(slaveList) {
-		return slaveList.map(s => s.slaveName).reduce((res, ch, i, arr) => res + (i === arr.length - 1 ? ' and ' : ', ') + ch);
+	function slaveListToText(slaveList, links) {
+		if (!links) {
+			return toSentence(slaveList.map(s => s.slaveName));
+		}
+		return App.UI.DOM.toSentence(slaveList.map(s => App.UI.DOM.referenceSlaveWithPreview(s, s.slaveName)));
 	}
 
-	/** See if an ID refers to a valid, active slave. This will return false for slaves that no longer exist or have not yet been created.
-	 * @param {number} slaveID
-	 * @returns {boolean}
+	/**
+	 * @param {Array<HTMLElement|DocumentFragment|string>} parts
+	 * @returns {HTMLSpanElement}
 	 */
-	function validSlaveID(slaveID) {
-		return slaveID > 0 && _.isObject(getSlave(slaveID));
+	function familySpan(...parts) {
+		const span = document.createElement("span");
+		span.classList.add("si-family");
+		span.append(...parts);
+		return span;
 	}
 
 	/** From a slave ID, return text describing that slave (even if they aren't currently your slave) to use in place of their name
 	 * @param {number} slaveID
-	 * @returns {string}
+	 * @param {boolean} allowLinks
+	 * @returns {string|HTMLSpanElement}
 	 */
-	function knownSlave(slaveID) {
-		if (validSlaveID(slaveID)) {
-			return getSlave(slaveID).slaveName;
+	function knownSlave(slaveID, allowLinks) {
+		const rel = findFather(slaveID);
+		if (slaveID > 0 && rel) {
+			return conditionalSlaveLink(rel, allowLinks);
 		} else if (slaveID in V.missingTable) {
 			return "your former slave " + V.missingTable[slaveID].slaveName;
 		} else {
@@ -29,6 +38,22 @@ App.Desc.family = (function() {
 		}
 	}
 
+	/**
+	 * @param {Relative} slave
+	 * @param {boolean} allowLinks
+	 * @returns {HTMLSpanElement|string}
+	 */
+	function conditionalSlaveLink(slave, allowLinks) {
+		const ownedSlave = getSlave(slave.ID);
+		if (allowLinks && ownedSlave) {
+			return App.UI.DOM.referenceSlaveWithPreview(ownedSlave, slave.slaveName);
+		} else if (slave.ID in V.missingTable) {
+			return "your former slave " + slave.slaveName;
+		} else {
+			return slave.slaveName;
+		}
+	}
+
 	/** Splits an array of slaves by sex (nieces/nephews, aunts/uncles, brothers/sisters, etc)
 	 * @param {Array<App.Entity.SlaveState>} slaves
 	 * @returns {{m: Array<App.Entity.SlaveState>, f: Array<App.Entity.SlaveState>}}
@@ -47,24 +72,30 @@ App.Desc.family = (function() {
 
 	/** Describe the members of a character's family.
 	 * @param {FC.HumanState} character (pass V.PC to get the PC's special family summary)
-	 * @returns {string}
+	 * @param {boolean} [allowLinks=false] Allow names of family members to be links to them. Should be disabled if the
+	 *                                      passage is not safe to navigate from.
+	 * @returns {DocumentFragment}
 	 */
-	function familySummary(character) {
+	function familySummary(character, allowLinks = false) {
+		let text;
 		if (character === V.PC) {
-			return PCFamilySummary();
+			text = PCFamilySummary(allowLinks);
 		} else {
-			return slaveFamilySummary(asSlave(character));
+			text = slaveFamilySummary(asSlave(character), allowLinks);
 		}
+		const f = new DocumentFragment();
+		$(f).append(...App.Events.spaceSentences(text));
+		return f;
 	}
 
 	/** Describe the members of a slave's family.
 	 * @param {App.Entity.SlaveState} slave
-	 * @returns {string}
+	 * @param {boolean} allowLinks
+	 * @returns {Array<string|HTMLElement|DocumentFragment>}
 	 */
-	function slaveFamilySummary(slave) {
-		let r = [];
-
+	function slaveFamilySummary(slave, allowLinks) {
 		const {He, His, he, him, himself, his, sister} = getPronouns(slave);
+		const r = [];
 
 		/* PC parentage */
 		if (slave.ID === V.PC.mother && slave.ID === V.PC.father) {
@@ -78,136 +109,194 @@ App.Desc.family = (function() {
 		if (slave.father === -1 && slave.mother === -1) {
 			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked yourself up and gave birth to ${him}.`);
 		} else if (slave.father === slave.mother && (slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves))) {
-			r.push(`${He} was <span class="lightgreen">both fathered and mothered by ${knownSlave(slave.father)}.</span>`);
+			r.push(`${He} was `, familySpan(`both fathered and mothered by `, knownSlave(slave.father, allowLinks), `.`));
 		}
 
 		if (slave.father === -1 && slave.mother !== -1) {
 			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked ${his} mother up.`);
 		} else if ((slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
-			r.push(`${He} was <span class="lightgreen">fathered by ${knownSlave(slave.father)}'s</span> virile dick.`);
+			r.push(`${He} was `, familySpan(`fathered by `, knownSlave(slave.father, allowLinks), `'s`), ` virile dick.`);
 		}
 
 		if (slave.father !== -1 && slave.mother === -1) {
 			r.push(`${He}'s <span class="lightgreen">your child;</span> you gave birth to ${him}.`);
 		} else if ((slave.mother > 0 || (slave.mother in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
-			r.push(`${He} was <span class="lightgreen">born from ${knownSlave(slave.mother)}'s</span> fertile womb.`);
+			r.push(`${He} was `, familySpan(`born from `, knownSlave(slave.mother, allowLinks), `'s`), ` fertile womb.`);
 		}
 
 		let children = V.slaves.filter((s) => slave.ID === s.father && slave.ID === s.mother);
 		const isSoleParent = children.length > 0;
 		if (children.length > 2) {
-			r.push(`${He} <span class="lightgreen">is the sole parent of ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`is the sole parent of `, slaveListToText(children, allowLinks), `.`));
 		} else if (children.length > 1) {
-			r.push(`${He} <span class="lightgreen">is the sole parent of a pair of your slaves: ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`is the sole parent of a pair of your slaves: `, slaveListToText(children, allowLinks), `.`));
 		} else if (children.length > 0) {
-			r.push(`${He} <span class="lightgreen">is the sole parent of a single slave of yours: ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`is the sole parent of a single slave of yours: `, slaveListToText(children, allowLinks), `.`));
 		}
 
 		children = V.slaves.filter((s) => slave.ID === s.father && slave.ID !== s.mother);
 		if (children.length > 2) {
-			r.push(`${He} <span class="lightgreen">fathered ${slaveListToText(children)}${isSoleParent ? " with other mothers" : ""}.</span>`);
+			r.push(He, familySpan(`fathered `, slaveListToText(children, allowLinks), `${isSoleParent ? " with other mothers" : ""}.`));
 		} else if (children.length > 1) {
-			r.push(`${He} <span class="lightgreen">fathered a pair of your slaves${isSoleParent ? " with other mothers" : ""}: ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`fathered a pair of your slaves${isSoleParent ? " with other mothers" : ""}: `, slaveListToText(children, allowLinks), `.`));
 		} else if (children.length > 0) {
-			r.push(`${He} <span class="lightgreen">fathered a single slave of yours${isSoleParent ? " with another mother" : ""}: ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`fathered a single slave of yours${isSoleParent ? " with another mother" : ""}: `, slaveListToText(children, allowLinks), `.`));
 		}
 
 		children = V.slaves.filter((s) => slave.ID === s.mother && slave.ID !== s.father);
 		if (children.length > 2) {
-			r.push(`${He} <span class="lightgreen">gave birth to ${slaveListToText(children)}${isSoleParent ? " with other fathers" : ""}.</span>`);
+			r.push(He, familySpan(`gave birth to `, slaveListToText(children, allowLinks), `${isSoleParent ? " with other fathers" : ""}.`));
 		} else if (children.length > 1) {
-			r.push(`${He} <span class="lightgreen">gave birth to a pair of your slaves${isSoleParent ? " with other fathers" : ""}: ${slaveListToText(children)}.</span>`);
+			r.push(He, familySpan(`gave birth to a pair of your slaves${isSoleParent ? " with other fathers" : ""}: `, slaveListToText(children, allowLinks), `.`));
 		} else if (children.length > 0) {
-			r.push(`${He} <span class="lightgreen">gave birth to a single slave of yours${isSoleParent ? " with another father" : ""}: ${slaveListToText(children)}.</span>`);
-		}
-
-		function getParentIndices(slaveID) {
-			if (slaveID === V.PC.ID) {
-				return {mi: V.slaveIndices[V.PC.mother], fi: V.slaveIndices[V.PC.father]};
-			} else {
-				const target = getSlave(slaveID);
-				if (target) {
-					return {mi: V.slaveIndices[target.mother], fi: V.slaveIndices[target.father]};
-				}
-			}
-			return {mi: undefined, fi: undefined};
+			r.push(He, familySpan(`gave birth to a single slave of yours${isSoleParent ? " with another father" : ""}: `, slaveListToText(children, allowLinks), `.`));
 		}
 
 		if (V.showDistantRelatives) {
 			/* grandparents */
-			const mi = V.slaveIndices[slave.mother];
-			const fi = V.slaveIndices[slave.father];
-			const {mi: mmi, fi: fmi} = getParentIndices(slave.mother);
-			const {mi: mfi, fi: ffi} = getParentIndices(slave.father);
-			if ((jsDef(mi) || jsDef(fi)) && !jsDef(mmi) && !jsDef(fmi) && !jsDef(mfi) && !jsDef(ffi)) {
-				if (jsDef(mi)) {
-					if ((jsDef(fi)) && mi === fi) {
-						if (V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].father) {
-							r.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with ${his} sole biological parent.</span>`);
-						} else if (V.PC.ID === V.slaves[mi].mother) {
-							r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} sole biological parent.</span>`);
-						} else if (V.PC.ID === V.slaves[fi].father) {
-							r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} sole biological parent.</span>`);
-						}
-					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to both of ${his} parents.</span>`);
-					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].father && V.PC.ID === V.slaves[fi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered both of ${his} parents.</span>`);
-					} else if (V.PC.ID === V.slaves[mi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} mother.</span>`);
-					} else if (V.PC.ID === V.slaves[mi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} mother.</span>`);
+			const mom = getRelative(slave.mother);
+			const dad = getRelative(slave.father);
+			const mgmom = mom ? getRelative(mom.mother) : null;
+			const mgdad = mom ? getRelative(mom.father) : null;
+			const pgmom = dad ? getRelative(dad.mother) : null;
+			const pgdad = dad ? getRelative(dad.father) : null;
+			if (mom && dad && mom.ID === dad.ID) { // sole parent
+				if (mgmom && mgdad && mgmom.ID === mgdad.ID) { // sole grandparent
+					if (mgmom.ID === V.PC.ID) {
+						r.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with ${his} sole biological parent.</span>`);
+					} else {
+						r.push(`${His} sole`, familySpan(`grandparent is `, conditionalSlaveLink(mgmom, allowLinks), `,`), `who gave birth to ${his} sole biological parent.`);
 					}
-				} else if (jsDef(fi)) {
-					if (V.PC.ID === V.slaves[fi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} father.</span>`);
-					} else if (V.PC.ID === V.slaves[fi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} father.</span>`);
+				} else { // two grandparents
+					if (mgmom && mgmom.ID === V.PC.ID) {
+						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} sole biological parent.</span>`);
+					} else if (mgmom) {
+						r.push(`${His} sole`, familySpan(`grandmother is `, conditionalSlaveLink(mgmom, allowLinks), `,`), `who gave birth to ${his} sole biological parent.`);
+					}
+					if (mgdad && mgdad.ID === V.PC.ID) {
+						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} sole biological parent.</span>`);
+					} else if (mgdad) {
+						r.push(`${His} sole`, familySpan(`grandfather is `, conditionalSlaveLink(mgdad, allowLinks), `,`), `who fathered ${his} sole biological parent.`);
 					}
 				}
-			} else {
-				if ((jsDef(mmi)) && (jsDef(ffi)) && mmi === ffi) {
-					r.push(`${His} sole <span class="lightgreen">grandparent is ${V.slaves[mmi].slaveName}.</span>`);
-				} else {
-					if ((jsDef(mmi)) && (jsDef(mfi)) && mmi === mfi) {
-						r.push(`${His} sole <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
+			} else { // two parents means between one and four grandparents
+				if (mgmom && mgdad && pgmom && pgdad && mgmom.ID === mgdad.ID && mgmom.ID === pgmom.ID && pgmom.ID === pgdad.ID) { // one grandparent
+					if (mgmom.ID === V.PC.ID) {
+						r.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with both of ${his} parents.</span>`);
 					} else {
-						if (jsDef(mmi)) {
-							r.push(`${His} maternal <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
+						r.push(`${His} sole `, familySpan(`grandparent is `, conditionalSlaveLink(mgmom, allowLinks), `.`));
+					}
+				} else {
+					// two grandparents can mean:
+					// two sole parents, one for each parent
+					// shared grandfather AND shared grandmother
+					// paternal grandmother is maternal grandfather and vice versa (no special handling)
+					// any 3+1 combination (no special handling)
+
+					// three grandparents can mean:
+					// sole grandparent on one side or the other
+					// same grandfather on both sides
+					// same grandmother on both sides
+					// paternal grandmother is maternal grandfather OR vice versa (no special handling)
+
+					// four distinct grandparents is easy
+
+					let didMGMom = false;
+					let didMGDad = false;
+					let didPGMom = false;
+					let didPGDad = false;
+					let pcout = [];
+					let npcout = [];
+
+					// so we handle: sole parents, on either or both sides
+					if (mgmom && mgdad && mgmom.ID === mgdad.ID) {
+						if (mgmom.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with ${his} mother.</span>`);
+						} else {
+							npcout.push(`${His} sole `, familySpan(`maternal grandparent is `, conditionalSlaveLink(mgmom, allowLinks), `.`));
 						}
-						if (jsDef(mfi)) {
-							r.push(`${His} paternal <span class="lightgreen">grandmother is ${V.slaves[mfi].slaveName}.</span>`);
+						didMGMom = didMGDad = true;
+					}
+					if (pgmom && pgdad && pgmom.ID === pgdad.ID) {
+						if (pgmom.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with ${his} father.</span>`);
+						} else {
+							npcout.push(`${His} sole `, familySpan(`paternal grandparent is `, conditionalSlaveLink(mgmom, allowLinks), `.`));
 						}
+						didPGMom = didPGDad = true;
 					}
-					if ((jsDef(fmi)) && (jsDef(ffi)) && fmi === ffi) {
-						r.push(`${His} sole <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
-					} else {
-						if (jsDef(fmi)) {
-							r.push(`${His} maternal <span class="lightgreen">grandfather is ${V.slaves[fmi].slaveName}.</span>`);
+
+					// shared grandfather
+					if (mgdad && pgdad && mgdad.ID === pgdad.ID) {
+						if (mgdad.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You fathered both of ${his} parents.</span>`);
+						} else {
+							npcout.push(`${His} sole `, familySpan(`grandfather is `, conditionalSlaveLink(mgdad, allowLinks), `.`));
+						}
+						didMGDad = didPGDad = true;
+					}
+
+					// shared grandmother
+					if (mgmom && pgmom && mgmom.ID === pgmom.ID) {
+						if (mgmom.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to both of ${his} parents.</span>`);
+						} else {
+							npcout.push(`${His} sole `, familySpan(`grandmother is `, conditionalSlaveLink(mgmom, allowLinks), `.`));
+						}
+						didMGMom = didPGMom = true;
+					}
+
+					// pick up any remaining grandparents (and the unhandled crosses)
+					if (mgdad && !didMGDad) {
+						if (mgdad.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} mother.</span>`);
+						} else {
+							npcout.push(`${His} maternal `, familySpan(`grandfather is `, conditionalSlaveLink(mgdad, allowLinks), `.`));
 						}
-						if (ffi) {
-							r.push(`${His} paternal <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
+					}
+					if (mgmom && !didMGMom) {
+						if (mgmom.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} mother.</span>`);
+						} else {
+							npcout.push(`${His} maternal `, familySpan(`grandmother is `, conditionalSlaveLink(mgmom, allowLinks), `.`));
 						}
 					}
+					if (pgdad && !didPGDad) {
+						if (pgdad.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} father.</span>`);
+						} else {
+							npcout.push(`${His} paternal `, familySpan(`grandfather is `, conditionalSlaveLink(pgdad, allowLinks), `.`));
+						}
+					}
+					if (pgmom && !didPGMom) {
+						if (pgmom.ID === V.PC.ID) {
+							pcout.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} father.</span>`);
+						} else {
+							npcout.push(`${His} paternal `, familySpan(`grandmother is `, conditionalSlaveLink(pgmom, allowLinks), `.`));
+						}
+					}
+
+					// reorder: pc as grandparent first, followed by NPC grandparents.
+					r.push(...pcout, ...npcout);
 				}
 			}
 
 			/* PC grandparents - determines if the current slave is your grandparent */
-			const pcMother = getSlave(V.PC.mother);
-			const pcFather = getSlave(V.PC.father);
+			const pcMother = getRelative(V.PC.mother);
+			const pcFather = getRelative(V.PC.father);
 			if (jsDef(pcMother)) {
 				if ((jsDef(pcFather)) && pcMother === pcFather) {
 					if (slave.ID === pcMother.mother && slave.ID === pcFather.father) {
-						r.push(`${He} is <span class="lightgreen">your sole grandparent. ${He} impregnated ${himself} with your sole parent ${pcMother.slaveName} who in turn impregnated themselves with you.</span>`);
+						r.push(`${He} is `, familySpan(`your sole grandparent. ${He} impregnated ${himself} with your sole parent `, conditionalSlaveLink(pcMother, allowLinks), ` who in turn impregnated themselves with you.`));
 					} else if (slave.ID === pcMother.mother) {
-						r.push(`${He} is <span class="lightgreen">your sole grandmother. ${He} gave birth to ${pcMother.slaveName} who in turn impregnated themselves with you.</span>`);
+						r.push(`${He} is `, familySpan(`your sole grandmother. ${He} gave birth to `, conditionalSlaveLink(pcMother, allowLinks), ` who in turn impregnated themselves with you.`));
 					} else if (slave.ID === pcFather.father) {
-						r.push(`${He} is <span class="lightgreen">your sole grandfather. ${He} fathered ${pcFather.slaveName} who in turn impregnated themselves with you.</span>`);
+						r.push(`${He} is `, familySpan(`your sole grandfather. ${He} fathered `, conditionalSlaveLink(pcFather, allowLinks), ` who in turn impregnated themselves with you.`));
 					}
 				} else if ((jsDef(pcFather)) && slave.ID === pcMother.mother && slave.ID === pcFather.mother) {
-					r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to both of your parents, ${pcMother.slaveName} and ${pcFather.slaveName}.`);
+					r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to both of your parents, `, conditionalSlaveLink(pcMother, allowLinks), ` and `, conditionalSlaveLink(pcFather, allowLinks), `.`);
 				} else if ((jsDef(pcFather)) && slave.ID === pcMother.father && slave.ID === pcFather.father) {
-					r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered both of your parents, ${pcFather.slaveName} and ${pcMother.slaveName}.`);
+					r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered both of your parents, `, conditionalSlaveLink(pcFather, allowLinks), ` and `, conditionalSlaveLink(pcMother, allowLinks), `.`);
 				} else if (slave.ID === pcMother.mother) {
 					r.push(`${He} is <span class="lightgreen">your maternal grandmother.</span>`);
 				} else if (slave.ID === pcMother.father) {
@@ -226,11 +315,11 @@ App.Desc.family = (function() {
 			if (children.length > 0) {
 				r.push(`${He} has`);
 				if (children.length > 2) {
-					r.push(`<span class="lightgreen">many grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
+					r.push(familySpan(`many grandchildren, `, slaveListToText(children, allowLinks), `, amongst your slaves.`));
 				} else if (children.length > 1) {
-					r.push(`<span class="lightgreen">two grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
+					r.push(familySpan(`two grandchildren, `, slaveListToText(children, allowLinks), `, amongst your slaves.`));
 				} else {
-					r.push(`a <span class="lightgreen">grandchild, ${slaveListToText(children)}, as your slave.</span>`);
+					r.push(`a`, familySpan(`grandchild, `, slaveListToText(children, allowLinks), `, as your slave.`));
 				}
 			}
 
@@ -241,13 +330,13 @@ App.Desc.family = (function() {
 				r.push(`${He} is`);
 				if (slave.genes === "XX") {
 					if (aunts.length > 0) {
-						r.push(`<span class="lightgreen">your aunt along with ${slaveListToText(aunts)}.</span>`);
+						r.push(familySpan(`your aunt along with `, slaveListToText(aunts, allowLinks), `.`));
 					} else {
 						r.push(`<span class="lightgreen">your aunt.</span>`);
 					}
 				} else {
 					if (uncles.length > 0) {
-						r.push(`<span class="lightgreen">your uncle along with ${slaveListToText(uncles)}.</span>`);
+						r.push(familySpan(`your uncle along with `, slaveListToText(uncles, allowLinks), `.`));
 					} else {
 						r.push(`<span class="lightgreen">your uncle.</span>`);
 					}
@@ -260,21 +349,21 @@ App.Desc.family = (function() {
 			if (aunts.length > 0) {
 				r.push(`${He} has`);
 				if (aunts.length > 2) {
-					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`many aunts, `, slaveListToText(aunts, allowLinks), `.`));
 				} else if (aunts.length > 1) {
-					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`two aunts, `, slaveListToText(aunts, allowLinks), `.`));
 				} else {
-					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`an aunt, `, slaveListToText(aunts, allowLinks), `.`));
 				}
 			}
 			if (uncles.length > 0) {
 				r.push(`${He} has`);
 				if (uncles.length > 2) {
-					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`many uncles, `, slaveListToText(uncles, allowLinks), `.`));
 				} else if (uncles.length > 1) {
-					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`two uncles, `, slaveListToText(uncles, allowLinks), `.`));
 				} else {
-					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`an uncle, `, slaveListToText(uncles, allowLinks), `.`));
 				}
 			}
 
@@ -286,13 +375,13 @@ App.Desc.family = (function() {
 				r.push(`${He} is`);
 				if (slave.genes === "XX") {
 					if (nieces.length > 0) {
-						r.push(`<span class="lightgreen">your niece along with ${slaveListToText(nieces)}.</span>`);
+						r.push(familySpan(`your niece along with `, slaveListToText(nieces, allowLinks), `.`));
 					} else {
 						r.push(`<span class="lightgreen">your niece.</span>`);
 					}
 				} else {
 					if (nephews.length > 0) {
-						r.push(`<span class="lightgreen">your nephew along with ${slaveListToText(nephews)}.</span>`);
+						r.push(familySpan(`your nephew along with `, slaveListToText(nephews, allowLinks), `.`));
 					} else {
 						r.push(`<span class="lightgreen">your nephew.</span>`);
 					}
@@ -305,21 +394,21 @@ App.Desc.family = (function() {
 			if (nieces.length > 0) {
 				r.push(`${He} has`);
 				if (nieces.length > 2) {
-					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
+					r.push(familySpan(`many nieces, `, slaveListToText(nieces, allowLinks), `, who are your slaves.`));
 				} else if (nieces.length > 1) {
-					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
+					r.push(familySpan(`two nieces, `, slaveListToText(nieces, allowLinks), `, who are your slaves.`));
 				} else {
-					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
+					r.push(familySpan(`a niece, `, slaveListToText(nieces, allowLinks), `, who is your slave.`));
 				}
 			}
 			if (nephews.length > 0) {
 				r.push(`${He} has`);
 				if (nephews.length > 2) {
-					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
+					r.push(familySpan(`many nephews, `, slaveListToText(nephews, allowLinks), `, who are your slaves.`));
 				} else if (nephews.length > 1) {
-					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
+					r.push(familySpan(`two nephews, `, slaveListToText(nephews, allowLinks), `, who are your slaves.`));
 				} else {
-					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
+					r.push(familySpan(`a nephew, `, slaveListToText(nephews, allowLinks), `, who is your slave.`));
 				}
 			}
 		} /* end distant relatives toggle check */
@@ -353,9 +442,9 @@ App.Desc.family = (function() {
 		if (areSisters(slave, V.PC) === 1) {
 			r.push(He);
 			if (twins.length > 1) {
-				r.push(`<span class="lightgreen">shared a cramped womb with you, ${slaveListToText(twins)}.</span>`);
+				r.push(familySpan(`shared a cramped womb with you, `, slaveListToText(twins, allowLinks), `.`));
 			} else if (twins.length > 0) {
-				r.push(`is <span class="lightgreen">your twin along with ${slaveListToText(twins)}.</span>`);
+				r.push(`is `, familySpan(`your twin along with `, slaveListToText(twins, allowLinks), `.`));
 			} else {
 				r.push(`is <span class="lightgreen">your twin.</span>`);
 			}
@@ -366,7 +455,7 @@ App.Desc.family = (function() {
 		if (areSisters(slave, V.PC) === 2 && slave.genes === "XX") {
 			r.push(`${He} is`);
 			if (sisters.length > 0) {
-				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(sisters)}.</span>`);
+				r.push(familySpan(`your ${sister} along with `, slaveListToText(sisters, allowLinks), `.`));
 			} else {
 				r.push(`<span class="lightgreen">your ${sister}.</span>`);
 			}
@@ -377,7 +466,7 @@ App.Desc.family = (function() {
 		if (areSisters(slave, V.PC) === 2 && slave.genes === "XY") {
 			r.push(`${He} is`);
 			if (brothers.length > 0) {
-				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(brothers)}.</span>`);
+				r.push(familySpan(`your ${sister} along with `, slaveListToText(brothers, allowLinks), `.`));
 			} else {
 				r.push(`<span class="lightgreen">your ${sister}.</span>`);
 			}
@@ -388,7 +477,7 @@ App.Desc.family = (function() {
 		if (areSisters(slave, V.PC) === 3 && slave.genes === "XX") {
 			r.push(`${He} is`);
 			if (halfSisters.length > 0) {
-				r.push(`<span class="lightgreen">your half-${sister} along with ${slaveListToText(halfSisters)}.</span>`);
+				r.push(familySpan(`your half-${sister} along with `, slaveListToText(halfSisters, allowLinks), `.`));
 			} else {
 				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
 			}
@@ -399,7 +488,7 @@ App.Desc.family = (function() {
 		if (areSisters(slave, V.PC) === 3 && slave.genes === "XY") {
 			r.push(`${He} is`);
 			if (halfBrothers.length > 0) {
-				r.push(`<span class="lightgreen">your half-${sister} along with ${slaveListToText(halfBrothers)}.</span>`);
+				r.push(familySpan(`your half-${sister} along with `, slaveListToText(halfBrothers, allowLinks), `.`));
 			} else {
 				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
 			}
@@ -410,11 +499,11 @@ App.Desc.family = (function() {
 		if (twins.length > 0) {
 			r.push(`${He}`);
 			if (twins.length > 2) {
-				r.push(`<span class="lightgreen">shared a cramped womb with ${slaveListToText(twins)}.</span>`);
+				r.push(familySpan(`shared a cramped womb with `, slaveListToText(twins, allowLinks), `.`));
 			} else if (twins.length > 1) {
-				r.push(`is <span class="lightgreen">one of a set of triplets; ${slaveListToText(twins)}</span> complete the trio.`);
+				r.push(`is `, familySpan(`one of a set of triplets; `, slaveListToText(twins, allowLinks)), ` complete the trio.`);
 			} else {
-				r.push(`is <span class="lightgreen">twins with ${twins[0].slaveName}.</span>`);
+				r.push(`is `, familySpan(`twins with `, conditionalSlaveLink(twins[0], allowLinks), `.`));
 			}
 		}
 
@@ -422,9 +511,9 @@ App.Desc.family = (function() {
 		if (sisters.length > 0) {
 			const sister2 = getPronouns(sisters[0]).sister;
 			if (sisters.length > 1) {
-				r.push(`<span class="lightgreen">${slaveListToText(sisters)} are ${his} ${sister2}s.</span>`);
+				r.push(familySpan(slaveListToText(sisters, allowLinks), ` are ${his} ${sister2}s.`));
 			} else {
-				r.push(`<span class="lightgreen">${sisters[0].slaveName} is ${his} ${sister2}.</span>`);
+				r.push(familySpan(conditionalSlaveLink(sisters[0], allowLinks), ` is ${his} ${sister2}.`));
 			}
 		}
 
@@ -432,9 +521,9 @@ App.Desc.family = (function() {
 		if (brothers.length > 0) {
 			const sister2 = getPronouns(brothers[0]).sister;
 			if (brothers.length > 1) {
-				r.push(`<span class="lightgreen">${slaveListToText(brothers)} are ${his} ${sister2}s.</span>`);
+				r.push(familySpan(slaveListToText(brothers, allowLinks), ` are ${his} ${sister2}s.`));
 			} else {
-				r.push(`<span class="lightgreen">${brothers[0].slaveName} is ${his} ${sister2}.</span>`);
+				r.push(familySpan(conditionalSlaveLink(brothers[0], allowLinks), ` is ${his} ${sister2}.`));
 			}
 		}
 
@@ -442,9 +531,9 @@ App.Desc.family = (function() {
 		if (halfSisters.length > 0) {
 			const sister2 = getPronouns(halfSisters[0]).sister;
 			if (halfSisters.length > 1) {
-				r.push(`<span class="lightgreen">${slaveListToText(halfSisters)} are half-${sister2}s to ${him}.</span>`);
+				r.push(familySpan(slaveListToText(halfSisters, allowLinks), ` are half-${sister2}s to ${him}.`));
 			} else {
-				r.push(`<span class="lightgreen">${halfSisters[0].slaveName} is a half-${sister2} to ${him}.</span>`);
+				r.push(familySpan(conditionalSlaveLink(halfSisters[0], allowLinks), ` is a half-${sister2} to ${him}.`));
 			}
 		}
 
@@ -452,9 +541,9 @@ App.Desc.family = (function() {
 		if (halfBrothers.length > 0) {
 			const sister2 = getPronouns(halfBrothers[0]).sister;
 			if (halfBrothers.length > 1) {
-				r.push(`<span class="lightgreen">${slaveListToText(halfBrothers)} are half-${sister2}s to ${him}.</span>`);
+				r.push(familySpan(slaveListToText(halfBrothers, allowLinks), ` are half-${sister2}s to ${him}.`));
 			} else if (halfBrothers.length > 0) {
-				r.push(`<span class="lightgreen">${halfBrothers[0].slaveName} is a half-${sister2} to ${him}.</span>`);
+				r.push(familySpan(conditionalSlaveLink(halfBrothers[0], allowLinks), ` is a half-${sister2} to ${him}.`));
 			}
 		}
 
@@ -464,7 +553,7 @@ App.Desc.family = (function() {
 				const PCcousins = V.slaves.filter((s) => s.ID !== slave.ID && areCousins(V.PC, s));
 				r.push(`${He} is`);
 				if (PCcousins.length > 0) {
-					r.push(`<span class="lightgreen">your cousin along with ${slaveListToText(PCcousins)}.</span>`);
+					r.push(familySpan(`your cousin along with `, slaveListToText(PCcousins, allowLinks), `.`));
 				} else {
 					r.push(`<span class="lightgreen">your cousin.</span>`);
 				}
@@ -472,9 +561,9 @@ App.Desc.family = (function() {
 
 			/* cousin - determines how many cousins a slave has*/
 			if (cousins.length > 1) {
-				r.push(`<span class="lightgreen">${slaveListToText(cousins)} are cousins to ${him}.</span>`);
+				r.push(familySpan(slaveListToText(cousins, allowLinks), ` are cousins to ${him}.`));
 			} else if (cousins.length > 0) {
-				r.push(`<span class="lightgreen">${cousins[0].slaveName} is a cousin to ${him}.</span>`);
+				r.push(familySpan(conditionalSlaveLink(cousins[0], allowLinks), ` is a cousin to ${him}.`));
 			}
 		}
 
@@ -487,7 +576,7 @@ App.Desc.family = (function() {
 			}
 		}
 
-		if (V.cheatMode) {
+		if (V.debugMode) {
 			r.push(`${He} has ${numberWithPlural(slave.sisters, "sister")} and ${numberWithPlural(slave.daughters, "daughter")}.`);
 		}
 
@@ -507,14 +596,15 @@ App.Desc.family = (function() {
 			r.push(`inbred, with a CoI of ${slave.inbreedingCoeff}.`);
 		}
 
-		return r.join(" ");
+		return r;
 	}
 
 	/** Describe the members of the PC's family.
-	 * @returns {string}
+	 * @param {boolean} allowLinks
+	 * @returns {Array<string|HTMLElement|DocumentFragment>}
 	 */
-	function PCFamilySummary() {
-		let r = [];
+	function PCFamilySummary(allowLinks) {
+		const r = [];
 
 		r.push(`<br>Your family records show that:`);
 
@@ -531,14 +621,14 @@ App.Desc.family = (function() {
 		parents = parents.concat(V.slaves.filter((s) => isParentP(V.PC, s)));
 
 		if (parents.length > 1) {
-			r.push(`<br>Your parents are <span class="lightgreen">${knownSlave(parents[0].ID)} and ${knownSlave(parents[1].ID)}.</span>`);
+			r.push(`<br>Your parents are `, familySpan(knownSlave(parents[0].ID, allowLinks), ` and `, knownSlave(parents[1].ID, allowLinks), `.`));
 		} else if (parents.length > 0) {
 			if (V.PC.father === V.PC.mother) {
 				/* apparently we don't keep pronoun records in the missing parents table??? */
 				const himself = jsDef(parents[0].pronoun) ? getPronouns(parents[0]).himself : "herself";
-				r.push(`<br>Your parent is <span class="lightgreen">${knownSlave(parents[0].ID)},</span> who impregnated ${himself} with you.`);
+				r.push(`<br>Your parent is `, familySpan(knownSlave(parents[0].ID, allowLinks), `,`), ` who impregnated ${himself} with you.`);
 			} else {
-				r.push(`<br>You know one of your parents, <span class="lightgreen">${knownSlave(parents[0].ID)}.</span>`);
+				r.push(`<br>You know one of your parents, `, familySpan(knownSlave(parents[0].ID, allowLinks), `.`));
 			}
 		}
 
@@ -549,21 +639,21 @@ App.Desc.family = (function() {
 			if (aunts.length > 0) {
 				r.push(`<br>You have`);
 				if (aunts.length > 2) {
-					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`many aunts, `, slaveListToText(aunts, allowLinks), `.`));
 				} else if (aunts.length > 1) {
-					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`two aunts, `, slaveListToText(aunts, allowLinks), `.`));
 				} else {
-					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
+					r.push(familySpan(`an aunt, `, slaveListToText(aunts, allowLinks), `.`));
 				}
 			}
 			if (uncles.length > 0) {
 				r.push(`<br>You have`);
 				if (uncles.length > 2) {
-					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`many uncles, `, slaveListToText(uncles, allowLinks), `.`));
 				} else if (uncles.length > 1) {
-					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`two uncles, `, slaveListToText(uncles, allowLinks), `.`));
 				} else {
-					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
+					r.push(familySpan(`an uncle, `, slaveListToText(uncles, allowLinks), `.`));
 				}
 			}
 		}
@@ -594,44 +684,44 @@ App.Desc.family = (function() {
 		}
 
 		if (twins.length > 1) {
-			r.push(`<br>You are <span class="lightgreen">twins with ${slaveListToText(twins)}.</span>`);
+			r.push(`<br>You are `, familySpan(`twins with `, slaveListToText(twins, allowLinks), `.`));
 		} else if (twins.length > 0) {
-			r.push(`<br>Your twin is <span class="lightgreen">${twins[0].slaveName}.</span>`);
+			r.push(`<br>Your twin is `, familySpan(conditionalSlaveLink(twins[0], allowLinks), `.`));
 		}
 
 		if (sisters.length > 1) {
-			r.push(`<br><span class="lightgreen">${slaveListToText(sisters)}</span> are your sisters.`);
+			r.push(`<br>`, slaveListToText(sisters, allowLinks), ` are your sisters.`);
 		} else if (sisters.length > 0) {
 			const {sister} = getPronouns(sisters[0]);
-			r.push(`<br>Your ${sister} is <span class="lightgreen">${sisters[0].slaveName}.</span>`);
+			r.push(`<br>Your ${sister} is `, familySpan(conditionalSlaveLink(sisters[0], allowLinks), `.`));
 		}
 
 		if (brothers.length > 1) {
-			r.push(`<br><span class="lightgreen">${slaveListToText(brothers)}</span> are your brothers.`);
+			r.push(`<br>`, slaveListToText(brothers, allowLinks), ` are your brothers.`);
 		} else if (brothers.length > 0) {
 			const {sister} = getPronouns(brothers[0]);
-			r.push(`<br>Your ${sister} is <span class="lightgreen">${brothers[0].slaveName}.</span>`);
+			r.push(`<br>Your ${sister} is `, familySpan(conditionalSlaveLink(brothers[0], allowLinks), `.`));
 		}
 
 		if (halfSisters.length > 1) {
-			r.push(`<br><span class="lightgreen">${slaveListToText(halfSisters)}</span> are your half-sisters.`);
+			r.push(`<br>`, slaveListToText(halfSisters, allowLinks), ` are your half-sisters.`);
 		} else if (halfSisters.length > 0) {
 			const {sister} = getPronouns(halfSisters[0]);
-			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfSisters[0].slaveName}.</span>`);
+			r.push(`<br>You have one half-${sister}, `, familySpan(conditionalSlaveLink(halfSisters[0], allowLinks), `.`));
 		}
 
 		if (halfBrothers.length > 1) {
-			r.push(`<br><span class="lightgreen">${slaveListToText(halfBrothers)}</span> are your half-brothers.`);
+			r.push(`<br>`, slaveListToText(halfBrothers, allowLinks), ` are your half-brothers.`);
 		} else if (halfBrothers.length > 0) {
 			const {sister} = getPronouns(halfBrothers[0]);
-			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfBrothers[0].slaveName}.</span>`);
+			r.push(`<br>You have one half-${sister}, `, familySpan(conditionalSlaveLink(halfBrothers[0], allowLinks), `.`));
 		}
 
 		if (V.showDistantRelatives) {
 			if (cousins.length > 1) {
-				r.push(`<br><span class="lightgreen">${slaveListToText(cousins)}</span> are your cousins.`);
+				r.push(`<br>`, slaveListToText(cousins, allowLinks), ` are your cousins.`);
 			} else if (cousins.length > 0) {
-				r.push(`<br>You have one cousin, <span class="lightgreen">${cousins[0].slaveName}.</span>`);
+				r.push(`<br>You have one cousin, `, familySpan(conditionalSlaveLink(cousins[0], allowLinks), `.`));
 			}
 		}
 
@@ -642,21 +732,21 @@ App.Desc.family = (function() {
 			if (nieces.length > 0) {
 				r.push(`<br>You have`);
 				if (nieces.length > 2) {
-					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
+					r.push(familySpan(`many nieces, `, slaveListToText(nieces, allowLinks), `, who are your slaves.`));
 				} else if (nieces.length > 1) {
-					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
+					r.push(familySpan(`two nieces, `, slaveListToText(nieces, allowLinks), `, who are your slaves.`));
 				} else {
-					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
+					r.push(familySpan(`a niece, `, slaveListToText(nieces, allowLinks), `, who is your slave.`));
 				}
 			}
 			if (nephews.length > 0) {
 				r.push(`<br>You have`);
 				if (nephews.length > 2) {
-					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
+					r.push(familySpan(`many nephews, `, slaveListToText(nephews, allowLinks), `, who are your slaves.`));
 				} else if (nephews.length > 1) {
-					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
+					r.push(familySpan(`two nephews, `, slaveListToText(nephews, allowLinks), `, who are your slaves.`));
 				} else {
-					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
+					r.push(familySpan(`a nephew, `, slaveListToText(nephews, allowLinks), `, who is your slave.`));
 				}
 			}
 		}
@@ -664,31 +754,31 @@ App.Desc.family = (function() {
 		/* Player is sole parent */
 		let children = V.slaves.filter((s) => s.father === V.PC.ID && s.mother === V.PC.ID);
 		if (children.length > 0) {
-			r.push(`<br>You are the sole parent of ${num(children.length)} of your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
+			r.push(`<br>You are the sole parent of ${num(children.length)} of your slaves, `, familySpan(slaveListToText(children, allowLinks), `.`));
 		}
 		const isSoleParent = children.length > 0;
 
 		/* Player is Father, lists children you fathered */
 		children = V.slaves.filter((s) => s.father === V.PC.ID && s.mother !== V.PC.ID);
 		if (children.length > 0) {
-			r.push(`<br>You fathered ${num(children.length)} of your slaves${isSoleParent ? " with other mothers" : ''}, <span class="lightgreen">${slaveListToText(children)}.</span>`);
+			r.push(`<br>You fathered ${num(children.length)} of your slaves${isSoleParent ? " with other mothers" : ''}, `, familySpan(slaveListToText(children, allowLinks), `.`));
 		}
 
 		/* Player is Mother, lists birthed children */
 		children = V.slaves.filter((s) => s.mother === V.PC.ID && s.father !== V.PC.ID);
 		if (children.length > 0) {
-			r.push(`<br>You gave birth to ${num(children.length)} of your slaves${isSoleParent ? " who had other fathers" : ''}, <span class="lightgreen">${slaveListToText(children)}.</span>`);
+			r.push(`<br>You gave birth to ${num(children.length)} of your slaves${isSoleParent ? " who had other fathers" : ''}, `, familySpan(slaveListToText(children, allowLinks), `.`));
 		}
 
 		/* Player is grandparent */
 		if (V.showDistantRelatives) {
 			children = V.slaves.filter((s) => isGrandparentP(s, V.PC));
 			if (children.length > 0) {
-				r.push(`<br>You have ${num(children.length)} grandchildren as your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
+				r.push(`<br>You have ${num(children.length)} grandchildren as your slaves, `, familySpan(slaveListToText(children, allowLinks), `.`));
 			}
 		}
 
-		if (V.cheatMode) {
+		if (V.debugMode) {
 			r.push(`<br>You have ${numberWithPlural(V.PC.sisters, "sister")} and ${numberWithPlural(V.PC.daughters, "daughter")}.`);
 		}
 
@@ -708,7 +798,7 @@ App.Desc.family = (function() {
 			r.push(`inbred, with a CoI of ${V.PC.inbreedingCoeff}.`);
 		}
 
-		return r.join(" ");
+		return r;
 	}
 
 	return familySummary;
diff --git a/src/descriptions/officeDescription.js b/src/descriptions/officeDescription.js
index 07e72e31554197a3cd889c18726837e9e0931dc9..8e5555860bb5ada1a69fe814146bc5f4498272e3 100644
--- a/src/descriptions/officeDescription.js
+++ b/src/descriptions/officeDescription.js
@@ -370,7 +370,7 @@ App.Desc.officeDescription = function(lastElement) {
 								r.push(`${heA}'s depicted striking a pose with one arm supporting ${hisA} enormous implants.`);
 								break;
 							case "pastoralist":
-								r.push(`${heA}'s depicted striking a sexy pose, hands trying to relieve the pressure of ${hisA} quartet of milk filled breasts.`);
+								r.push(`${heA}'s depicted striking a sexy pose, hands trying to relieve the pressure of ${hisA} quartet of milk-filled breasts.`);
 								break;
 							case "maturity preferentialist":
 								r.push(`${heA}'s depicted in a pose not unlike something you'd see on a 60's pinup calendar`);
@@ -464,7 +464,6 @@ App.Desc.officeDescription = function(lastElement) {
 	function printTrinkets() {
 		const frag = new DocumentFragment();
 
-		// depending on length of trinketString, add necessary conjunctions
 		frag.append(
 			`There's a display case behind your desk, with `,
 			App.UI.DOM.linkReplace(`${num(V.trinkets.size)} items`, trinkets()),
@@ -474,179 +473,175 @@ App.Desc.officeDescription = function(lastElement) {
 		return frag;
 
 		function trinkets() {
-			const span = document.createElement("span");
-			const trinkets = [...V.trinkets];
+			const frag = new DocumentFragment();
 
-			trinkets.forEach((trinket, i) => {
-				const innerSpan = document.createElement("span");
+			/** @type {Array<string|HTMLElement>} */
+			let trinketElements = [];
+			let plurals = false;
 
-				if (trinkets.length > 1) {
-					if (i === trinkets.length - 1) {
-						if ((typeof trinket[1] === "number" && trinket[1] === 1) || (Array.isArray(trinket[1]) && trinket[1].length === 0)) {
-							innerSpan.append(
-								` and `,
-								trinket[0],
-							);
-						} else {
-							if (typeof trinket[1] !== "number") {
-								innerSpan.append(
-									` and `,
-									trinketPluralReplacer(trinket[0], trinket[1]),
-								);
-							}
-						}
-					} else {
-						innerSpan.append(`${trinket[0]}`);
+			for (const [trinketDesc, value] of V.trinkets) {
+				if ((typeof value === "number" && value === 1) || (Array.isArray(value) && value.length === 0)) {
+					trinketElements.push(capFirstChar(trinketDesc));
+				} else {
+					trinketElements.push(trinketPluralReplacer(trinketDesc, value));
+					plurals = true;
+				}
+			}
+			trinketElements.sort((a, b) => a > b ? 1 : -1);
 
-						if (trinkets.length > 2) {
-							innerSpan.append(`, `);
-						}
-					}
+			if (trinketElements.length === 1) {
+				if (V.trinkets.size === 1) {
+					frag.append(`a single item:`);
 				} else {
-					innerSpan.append(`a ${trinket[0]}`);
+					frag.append(`:`);
 				}
+			} else if (trinketElements.length === 2 && plurals === false) {
+				frag.append(`a couple of items:`);
+			}
+			const list = App.UI.DOM.appendNewElement("ul", frag);
 
-				span.append(innerSpan);
-			});
+			list.style.textIndent = "0";
+			trinketElements.forEach(ts => App.UI.DOM.appendNewElement("li", list, ts));
 
-			return span;
+			return frag;
 		}
 	}
 
 	/**
 	 *
 	 * @param {string} desc
-	 * @param {Array} array
-	 * @returns {HTMLSpanElement}
+	 * @param {number|FC.TrinketData[]} value
+	 * @returns {HTMLElement}
 	 */
-	function trinketPluralReplacer(desc, array) {
-		const his = (array && array[0] && array[0].id && getSlave(array[0].id) ? getPronouns(getSlave(array[0].id)).possessive : "their");
-		const he = (array && array[0] && array[0].id && getSlave(array[0].id) ? getPronouns(getSlave(array[0].id)).pronoun : "they");
+	function trinketPluralReplacer(desc, value) {
+		const isArray = Array.isArray(value) && value.length > 0;
+		const his = (isArray && value[0].id && getSlave(value[0].id) ? getPronouns(getSlave(value[0].id)).possessive : "their");
+		const he = (isArray && value[0].id && getSlave(value[0].id) ? getPronouns(getSlave(value[0].id)).pronoun : "they");
 		switch (desc) {
 			case "best in show balls":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a best in show ribbon awarded to`, slaveSentence(array), `for ${his} balls`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A best in show ribbon awarded to`, slaveSentence(value), `for ${his} balls`]);
 					} else {
-						App.Events.addNode(el, [`best in show ribbons awarded to`, slaveSentence(array), `for their balls`]);
+						App.Events.addNode(el, [`Best in show ribbons awarded to`, slaveSentence(value), `for their balls`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "best in show milk cow":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a best in show ribbon awarded to`, slaveSentence(array), `as a milk cow`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A best in show ribbon awarded to`, slaveSentence(value), `as a milk cow`]);
 					} else {
-						App.Events.addNode(el, [`best in show ribbons awarded to`, slaveSentence(array), `as milk cows`]);
+						App.Events.addNode(el, [`Best in show ribbons awarded to`, slaveSentence(value), `as milk cows`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "best in show breeder":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a best in show ribbon awarded to`, slaveSentence(array), `as a breeder`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A best in show ribbon awarded to`, slaveSentence(value), `as a breeder`]);
 					} else {
-						App.Events.addNode(el, [`best in show ribbons awarded to`, slaveSentence(array), `as breeders`]);
+						App.Events.addNode(el, [`Best in show ribbons awarded to`, slaveSentence(value), `as breeders`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "famous courtesan":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a framed article written about`, slaveSentence(array), `when ${he} debuted as a famous courtesan`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A framed article written about`, slaveSentence(value), `when ${he} debuted as a famous courtesan`]);
 					} else {
-						App.Events.addNode(el, [`framed articles written about`, slaveSentence(array), `when they debuted as famous courtesans`]);
+						App.Events.addNode(el, [`Framed articles written about`, slaveSentence(value), `when they debuted as famous courtesans`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "famous whore":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a framed pornographic advertisement for`, slaveSentence(array), `from the week ${he} became a famous whore`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A framed pornographic advertisement for`, slaveSentence(value), `from the week ${he} became a famous whore`]);
 					} else {
-						App.Events.addNode(el, [`framed pornographic advertisements from`, slaveSentence(array), `from the weeks they became famous whores`]);
+						App.Events.addNode(el, [`Framed pornographic advertisements from`, slaveSentence(value), `from the weeks they became famous whores`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "catgirl icon":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a gorgeous quasi-religious icon made by`, slaveSentence(array), `showing you creating the catgirl race`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A gorgeous quasi-religious icon made by`, slaveSentence(value), `showing you creating the catgirl race`]);
 					} else {
-						App.Events.addNode(el, [`gorgeous quasi-religious icons made by`, slaveSentence(array), `showing you creating the catgirl race`]);
+						App.Events.addNode(el, [`Gorgeous quasi-religious icons made by`, slaveSentence(value), `showing you creating the catgirl race`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "cat clay sculpture":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a small, elegant clay sculpture made by`, slaveSentence(array), `showing you surrounded by happy catgirl slaves`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A small, elegant clay sculpture made by`, slaveSentence(value), `showing you surrounded by happy catgirl slaves`]);
 					} else {
-						App.Events.addNode(el, [`small, elegant clay sculptures made by`, slaveSentence(array), `showing you surrounded by happy catgirl slaves`]);
+						App.Events.addNode(el, [`Small, elegant clay sculptures made by`, slaveSentence(value), `showing you surrounded by happy catgirl slaves`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "cat drawing":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a pretty drawing of you and`, slaveSentence(array), `cuddling together peacefully`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A pretty drawing of you and`, slaveSentence(value), `cuddling together peacefully`]);
 					} else {
-						App.Events.addNode(el, [`pretty drawings of you and`, slaveSentence(array), `cuddling together peacefully`]);
+						App.Events.addNode(el, [`Pretty drawings of you and`, slaveSentence(value), `cuddling together peacefully`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "cat crayon":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a red construction paper heart with crude crayon figures of you and`, slaveSentence(array), `holding hands above text reading "I LUV U ${V.PC.title !== 0 ? `MASTER` : `MISTRESS`}"`]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A red construction paper heart with crude crayon figures of you and`, slaveSentence(value), `holding hands above text reading "I LUV U ${V.PC.title !== 0 ? `MASTER` : `MISTRESS`}"`]);
 					} else {
-						App.Events.addNode(el, [`red construction paper hearts with crude crayon figures of you and`, slaveSentence(array), `holding hands above text reading "I LUV U ${V.PC.title !== 0 ? `MASTER` : `MISTRESS`}"`]);
+						App.Events.addNode(el, [`Red construction paper hearts with crude crayon figures of you and`, slaveSentence(value), `holding hands above text reading "I LUV U ${V.PC.title !== 0 ? `MASTER` : `MISTRESS`}"`]);
 					}
 					return el;
 				} else {
 					return null;
 				}
 			case "a cloth napkin":
-				if (array.length > 0) {
+				if (isArray) {
 					const el = document.createElement("span");
-					if (array.length === 1) {
-						App.Events.addNode(el, [`a cloth napkin skillfully folded into the shape of`, array[0].napkinShape, `given to you by`, slaveSentence(array)]);
+					if (value.length === 1) {
+						App.Events.addNode(el, [`A cloth napkin skillfully folded into the shape of`, value[0].napkinShape, `given to you by`, slaveSentence(value)]);
 					} else {
 						const r = [];
-						// Napkins are weird; we need to sort by two properties: napkinShape and the slave. First, set up a map of the types of napkins, and attach the appropriate slaves to them by array:
+						// Napkins are weird; we need to sort by two properties: napkinShape and the slave. First, set up a map of the types of napkins, and attach the appropriate slaves to them by value:
 						const napkinMap = new Map([]);
-						for (const slave of array) {
+						for (const slave of value) {
 							if (!napkinMap.get(slave.napkinShape)) {
 								napkinMap.set(slave.napkinShape, []);
 							}
 							napkinMap.get(slave.napkinShape).push(slave);
 						}
-						r.push(`cloth napkins skillfully folded into ${napkinMap.size === 1 ? "a single shape" : "various shapes"} by your slaves.`);
+						r.push(`Cloth napkins skillfully folded into ${napkinMap.size === 1 ? "a single shape" : "various shapes"} by your slaves.`);
 						// Make a fragment for each napkin type that we have, including the slaves that made that type
 						for (const [shape, slaves] of napkinMap) {
 							r.push(App.UI.DOM.combineNodes(slaveSentence(slaves), ` ${slaves.length === 1 ? "" : "each "}made ${shape}.`,));
@@ -658,9 +653,13 @@ App.Desc.officeDescription = function(lastElement) {
 					return null;
 				}
 			case "a poster for the movie that was made about the love between one of your mercenaries and": {
-				const el = document.createElement("span");
-				el.append("a poster for the movie that was made about the love between one of your mercenaries and ", slaveSentence(array), ".");
-				return el;
+				if (isArray) {
+					const el = document.createElement("span");
+					el.append("A poster for the movie that was made about the love between one of your mercenaries and ", slaveSentence(value), ".");
+					return el;
+				} else {
+					return null;
+				}
 			}
 			// should never have plurals
 			case "a collection of diplomas from expensive schools":
@@ -678,10 +677,10 @@ App.Desc.officeDescription = function(lastElement) {
 			case "a Daughters of Liberty flag that once hung in their forward command post within your arcology":
 			case "a Daughters of Liberty brassard":
 			case "a shot-torn flag of the failed nation whose militants attacked the Free City":
-				return App.UI.DOM.makeElement("span", desc);
+				return App.UI.DOM.makeElement("span", capFirstChar(desc));
 			// manual replacement
 			case "a thank-you note from a MILF tourist whom you made feel welcome in the arcology":
-				return App.UI.DOM.makeElement("span", "several thank-you notes from MILF tourists whom you made feel welcome in the arcology");
+				return App.UI.DOM.makeElement("span", "Several thank-you notes from MILF tourists whom you made feel welcome in the arcology");
 			// replacement by groups
 			default:
 				if (desc.endsWith("citizen")) { // will not reduce spam from different future societies
@@ -697,7 +696,7 @@ App.Desc.officeDescription = function(lastElement) {
 					desc = desc.replace("a ", "several ");
 					desc = desc.replace("owner", "owners");
 				}
-				return App.UI.DOM.makeElement("span", desc);
+				return App.UI.DOM.makeElement("span", capFirstChar(desc));
 		}
 
 		/**
diff --git a/src/endWeek/economics/arcmgmt.js b/src/endWeek/economics/arcmgmt.js
index 614cfe607c7cbec917e0238a641e90ce7a3b9a48..f4f45acfdd01a165e7c2675f9c8bec08ffe1a91c 100644
--- a/src/endWeek/economics/arcmgmt.js
+++ b/src/endWeek/economics/arcmgmt.js
@@ -1868,7 +1868,7 @@ App.EndWeek.arcManagement = function() {
 		V.lowerClass -= deathsLC;
 		V.middleClass -= deathsMC;
 		V.upperClass -= deathsUC;
-		V.lowerClass -= deathsTC;
+		V.topClass -= deathsTC;
 		if (deathsLC > 0) {
 			z.push(numberWithPluralOne(deathsLC, "lower class citizen"));
 		}
@@ -1882,7 +1882,7 @@ App.EndWeek.arcManagement = function() {
 			z.push(numberWithPluralOne(deathsTC, "millionaire"));
 		}
 		if (deathsLC > 0 || deathsMC > 0 || deathsUC > 0 || deathsTC > 0) {
-			r.push(App.UI.DOM.makeElement("span", `${capFirstChar(toSentence(z))} passed away due to natural causes.`, "red"));
+			r.push(App.UI.DOM.makeElement("span", `${capFirstChar(toSentence(z))} passed away due to natural causes.`, ["red"]));
 		}
 
 		/* Slave expiration*/
@@ -1926,16 +1926,16 @@ App.EndWeek.arcManagement = function() {
 				}
 			});
 		if (count > 9) {
-			r.push(App.UI.DOM.makeElement("span", `A great amount of lower class citizens`, "green"));
+			r.push(App.UI.DOM.makeElement("span", `A great amount of lower class citizens`, ["green"]));
 			r.push(`were attracted by the sectors filled with dense apartments.`);
 		} else if (count > 5) {
-			r.push(App.UI.DOM.makeElement("span", `A large amount of lower class citizens`, "green"));
+			r.push(App.UI.DOM.makeElement("span", `A large amount of lower class citizens`, ["green"]));
 			r.push(`were attracted by your sprawling blocks of dense apartments.`);
 		} else if (count > 2) {
-			r.push(App.UI.DOM.makeElement("span", `A moderate amount of lower class citizens`, "green"));
+			r.push(App.UI.DOM.makeElement("span", `A moderate amount of lower class citizens`, ["green"]));
 			r.push(`were attracted by your dense apartment complexes`);
 		} else if (count > 0) {
-			r.push(App.UI.DOM.makeElement("span", `A small amount of lower class citizens`, "green"));
+			r.push(App.UI.DOM.makeElement("span", `A small amount of lower class citizens`, ["green"]));
 			r.push(`were attracted by your dense apartments.`);
 		}
 		return r;
diff --git a/src/endWeek/economics/neighborsDevelopment.js b/src/endWeek/economics/neighborsDevelopment.js
index aaeba25ae78a5f87aee8192af8c492b50394af6f..e0458fd2560feebb1fd425b505d51fc49bf6792c 100644
--- a/src/endWeek/economics/neighborsDevelopment.js
+++ b/src/endWeek/economics/neighborsDevelopment.js
@@ -1435,10 +1435,8 @@ App.EndWeek.neighborsDevelopment = function() {
 					let attacking = [];
 					const dipFSes = FutureSocieties.diplomaticFSes(arc, arc2);
 					for (const sharedFS of dipFSes.shared) {
-						if (arc2[sharedFS] > 60) {
-							if (sharedFS === "FSNull") {
-								continue; // Multiculturalism is not affected by influence.
-							}
+						// Multiculturalism is not affected by influence.
+						if (sharedFS !== "FSNull" && arc2[sharedFS] > 60) {
 							arc[sharedFS] += Math.trunc((arc2[sharedFS] - 60) / 4) + appliedInfluenceBonus;
 							if (arc[sharedFS] > V.FSLockinLevel) {
 								alignment += 1;
@@ -1453,10 +1451,8 @@ App.EndWeek.neighborsDevelopment = function() {
 						}
 					}
 					for (const [arcFS, arc2FS] of dipFSes.conflicting) {
-						if (arc2[arc2FS] > 60) {
-							if (arcFS === "FSNull") {
-								continue; // Multiculturalism is not affected by influence.
-							}
+						// Multiculturalism is not affected by influence.
+						if (arcFS !== "FSNull" && arc2[arc2FS] > 60) {
 							arc[arcFS] -= Math.trunc((arc2[arc2FS] - 60) / 4) + appliedInfluenceBonus;
 							if (arcFS === "FSSubjugationist" && arc2FS === "FSSupremacist") {
 								attacking.push("opposing Subjugationism");
@@ -1969,614 +1965,628 @@ App.EndWeek.neighborsDevelopment = function() {
 			if (arc.government === "your agent") {
 				const leader = App.currentAgent(i);
 				const {he, his, himself, woman, him, hers} = getPronouns(leader);
+				/** @type {Array<{fs: FC.FutureSociety, msg: string}>} */
+				const candidates = [];
 
-				if (validFSes.includes("FSRepopulationFocus") && leader.fetish === "pregnancy" && V.seePreg === 1) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Repopulationism,</span> since as a pregnancy fetishist, ${he} can't wait to see the female population's bellies swell with life.`);
-					arc.FSRepopulationFocus = 5;
-					return;
-				} else if (validFSes.includes("FSRestart") && (leader.preg < -1 || (leader.ovaries === 0 && leader.mpreg !== 1)) && leader.genes === "XX") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Eugenics,</span> since if no-one can get pregnant, ${he} won't be alone.`);
-					arc.FSRestart = 5;
-					return;
-				}
-				if (validFSes.includes("FSGenderRadicalist") && leader.dick > 0) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Gender Radicalism,</span> since ${he}'s a walking, swinging argument for dickgirls.`);
-					arc.FSGenderRadicalist = 5;
-					return;
-				} else if (validFSes.includes("FSGenderFundamentalist") && (leader.pregKnown === 1 || leader.bellyPreg > 1500)) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Gender Fundamentalism,</span> since its citizens find leadership by a pregnant ${woman} fascinating.`);
-					arc.FSGenderFundamentalist = 5;
-					return;
-				}
-				if (validFSes.includes("FSPaternalist") && leader.behavioralQuirk === "advocate") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Paternalism,</span> since as an advocate for slavery, ${he} believes in its benefits.`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if (validFSes.includes("FSDegradationist") && leader.fetish === "sadist") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Degradationism,</span> since as a sexual sadist, ${he}'s excited by the idea of leading a society that applauds ${his} cruelest impulses.`);
-					arc.FSDegradationist = 5;
-					return;
+				if (leader.fetish === "pregnancy" && V.seePreg === 1) {
+					candidates.push({fs: "FSRepopulationFocus", msg: `since as a pregnancy fetishist, ${he} can't wait to see the female population's bellies swell with life.`});
 				}
-				if (validFSes.includes("FSSlaveProfessionalism") && (leader.intelligence + leader.intelligenceImplant >= 120) && (leader.skill.vaginal + leader.skill.oral + leader.skill.anal + leader.skill.whoring + leader.skill.entertainment >= 400)) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Slave Professionalism,</span> since ${he} wishes to produce slaves you can be proud of.`);
-					arc.FSSlaveProfessionalism = 5;
-					return;
-				} else if (validFSes.includes("FSIntellectualDependency") && (leader.intelligence + leader.intelligenceImplant >= 120) && (leader.behavioralFlaw === "arrogant" || leader.behavioralQuirk === "insecure")) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Intellectual Dependency,</span>`);
-					if (leader.behavioralQuirk === "insecure") {
-						r.push(`since, due to ${his} own insecurities, needs to be frequently reassured that ${he} is smarter than the masses.`);
-					} else {
-						r.push(`since ${he} absolutely needs to feel intellectually superior to ${his} chattel.`);
-					}
-					arc.FSIntellectualDependency = 5;
-					return;
+				if ((leader.preg < -1 || (leader.ovaries === 0 && leader.mpreg !== 1)) && leader.genes === "XX") {
+					candidates.push({fs: "FSRestart", msg: `since if no-one can get pregnant, ${he} won't be alone.`});
 				}
-				if (validFSes.includes("FSBodyPurist") && leader.chem > 50) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Body Purism,</span> since ${he} knows what long term drug damage feels like, and doesn't want any slave to ever experience it again.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSTransformationFetishist") && leader.boobsImplant > 1000) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Transformation Fetishism,</span> out of a perverse desire to subject all slaves to massive implants like ${hers}.`);
-					arc.FSTransformationFetishist = 5;
-					return;
+				if (leader.dick > 0) {
+					candidates.push({fs: "FSGenderRadicalist", msg: `since ${he}'s a walking, swinging argument for dickgirls.`});
 				}
-				if (validFSes.includes("FSYouthPreferentialist") && leader.actualAge <= 25) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Youth Preferentialism,</span> to buttress acceptance of ${his} own young age.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSMaturityPreferentialist") && leader.actualAge > 35) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Maturity Preferentialism,</span> since ${he} has a certain personal interest in promoting the idea that MILFs are sexy.`);
-					arc.FSMaturityPreferentialist = 5;
-					return;
+				if (leader.pregKnown === 1 || leader.bellyPreg > 1500) {
+					candidates.push({fs: "FSGenderFundamentalist", msg: `since its citizens find leadership by a pregnant ${woman} fascinating.`});
 				}
-				if (validFSes.includes("FSSlimnessEnthusiast") && leader.behavioralQuirk === "insecure") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Slimness Enthusiasm,</span> since ${his} history of anorexia has deeply impacted ${his} idea of beauty.`);
-					arc.FSSlimnessEnthusiast = 5;
-					return;
-				} else if (validFSes.includes("FSAssetExpansionist") && leader.fetish === "boobs") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Asset Expansionism,</span> since ${he}'s a breast expansion fetishist in addition to being a mere breast fetishist.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSAssetExpansionist") && leader.sexualQuirk === "size queen" && leader.vagina > 3) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Asset Expansionism,</span> since ${he}'s a stickler for big dicks and seeks to find one large enough to push ${him} to ${his} very limit.`);
-					arc.FSAssetExpansionist = 5;
-					return;
+				if (leader.behavioralQuirk === "advocate") {
+					candidates.push({fs: "FSPaternalist", msg: `since as an advocate for slavery, ${he} believes in its benefits.`});
 				}
-				if (validFSes.includes("FSCummunism") && leader.fetish === "cumslut") { // this will become the cum focused condition, being replaced with breast focus for milk
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Cummunism,</span> since ${he} already loves sucking down huge loads of cum.`);
-					arc.FSCummunism = 5;
-					return;
-				} else if (validFSes.includes("FSPastoralist") && leader.fetish === "boobs") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Pastoralism,</span> since ${he} loves boobs and adores suckling them.`);
-					arc.FSPastoralist = 5;
-					return;
+				if (leader.fetish === "sadist") {
+					candidates.push({fs: "FSDegradationist", msg: `since as a sexual sadist, ${he}'s excited by the idea of leading a society that applauds ${his} cruelest impulses.`});
 				}
-				if (validFSes.includes("FSHedonisticDecadence") && leader.behavioralFlaw === "gluttonous") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Decadent Hedonism,</span> since ${he} already loves over-eating.`);
-					arc.FSHedonisticDecadence = 5;
-					return;
-				} else if (validFSes.includes("FSPhysicalIdealist") && leader.behavioralQuirk === "fitness") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Physical Idealism,</span> since ${he}'s a fitness fanatic ${himself}.`);
-					arc.FSPhysicalIdealist = 5;
-					return;
-				} else if (validFSes.includes("FSHedonisticDecadence") && leader.fetish !== "none" && leader.fetishStrength >= 100) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Decadent Hedonism,</span> since ${he} seeks to satisfy ${his} powerful fetish.`);
-					arc.FSHedonisticDecadence = 5;
-					return;
-				}
-				if (validFSes.includes("FSStatuesqueGlorification") && leader.height >= 200) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Statuesque Glorification,</span> since ${he} is tired of being one of the tallest in arcology.`);
-					arc.FSStatuesqueGlorification = 5;
-					return;
-				} else if (validFSes.includes("FSPetiteAdmiration") && leader.height >= 170 && leader.fetish === "dom") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Petite Admiration,</span> since it is far easier to dominate someone much smaller than oneself.`);
-					arc.FSPetiteAdmiration = 5;
-					return;
-				}
-				if (validFSes.includes("FSIncestFetishist")) {
-					const lover = V.slaves.find(s => (s.ID === leader.relationshipTarget && areRelated(s, leader) && s.assignment === Job.AGENTPARTNER));
-					if ((leader.behavioralQuirk === "sinful" || leader.sexualQuirk === "perverted") && lover && V.seeIncest === 1) {
-						r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Incest Festishism,</span> to share the love and joy ${he} holds with ${his} ${relativeTerm(leader, lover)}.`);
-						arc.FSIncestFetishist = 5;
-						return;
+				if (leader.intelligence + leader.intelligenceImplant >= 120) {
+					if (leader.skill.vaginal + leader.skill.oral + leader.skill.anal + leader.skill.whoring + leader.skill.entertainment >= 400) {
+						candidates.push({fs: "FSSlaveProfessionalism", msg: `since ${he} wishes to produce slaves you can be proud of.`});
 					}
-				}
-				if (validFSes.includes("FSChattelReligionist") && leader.behavioralFlaw === "devout") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Chattel Religionism,</span> to share and spread ${his} deeply held beliefs about the holiness of sexual service.`);
-					arc.FSChattelReligionist = 5;
-					return;
-				} else if (validFSes.includes("FSChattelReligionist") && leader.behavioralQuirk === "sinful") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Chattel Religionism,</span> since ${he}'s excited by the prospect of getting away with horrible sins against old religions in public.`);
-					arc.FSChattelReligionist = 5;
-					return;
-				}
-				if (validFSes.includes("FSEgyptianRevivalist") && leader.relationshipTarget !== 0) {
-					const lover = getSlave(leader.relationshipTarget);
-					if (lover && areRelated(leader, lover)) {
-						r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Egyptian Revivalism,</span> since ${he}'s already part of a gloriously incestuous relationship.`);
-						arc.FSEgyptianRevivalist = 5;
-						return;
+					if (leader.behavioralFlaw === "arrogant") {
+						candidates.push({fs: "FSIntellectualDependency", msg: `since, due to ${his} own insecurities, needs to be frequently reassured that ${he} is smarter than the masses.`});
 					}
-				} else if (validFSes.includes("FSChineseRevivalist") && leader.nationality === "Chinese") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Chinese Revivalism,</span> since ${he}'s Chinese ${himself} and can claim high honor in such a society.`);
-					arc.FSChineseRevivalist = 5;
-					return;
-				} else if (validFSes.includes("FSEdoRevivalist") && leader.nationality === "Japanese") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Edo Revivalism,</span> since ${he}'s Japanese ${himself} and can claim high honor in such a society.`);
-					arc.FSEdoRevivalist = 5;
-					return;
-				} else if (validFSes.includes("FSAztecRevivalist") && leader.nationality === "Mexican") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Aztec Revivalism,</span> since ${he}'s Mexican ${himself} and can claim high honor in such a society.`);
-					arc.FSAztecRevivalist = 5;
-					return;
-				} else if (validFSes.includes("FSNeoImperialist") && ["German", "French", "Spanish", "English"].includes(leader.nationality)) {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Neo-Imperialism,</span> since ${he}'s ${leader.nationality} ${himself} and can easily cement ${his} rule with Imperial directives in your name.`);
-					arc.FSNeoImperialist = 5;
-					return;
-				} else if (validFSes.includes("FSRomanRevivalist") && leader.behavioralQuirk === "confident") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Roman Revivalism,</span> since it appeals to ${his} confident, patrician nature.`);
-					arc.FSRomanRevivalist = 5;
-					return;
-				} else if (validFSes.includes("FSArabianRevivalist") && leader.fetish === "dom") {
-					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Arabian Revivalism,</span> since ${he}'s sexually dominant and quite likes the idea of overseeing slave bazaars.`);
-					arc.FSArabianRevivalist = 5;
-					return;
-				}
-			}
-
-			/* CROSS-FS ADOPTION*/
-			if (arc.FSSubjugationist > random(50, 200)) {
-				if (validFSes.includes("FSDegradationist")) {
-					r.push(`The arcology's racial Subjugationist culture <span class="yellow">pushes it towards Degradationism.</span>`);
-					arc.FSDegradationist = 5;
-					return;
-				} else if ((validFSes.includes("FSAztecRevivalist") && validFSes.includes("FSEgyptianRevivalist"))) {
-					if (random(0, 1) === 0) {
-						r.push(`The arcology's racial Subjugationist culture <span class="yellow">pushes it towards Egyptian Revivalism,</span> since the Ancient Egyptians are famous for keeping a race of slaves.`);
-						arc.FSEgyptianRevivalist = 5;
-						return;
-					} else {
-						r.push(`The arcology's racial Supremacist culture <span class="yellow">pushes it towards Aztec Revivalism,</span> since the enslavement and sacrifice of slaves was fundamental to the culture.`);
-						arc.FSAztecRevivalist = 5;
-						return;
+					if (leader.behavioralQuirk === "insecure") {
+						candidates.push({fs: "FSIntellectualDependency", msg: `since ${he} absolutely needs to feel intellectually superior to ${his} chattel.`});
 					}
 				}
-			}
-			if (arc.FSRestart > random(50, 200)) {
-				if (validFSes.includes("FSNeoImperialist")) {
-					r.push(`The arcology's elitist, eugenicist culture <span class="yellow">pushes it towards Neo-Imperialism,</span> since the societal elite view themselves as the only appropriate rulers of their society.`);
-					arc.FSNeoImperialist = 5;
-					return;
+				if (leader.chem > 50) {
+					candidates.push({fs: "FSBodyPurist", msg: `since ${he} knows what long term drug damage feels like, and doesn't want any slave to ever experience it again.`});
 				}
-			}
-			if (arc.FSSupremacist > random(50, 200)) {
-				if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's racial Supremacist culture <span class="yellow">pushes it towards Paternalism.</span>`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if ((validFSes.includes("FSEdoRevivalist") && validFSes.includes("FSChineseRevivalist") && (arc.FSSupremacistRace === "asian"))) {
-					if (random(0, 1) === 0) {
-						r.push(`The arcology's racial Supremacist culture <span class="yellow">pushes it towards Edo Revivalism,</span> since the beauty and grace of the Japanese people are watchwords there.`);
-						arc.FSEdoRevivalist = 5;
-						return;
-					} else {
-						r.push(`The arcology's racial Supremacist culture <span class="yellow">pushes it towards Chinese Revivalism,</span> since the wisdom of the Middle Kingdom is admired there.`);
-						arc.FSChineseRevivalist = 5;
-						return;
-					}
+				if (leader.boobsImplant > 1000) {
+					candidates.push({fs: "FSTransformationFetishist", msg: `out of a perverse desire to subject all slaves to massive implants like ${hers}.`});
 				}
-			}
-			if (arc.FSRepopulationFocus > random(50, 200)) {
-				if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Repopulationist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since big pregnant bellies go great with huge tits and asses.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSGenderFundamentalist")) {
-					r.push(`The arcology's Repopulationist culture <span class="yellow">pushes it towards Gender Fundamentalism,</span> since traditional women make better mothers.`);
-					arc.FSGenderFundamentalist = 5;
-					return;
-				} else if (validFSes.includes("FSPetiteAdmiration")) {
-					r.push(`The arcology's Repopulationist culture <span class="yellow">pushes it towards Petite Admiration,</span> since shorter women tend to have an easier time with childbirth.`);
-					arc.FSPetiteAdmiration = 5;
-					return;
+				if (leader.actualAge <= 25) {
+					candidates.push({fs: "FSYouthPreferentialist", msg: `to buttress acceptance of ${his} own young age.`});
+				} 
+				if (leader.actualAge > 35) {
+					candidates.push({fs: "FSMaturityPreferentialist", msg: `since ${he} has a certain personal interest in promoting the idea that MILFs are sexy.`});
 				}
-			} else if (arc.FSRestart > random(50, 200)) {
-				if (validFSes.includes("FSDegradationist")) {
-					r.push(`The arcology's elite focused culture <span class="yellow">pushes it towards Degradationism,</span> since its lowest class deserves nothing but misery.`);
-					arc.FSDegradationist = 5;
-					return;
-				} else if (validFSes.includes("FSSlaveProfessionalism")) {
-					r.push(`The arcology's elite focused culture <span class="yellow">pushes it towards Slave Professionalism,</span> since the highest class deserve nothing less than the best slaves.`);
-					arc.FSSlaveProfessionalism = 5;
-					return;
-				} else if (validFSes.includes("FSHedonisticDecadence")) {
-					r.push(`The arcology's wide range of imports <span class="yellow">pushes it towards Decadent Hedonism,</span> since it has access to so many undiscovered pleasures.`);
-					arc.FSHedonisticDecadence = 5;
-					return;
+				if (leader.behavioralQuirk === "insecure" || leader.behavioralFlaw === "anorexic") {
+					candidates.push({fs: "FSSlimnessEnthusiast", msg: `since ${his} history of anorexia has deeply impacted ${his} idea of beauty.`});
 				}
-			}
-			if (arc.FSGenderRadicalist > random(50, 200)) {
-				if (validFSes.includes("FSTransformationFetishist")) {
-					r.push(`The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Transformation Fetishism,</span> since surgery can turn a slave into anything.`);
-					arc.FSTransformationFetishist = 5;
-					return;
-				} else if (validFSes.includes("FSSlimnessEnthusiast")) {
-					r.push(`The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since that's the kind of body many of its slaves have.`);
-					arc.FSSlimnessEnthusiast = 5;
-					return;
-				} else if (validFSes.includes("FSCummunism")) {
-					r.push(`The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Cummunism,</span> since many of its slaves are capable of giving cum.`);
-					arc.FSCummunism = 5;
-					return;
+				if (leader.fetish === "boobs") {
+					candidates.push({fs: "FSAssetExpansionist", msg: `since ${he}'s a breast expansion fetishist in addition to being a mere breast fetishist.`});
 				}
-			} else if (arc.FSGenderFundamentalist > random(50, 200)) {
-				if (validFSes.includes("FSPastoralist")) {
-					r.push(`The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Pastoralism,</span> since its pregnant slaves are already giving milk.`);
-					arc.FSPastoralist = 5;
-					return;
-				} else if (validFSes.includes("FSIntellectualDependency")) {
-					r.push(`The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Intellectual Dependency,</span> since women don't need to think to serve men.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSYouthPreferentialist")) {
-					r.push(`The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since younger slaves are beautiful and fertile.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
+				if (leader.sexualQuirk === "size queen" && leader.vagina > 3) {
+					candidates.push({fs: "FSAssetExpansionist", msg: `since ${he}'s a stickler for big dicks and seeks to find one large enough to push ${him} to ${his} very limit.`});
 				}
-			}
-			if (arc.FSPaternalist > random(50, 200)) {
-				if (validFSes.includes("FSChattelReligionist")) {
-					r.push(`The arcology's Paternalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since many of its slaves are already worshipful.`);
-					arc.FSChattelReligionist = 5;
-					return;
-				} else if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Paternalist culture <span class="yellow">pushes it towards Body Purism,</span> since giving slaves dangerous drugs is hardly good for them.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSRomanRevivalist")) {
-					r.push(`The arcology's Paternalist culture <span class="yellow">pushes it towards Roman Revivalism,</span> since loyal service to the res publica bears similarity to their existing mores.`);
-					arc.FSRomanRevivalist = 5;
-					return;
+				if (leader.fetish === "cumslut") {
+					candidates.push({fs: "FSCummunism", msg: `since ${he} already loves sucking down huge loads of cum.`});
 				}
-			} else if (arc.FSDegradationist > random(50, 200)) {
-				if (validFSes.includes("FSTransformationFetishist")) {
-					r.push(`The arcology's Degradationist culture <span class="yellow">pushes it towards Transformation Fetishism,</span> the ultimate expression of power over slave bodies.`);
-					arc.FSTransformationFetishist = 5;
-					return;
-				} else if (validFSes.includes("FSGenderRadicalist")) {
-					r.push(`The arcology's Degradationist culture <span class="yellow">pushes it towards Gender Radicalism,</span> since the joy of forcing a gender role on a slave is already popular.`);
-					arc.FSGenderRadicalist = 5;
-					return;
+				if (leader.fetish === "boobs") {
+					candidates.push({fs: "FSPastoralist", msg: `since ${he} loves boobs and adores suckling them.`});
 				}
-			}
-			if (arc.FSIntellectualDependency > random(50, 200)) {
-				if (validFSes.includes("FSTransformationFetishist")) {
-					r.push(`The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Transformation Fetishism,</span> to give its bimbos a body most fitting.`);
-					arc.FSTransformationFetishist = 5;
-					return;
-				} else if (validFSes.includes("FSYouthPreferentialist")) {
-					r.push(`The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since the young have more energy to party.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSHedonisticDecadence")) {
-					r.push(`The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Decadent Hedonism,</span> since base instinct already rules slaves' lives.`);
-					arc.FSHedonisticDecadence = 5;
-					return;
-				} else if (validFSes.includes("FSRepopulationFocus")) {
-					r.push(`The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Repopulationism,</span> since there has been an epidemic of unplanned pregnancies among the slave population.`);
-					arc.FSRepopulationFocus = 5;
-					return;
+				if (leader.behavioralQuirk === "fitness") {
+					candidates.push({fs: "FSPhysicalIdealist", msg: `since ${he}'s a fitness fanatic ${himself}.`});
 				}
-			} else if (arc.FSSlaveProfessionalism > random(50, 200)) {
-				if (validFSes.includes("FSMaturityPreferentialist")) {
-					r.push(`The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Maturity Preferentialist,</span> since with age comes experience.`);
-					arc.FSMaturityPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Paternalism,</span> since happy slaves are much more willing to be molded in to shape.`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if (validFSes.includes("FSPhysicalIdealist")) {
-					r.push(`The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Physical Idealism,</span> since a fitting body is required to house the perfect mind.`);
-					arc.FSPhysicalIdealist = 5;
-					return;
-				} else if (validFSes.includes("FSChattelReligionist")) {
-					r.push(`The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Chattel Religionism,</span> since skilled service is already a part of a slave's daily life.`);
-					arc.FSChattelReligionist = 5;
-					return;
-				}
-			}
-			if (arc.FSBodyPurist > random(50, 200)) {
-				if (validFSes.includes("FSPhysicalIdealist")) {
-					r.push(`The arcology's Body Purist culture <span class="yellow">pushes it towards Physical Idealism,</span> since it already takes an intense interest in bodily perfection.`);
-					arc.FSPhysicalIdealist = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Body Purist culture <span class="yellow">pushes it towards Paternalism,</span> since it's become obvious that happiness is a necessary part of wellness.`);
-					arc.FSPaternalist = 5;
-					return;
+				if (leader.behavioralFlaw === "gluttonous") {
+					candidates.push({fs: "FSHedonisticDecadence", msg: `since ${he} already loves over-eating.`});
 				}
-			} else if (arc.FSTransformationFetishist > random(50, 200)) {
-				if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Transformation Fetishist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since it's already overrun with massive tits and asses.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSDegradationist")) {
-					r.push(`The arcology's Transformation Fetishist culture <span class="yellow">pushes it towards Degradationism,</span> since it's already used to slaves whining about their latest surgeries.`);
-					arc.FSDegradationist = 5;
-					return;
+				if (leader.fetish !== "none" && leader.fetishStrength >= 100) {
+					candidates.push({fs: "FSHedonisticDecadence", msg: `since ${he} seeks to satisfy ${his} powerful fetish.`});
 				}
-			}
-			if (arc.FSYouthPreferentialist > random(50, 200)) {
-				if (validFSes.includes("FSSlimnessEnthusiast")) {
-					r.push(`The arcology's Youth Preferentialist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since that's the kind of body many of its slaves have.`);
-					arc.FSSlimnessEnthusiast = 5;
-					return;
-				} else if (validFSes.includes("FSRepopulationFocus")) {
-					r.push(`The arcology's Youth Preferentialist culture <span class="yellow">pushes it towards Repopulationism,</span> since many of its slaves are deliciously ripe for breeding.`);
-					arc.FSRepopulationFocus = 5;
-					return;
+				if (leader.height >= 200) {
+					candidates.push({fs: "FSStatuesqueGlorification", msg: `since ${he} is tired of being one of the tallest in arcology.`});
 				}
-			} else if (arc.FSMaturityPreferentialist > random(50, 200)) {
-				if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Maturity Preferentialist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since that's the kind of body many of its slaves have.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Maturity Preferentialist culture <span class="yellow">pushes it towards Paternalism,</span> since its many older slaves have skills best applied by a happy woman.`);
-					arc.FSPaternalist = 5;
-					return;
+				if (leader.height >= 170 && leader.fetish === "dom") {
+					candidates.push({fs: "FSPetiteAdmiration", msg: `since it is far easier to dominate someone much smaller than oneself.`});
 				}
-			}
-			if (arc.FSPetiteAdmiration > random(50, 200)) {
-				if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Petite Admiration culture <span class="yellow">pushes it towards Asset Expansionist,</span> since a ${girlU} with tits wider than ${heU} is tall attracts quite some attention.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Petite Admiration culture <span class="yellow">pushes it towards Paternalism,</span> since such tiny ${girlU}s need extra special attention.`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if (validFSes.includes("FSIncestFetishist")) {
-					r.push(`The arcology's Petite Admiration culture <span class="yellow">pushes it towards Incest Fetishism,</span> since age play often goes hand-in-hand with size play.`);
-					arc.FSIncestFetishist = 5;
-					return;
-				}
-			} else if (arc.FSStatuesqueGlorification > random(50, 200)) {
-				if (validFSes.includes("FSPhysicalIdealist")) {
-					r.push(`The arcology's Statuesque Glorification culture <span class="yellow">pushes it towards Physical Idealism,</span> since being ripped complements being tall.`);
-					arc.FSPhysicalIdealist = 5;
-					return;
-				} else if (validFSes.includes("FSDegradationist")) {
-					r.push(`The arcology's Statuesque Glorification culture <span class="yellow">pushes it towards Degradationism,</span> since those that don't measure up deserve only suffering.`);
-					arc.FSDegradationist = 5;
-					return;
-				}
-			}
-			if (arc.FSSlimnessEnthusiast > random(50, 200)) {
-				if (validFSes.includes("FSYouthPreferentialist")) {
-					r.push(`The arcology's Slimness Enthusiast culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since younger slaves are often attractively slim.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Slimness Enthusiast culture <span class="yellow">pushes it towards Body Purism,</span> since the last thing they want is prettily slender girls with health trouble.`);
-					arc.FSBodyPurist = 5;
-					return;
+				if (leader.height < 160 && leader.fetish !== "submissive") {
+					candidates.push({fs: "FSPetiteAdmiration", msg: `since ${he} doesn't like ${his} subordinates towering over ${him}.`});
 				}
-			} else if (arc.FSAssetExpansionist > random(50, 200)) {
-				if (validFSes.includes("FSMaturityPreferentialist")) {
-					r.push(`The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Maturity Preferentialism,</span> since MILF slaves tend to come with nice big tits.`);
-					arc.FSMaturityPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Body Purism,</span> since slaves on curatives are slaves not on growth hormones.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSPetiteAdmiration") && validFSes.includes("FSStatuesqueGlorification")) {
-					if (random(0, 1) === 1) {
-						r.push(`The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Petite Admiration,</span> since the smaller a slave's body is, the bigger their breasts will look.`);
-						arc.FSPetiteAdmiration = 5;
-						return;
-					} else {
-						r.push(`The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Statuesque Glorification,</span> as the love of all things huge is rather indiscriminate.`);
-						arc.FSStatuesqueGlorification = 5;
-						return;
+				const lover = getSlave(leader.relationshipTarget);
+				if (lover && areRelated(leader, lover) && V.seeIncest === 1) {
+					if ((leader.behavioralQuirk === "sinful" || leader.sexualQuirk === "perverted")) {
+						candidates.push({fs: "FSIncestFetishist", msg: `to share the love and joy ${he} holds with ${his} ${relativeTerm(leader, lover)}.`});
+					}
+					if (lover.assignment === Job.AGENTPARTNER && leader.relationship > 3) {
+						candidates.push({fs: "FSEgyptianRevivalist", msg: `since ${he}'s already part of a gloriously incestuous relationship.`});
 					}
 				}
-			}
-			if (arc.FSPastoralist > random(50, 200)) {
-				if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Pastoralist culture <span class="yellow">pushes it towards Body Purism,</span> since there have been concerns about milk purity.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Pastoralist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since they're convinced that there's no such thing as udders that are too big.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSRepopulationFocus")) {
-					r.push(`The arcology's Pastoralist culture <span class="yellow">pushes it towards Repopulationism,</span> since pregnancy stimulates milk flow.`);
-					arc.FSRepopulationFocus = 5;
-					return;
-				}
-			} else if (arc.FSCummunism > random(50, 200)) {
-				if (validFSes.includes("FSPhysicalIdealist")) {
-					r.push(`The arcology's Cummunist culture <span class="yellow">pushes it towards Physical Idealism,</span> since big balls and huge loads go hand in hand with masculine muscles.`);
-					arc.FSPhysicalIdealist = 5;
-					return;
-				} else if (validFSes.includes("FSAssetExpansionist")) {
-					r.push(`The arcology's Cummunist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since they're convinced that there's no such thing as balls that are too big.`);
-					arc.FSAssetExpansionist = 5;
-					return;
-				} else if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Cummunist culture <span class="yellow">pushes it towards Body Purism,</span> since there have been concerns about cum purity.`);
-					arc.FSBodyPurist = 5;
-					return;
-				}
-			}
-			if (arc.FSHedonisticDecadence > random(50, 200)) {
-				if (validFSes.includes("FSPastoralist")) {
-					r.push(`The arcology's Hedonistic culture <span class="yellow">pushes it towards Pastoralism,</span> since nothing beats a nice glass of fresh squeezed milk with your cake.`);
-					arc.FSPastoralist = 5;
-					return;
-				} else if (validFSes.includes("FSIntellectualDependency")) {
-					r.push(`The arcology's Hedonistic culture <span class="yellow">pushes it towards Intellectual Dependency,</span> since higher thought is unneeded when you have everything you want.`);
-					arc.FSIntellectualDependency = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Hedonistic culture <span class="yellow">pushes it towards Paternalism,</span> since happiness is infectious.`);
-					arc.FSPaternalist = 5;
-					return;
-				}
-			} else if (arc.FSPhysicalIdealist > random(50, 200)) {
-				if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Physical Idealist culture <span class="yellow">pushes it towards Body Purism,</span> since it's already used to treating slaves' bodies as temples.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSYouthPreferentialist")) {
-					r.push(`The arcology's Physical Idealist culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since beauty and athletic prowess do tend to peak early.`);
-					arc.FSYouthPreferentialist = 5;
-					return;
-				} else if (validFSes.includes("FSStatuesqueGlorification")) {
-					r.push(`The arcology's Physical Idealist culture <span class="yellow">pushes it towards Statuesque Glorification,</span> to better emulate the titans of legend.`);
-					arc.FSStatuesqueGlorification = 5;
-					return;
-				} else if (validFSes.includes("FSCummunism")) {
-					r.push(`The arcology's Physical Idealist culture <span class="yellow">pushes it towards Cummunism,</span> since muscular, testosterone filled slaves make admirable cumshots.`);
-					arc.FSCummunism = 5;
-					return;
-				}
-			}
-			if (arc.FSIncestFetishist > random(50, 200)) {
-				if (validFSes.includes("FSRepopulationFocus")) {
-					r.push(`The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Repopulationism,</span> in order to create many new future loving couples.`);
-					arc.FSRepopulationFocus = 5;
-					return;
-				} else if (validFSes.includes("FSBodyPurist")) {
-					r.push(`The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Body Purism,</span> in order to keep its bloodlines pure.`);
-					arc.FSBodyPurist = 5;
-					return;
-				} else if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Paternalism,</span> as healthy slaves live longer allowing relationships to span generations.`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if (validFSes.includes("FSEgyptianRevivalist")) {
-					r.push(`The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Egyptian Revivalism,</span> as they naturally seek even more incestuous fun.`);
-					arc.FSEgyptianRevivalist = 5;
-					return;
+				if (leader.behavioralFlaw === "devout") {
+					candidates.push({fs: "FSChattelReligionist", msg: `to share and spread ${his} deeply held beliefs about the holiness of sexual service.`});
 				}
-			}
-			if (arc.FSChattelReligionist > random(50, 200)) {
-				if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Chattel Religionist culture <span class="yellow">pushes it towards Paternalism,</span> since charitable care for slaves' welfare has become widespread.`);
-					arc.FSPaternalist = 5;
-					return;
-				} else if (validFSes.includes("FSArabianRevivalist")) {
-					r.push(`The arcology's Chattel Religionist culture <span class="yellow">pushes it towards Arabian Revivalism,</span> since such an intermingling of slavery and faith fascinates them.`);
-					arc.FSArabianRevivalist = 5;
-					return;
+				if (leader.behavioralQuirk === "sinful") {
+					candidates.push({fs: "FSChattelReligionist", msg: `since ${he}'s excited by the prospect of getting away with horrible sins against old religions in public.`});
 				}
-			}
-			if (arc.FSRomanRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Roman Revivalist culture <span class="yellow">pushes it towards Paternalism,</span> since some Roman slaves were traditionally permitted limited rights.`);
-					arc.FSPaternalist = 5;
-					return;
+				if (leader.nationality === "Chinese") {
+					candidates.push({fs: "FSChineseRevivalist", msg: `since ${he}'s Chinese ${himself} and can claim high honor in such a society.`});
+				} else if (leader.nationality === "Japanese") {
+					candidates.push({fs: "FSEdoRevivalist", msg: `since ${he}'s Japanese ${himself} and can claim high honor in such a society.`});
+				} else if (leader.nationality === "Mexican") {
+					candidates.push({fs: "FSAztecRevivalist", msg: `since ${he}'s Mexican ${himself} and can claim high honor in such a society.`});
+				} else if (leader.nationality === "Egyptian") {
+					candidates.push({fs: "FSEgyptianRevivalist", msg: `since ${he}'s Egyptian ${himself} and wants to relive the glory of the Pharaohs.`});
+				} else if (["German", "French", "Spanish", "English"].includes(leader.nationality)) {
+					candidates.push({fs: "FSNeoImperialist", msg: `since ${he}'s ${leader.nationality} ${himself} and can easily cement ${his} rule with Imperial directives in your name.`});
 				}
-			}
-			if (arc.FSNeoImperialist > random(50, 200)) {
-				if (validFSes.includes("FSRestart")) {
-					r.push(`The arcology's Neo-Imperialist culture <span class="yellow">pushes it towards Eugenics,</span> since their hegemonic, noble culture naturally views itself as genetically superior to the unwashed masses.`);
-					arc.FSRestart = 5;
-					return;
+				if (leader.behavioralQuirk === "confident") {
+					candidates.push({fs: "FSRomanRevivalist", msg: `since it appeals to ${his} confident, patrician nature.`});
 				}
-			}
-			if (arc.FSAztecRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSDegradationist")) {
-					r.push(`The arcology's Aztec Revivalist culture <span class="yellow">pushes it towards Degradation,</span> since most Aztec war slaves were tortured and sacrificed.`);
-					arc.FSDegradationist = 5;
-					return;
+				if (leader.fetish === "dom") {
+					candidates.push({fs: "FSArabianRevivalist", msg: `since ${he}'s sexually dominant and quite likes the idea of overseeing slave bazaars.`});
 				}
-			}
-			if (arc.FSEgyptianRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSChattelReligionist")) {
-					r.push(`The arcology's Egyptian Revivalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since worship is already becoming an established part of its life.`);
-					arc.FSChattelReligionist = 5;
-					return;
-				} else if (validFSes.includes("FSIncestFetishist")) {
-					r.push(`The arcology's Egyptian Revivalist culture <span class="yellow">pushes it towards Incest Fetishism,</span> since more incest is only a good thing in its eyes.`);
-					arc.FSIncestFetishist = 5;
-					return;
-				}
-			}
-			if (arc.FSEdoRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSSlimnessEnthusiast")) {
-					r.push(`The arcology's Edo Revivalist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since slim and elegant slaves are already fashionable there.`);
-					arc.FSSlimnessEnthusiast = 5;
+				const chosen = candidates.filter(c => validFSes.includes(c.fs)).random();
+				if (chosen) {
+					r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt ${FutureSocieties.displayName(chosen.fs)},</span>`, chosen.msg);
+					arc[chosen.fs] = 5;
 					return;
 				}
 			}
-			if (arc.FSArabianRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSChattelReligionist")) {
-					r.push(`The arcology's Arabian Revivalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since the word of God is already a matter of daily significance there.`);
-					arc.FSChattelReligionist = 5;
-					return;
+
+			/* CROSS-FS ADOPTION */
+			/** Map from source to an array of destination FSes.  On the destination side, order matters; adoption is attempted in sequence through the array.
+			 *  If several destination FSes should be equally likely at a particular stage, put them in a nested array.
+			 * @typedef {{fs: FC.FutureSociety, prereqs?: () => boolean, msg: string}} crossFSDest
+			 * @type {Map<FC.FutureSociety, (crossFSDest|crossFSDest[])[]>} */
+			const crossFS = new Map([
+				["FSSubjugationist", [
+					{
+						fs: "FSDegradationist",
+						msg: `The arcology's racial Subjugationist culture <span class="yellow">pushes it towards Degradationism.</span>`,
+					},
+					[ // pick one at random
+						{
+							fs:	"FSAztecRevivalist",
+							msg: `The arcology's racial Supremacist culture <span class="yellow">pushes it towards Aztec Revivalism,</span> since the enslavement and sacrifice of slaves was fundamental to the culture.`
+						},
+						{
+							fs: "FSEgyptianRevivalist",
+							msg: `The arcology's racial Subjugationist culture <span class="yellow">pushes it towards Egyptian Revivalism,</span> since the Ancient Egyptians are famous for keeping a race of slaves.`
+						}
+					]
+				]],
+				["FSSupremacist", [
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's racial Supremacist culture <span class="yellow">pushes it towards Paternalism.</span>`,
+					},
+					[ // pick one at random
+						{
+							fs: "FSEdoRevivalist",
+							prereqs: () => arc.FSSupremacistRace === "asian",
+							msg: `The arcology's racial Supremacist culture <span class="yellow">pushes it towards Edo Revivalism,</span> since the beauty and grace of the Japanese people are watchwords there.`
+						},
+						{
+							fs: "FSChineseRevivalist",
+							prereqs: () => arc.FSSupremacistRace === "asian",
+							msg: `The arcology's racial Supremacist culture <span class="yellow">pushes it towards Chinese Revivalism,</span> since the wisdom of the Middle Kingdom is admired there.`
+						}
+					]
+				]],
+				["FSRepopulationFocus", [
+					{
+						fs: "FSGenderFundamentalist",
+						msg: `The arcology's Repopulationist culture <span class="yellow">pushes it towards Gender Fundamentalism,</span> since traditional women make better mothers.`
+					},
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Repopulationist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since big pregnant bellies go great with huge tits and asses.`
+					},
+					{
+						fs: "FSPetiteAdmiration",
+						msg: `The arcology's Repopulationist culture <span class="yellow">pushes it towards Petite Admiration,</span> since shorter women tend to have an easier time with childbirth.`
+					},
+				]],
+				["FSRestart", [
+					{
+						fs: "FSNeoImperialist",
+						msg: `The arcology's elitist, eugenicist culture <span class="yellow">pushes it towards Neo-Imperialism,</span> since the societal elite view themselves as the only appropriate rulers of their society.`
+					},
+					{
+						fs: "FSDegradationist",
+						msg: `The arcology's elite focused culture <span class="yellow">pushes it towards Degradationism,</span> since its lowest class deserves nothing but misery.`
+					},
+					{
+						fs: "FSSlaveProfessionalism",
+						msg: `The arcology's elite focused culture <span class="yellow">pushes it towards Slave Professionalism,</span> since the highest class deserve nothing less than the best slaves.`
+					},
+					{
+						fs: "FSHedonisticDecadence",
+						msg: `The arcology's wide range of imports <span class="yellow">pushes it towards Decadent Hedonism,</span> since it has access to so many undiscovered pleasures.`
+					},
+				]],
+				["FSGenderRadicalist", [
+					{
+						fs: "FSTransformationFetishist",
+						msg: `The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Transformation Fetishism,</span> since surgery can turn a slave into anything.`
+					},
+					{
+						fs: "FSSlimnessEnthusiast",
+						msg: `The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since that's the kind of body many of its slaves have.`
+					},
+					{
+						fs: "FSCummunism",
+						msg: `The arcology's Gender Radicalist culture <span class="yellow">pushes it towards Cummunism,</span> since many of its slaves are capable of giving cum.`
+					},
+				]],
+				["FSGenderFundamentalist", [
+					{
+						fs: "FSPastoralist",
+						msg: `The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Pastoralism,</span> since its pregnant slaves are already giving milk.`
+					},
+					{
+						fs: "FSIntellectualDependency",
+						msg: `The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Intellectual Dependency,</span> since women don't need to think to serve men.`
+					},
+					{
+						fs: "FSYouthPreferentialist",
+						msg: `The arcology's Gender Fundamentalist culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since younger slaves are beautiful and fertile.`
+					},
+				]],
+				["FSPaternalist", [
+					{
+						fs: "FSChattelReligionist",
+						msg: `The arcology's Paternalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since many of its slaves are already worshipful.`
+					},
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Paternalist culture <span class="yellow">pushes it towards Body Purism,</span> since giving slaves dangerous drugs is hardly good for them.`
+					},
+					{
+						fs: "FSRomanRevivalist",
+						msg: `The arcology's Paternalist culture <span class="yellow">pushes it towards Roman Revivalism,</span> since loyal service to the res publica bears similarity to their existing mores.`
+					},
+				]],
+				["FSDegradationist", [
+					{
+						fs: "FSTransformationFetishist",
+						msg: `The arcology's Degradationist culture <span class="yellow">pushes it towards Transformation Fetishism,</span> the ultimate expression of power over slave bodies.`
+					},
+					{
+						fs: "FSGenderRadicalist",
+						msg: `The arcology's Degradationist culture <span class="yellow">pushes it towards Gender Radicalism,</span> since the joy of forcing a gender role on a slave is already popular.`
+					},
+					{
+						fs: "FSIntellectualDependency",
+						msg: `The arcology's Degradationist culture <span class="yellow">pushes it towards Intellectual Dependency,</span> since there's no need for a sex toy to be thinking.`
+					},
+				]],
+				["FSIntellectualDependency", [
+					{
+						fs: "FSTransformationFetishist",
+						msg: `The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Transformation Fetishism,</span> to give its bimbos a body most fitting.`
+					},
+					{
+						fs: "FSYouthPreferentialist",
+						msg: `The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since the young have more energy to party.`
+					},
+					{
+						fs: "FSHedonisticDecadence",
+						msg: `The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Decadent Hedonism,</span> since base instinct already rules slaves' lives.`
+					},
+					{
+						fs: "FSRepopulationFocus",
+						msg: `The arcology's Intellectual Dependency culture <span class="yellow">pushes it towards Repopulationism,</span> since there has been an epidemic of unplanned pregnancies among the slave population.`
+					},
+				]],
+				["FSSlaveProfessionalism", [
+					{
+						fs: "FSMaturityPreferentialist",
+						msg: `The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Maturity Preferentialist,</span> since with age comes experience.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Paternalism,</span> since happy slaves are much more willing to be molded into shape.`
+					},
+					{
+						fs: "FSPhysicalIdealist",
+						msg: `The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Physical Idealism,</span> since a fitting body is required to house the perfect mind.`
+					},
+					{
+						fs: "FSChattelReligionist",
+						msg: `The arcology's Slave Professionalism culture <span class="yellow">pushes it towards Chattel Religionism,</span> since skilled service is already a part of a slave's daily life.`
+					},
+				]],
+				["FSBodyPurist", [
+					{
+						fs: "FSPhysicalIdealist",
+						msg: `The arcology's Body Purist culture <span class="yellow">pushes it towards Physical Idealism,</span> since it already takes an intense interest in bodily perfection.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Body Purist culture <span class="yellow">pushes it towards Paternalism,</span> since it's become obvious that happiness is a necessary part of wellness.`
+					},
+				]],
+				["FSTransformationFetishist", [
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Transformation Fetishist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since it's already overrun with massive tits and asses.`
+					},
+					{
+						fs: "FSDegradationist",
+						msg: `The arcology's Transformation Fetishist culture <span class="yellow">pushes it towards Degradationism,</span> since it's already used to slaves whining about their latest surgeries.`
+					},
+				]],
+				["FSYouthPreferentialist", [
+					{
+						fs: "FSSlimnessEnthusiast",
+						msg: `The arcology's Youth Preferentialist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since that's the kind of body many of its slaves have.`
+					},
+					{
+						fs: "FSRepopulationFocus",
+						msg: `The arcology's Youth Preferentialist culture <span class="yellow">pushes it towards Repopulationism,</span> since many of its slaves are deliciously ripe for breeding.`
+					},
+				]],
+				["FSMaturityPreferentialist", [
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Maturity Preferentialist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since that's the kind of body many of its slaves have.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Maturity Preferentialist culture <span class="yellow">pushes it towards Paternalism,</span> since its many older slaves have skills best applied by a happy woman.`
+					},
+				]],
+				["FSPetiteAdmiration", [
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Petite Admiration culture <span class="yellow">pushes it towards Asset Expansionist,</span> since a ${girlU} with tits wider than ${heU} is tall attracts quite some attention.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Petite Admiration culture <span class="yellow">pushes it towards Paternalism,</span> since such tiny ${girlU}s need extra special attention.`
+					},
+					{
+						fs: "FSIncestFetishist",
+						msg: `The arcology's Petite Admiration culture <span class="yellow">pushes it towards Incest Fetishism,</span> since age play often goes hand-in-hand with size play.`
+					},
+				]],
+				["FSStatuesqueGlorification", [
+					{
+						fs: "FSPhysicalIdealist",
+						msg: `The arcology's Statuesque Glorification culture <span class="yellow">pushes it towards Physical Idealism,</span> since being ripped complements being tall.`
+					},
+					{
+						fs: "FSDegradationist",
+						msg: `The arcology's Statuesque Glorification culture <span class="yellow">pushes it towards Degradationism,</span> since those that don't measure up deserve only suffering.`
+					},
+				]],
+				["FSSlimnessEnthusiast", [
+					{
+						fs: "FSYouthPreferentialist",
+						msg: `The arcology's Slimness Enthusiast culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since younger slaves are often attractively slim.`
+					},
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Slimness Enthusiast culture <span class="yellow">pushes it towards Body Purism,</span> since the last thing they want is prettily slender girls with health trouble.`
+					},
+				]],
+				["FSAssetExpansionist", [
+					{
+						fs: "FSMaturityPreferentialist",
+						msg: `The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Maturity Preferentialism,</span> since MILF slaves tend to come with nice big tits.`
+					},
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Body Purism,</span> since slaves on curatives are slaves not on growth hormones.`
+					},
+					[ // pick one at random
+						{
+							fs: "FSPetiteAdmiration",
+							msg: `The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Petite Admiration,</span> since the smaller a slave's body is, the bigger their breasts will look.`
+						},
+						{
+							fs: "FSStatuesqueGlorification",
+							msg: `The arcology's Asset Expansionist culture <span class="yellow">pushes it towards Statuesque Glorification,</span> as the love of all things huge is rather indiscriminate.`
+						},
+					]
+				]],
+				["FSPastoralist", [
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Pastoralist culture <span class="yellow">pushes it towards Body Purism,</span> since there have been concerns about milk purity.`
+					},
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Pastoralist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since they're convinced that there's no such thing as udders that are too big.`
+					},
+					{
+						fs: "FSRepopulationFocus",
+						msg: `The arcology's Pastoralist culture <span class="yellow">pushes it towards Repopulationism,</span> since pregnancy stimulates milk flow.`
+					},
+				]],
+				["FSCummunism", [
+					{
+						fs: "FSPhysicalIdealist",
+						msg: `The arcology's Cummunist culture <span class="yellow">pushes it towards Physical Idealism,</span> since big balls and huge loads go hand in hand with masculine muscles.`
+					},
+					{
+						fs: "FSAssetExpansionist",
+						msg: `The arcology's Cummunist culture <span class="yellow">pushes it towards Asset Expansionism,</span> since they're convinced that there's no such thing as balls that are too big.`
+					},
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Cummunist culture <span class="yellow">pushes it towards Body Purism,</span> since there have been concerns about cum purity.`
+					},
+				]],
+				["FSHedonisticDecadence", [
+					{
+						fs: "FSPastoralist",
+						msg: `The arcology's Hedonistic culture <span class="yellow">pushes it towards Pastoralism,</span> since nothing beats a nice glass of fresh squeezed milk with your cake.`
+					},
+					{
+						fs: "FSIntellectualDependency",
+						msg: `The arcology's Hedonistic culture <span class="yellow">pushes it towards Intellectual Dependency,</span> since higher thought is unneeded when you have everything you want.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Hedonistic culture <span class="yellow">pushes it towards Paternalism,</span> since happiness is infectious.`
+					},
+				]],
+				["FSPhysicalIdealist", [
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Physical Idealist culture <span class="yellow">pushes it towards Body Purism,</span> since it's already used to treating slaves' bodies as temples.`
+					},
+					{
+						fs: "FSYouthPreferentialist",
+						msg: `The arcology's Physical Idealist culture <span class="yellow">pushes it towards Youth Preferentialism,</span> since beauty and athletic prowess do tend to peak early.`
+					},
+					{
+						fs: "FSStatuesqueGlorification",
+						msg: `The arcology's Physical Idealist culture <span class="yellow">pushes it towards Statuesque Glorification,</span> to better emulate the titans of legend.`
+					},
+					{
+						fs: "FSCummunism",
+						msg: `The arcology's Physical Idealist culture <span class="yellow">pushes it towards Cummunism,</span> since muscular, testosterone-filled slaves make admirable cumshots.`
+					},
+				]],
+				["FSIncestFetishist", [
+					{
+						fs: "FSRepopulationFocus",
+						msg: `The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Repopulationism,</span> in order to create many new future loving couples.`
+					},
+					{
+						fs: "FSBodyPurist",
+						msg: `The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Body Purism,</span> in order to keep its bloodlines pure.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Paternalism,</span> as healthy slaves live longer allowing relationships to span generations.`
+					},
+					{
+						fs: "FSEgyptianRevivalist",
+						msg: `The arcology's Incest Fetishizing culture <span class="yellow">pushes it towards Egyptian Revivalism,</span> as they naturally seek even more incestuous fun.`
+					},
+				]],
+				["FSChattelReligionist", [
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Chattel Religionist culture <span class="yellow">pushes it towards Paternalism,</span> since charitable care for slaves' welfare has become widespread.`
+					},
+					{
+						fs: "FSArabianRevivalist",
+						msg: `The arcology's Chattel Religionist culture <span class="yellow">pushes it towards Arabian Revivalism,</span> since such an intermingling of slavery and faith fascinates them.`
+					},
+				]],
+				["FSRomanRevivalist", [
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Roman Revivalist culture <span class="yellow">pushes it towards Paternalism,</span> since some Roman slaves were traditionally permitted limited rights.`
+					},
+				]],
+				["FSNeoImperialist", [
+					{
+						fs: "FSRestart",
+						msg: `The arcology's Neo-Imperialist culture <span class="yellow">pushes it towards Eugenics,</span> since their hegemonic, noble culture naturally views itself as genetically superior to the unwashed masses.`
+					},
+				]],
+				["FSAztecRevivalist", [
+					{
+						fs: "FSDegradationist",
+						msg: `The arcology's Aztec Revivalist culture <span class="yellow">pushes it towards Degradation,</span> since most Aztec war slaves were tortured and sacrificed.`
+					},
+				]],
+				["FSEgyptianRevivalist", [
+					{
+						fs: "FSChattelReligionist",
+						msg: `The arcology's Egyptian Revivalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since worship is already becoming an established part of its life.`
+					},
+					{
+						fs: "FSIncestFetishist",
+						msg: `The arcology's Egyptian Revivalist culture <span class="yellow">pushes it towards Incest Fetishism,</span> since more incest is only a good thing in its eyes.`
+					},
+				]],
+				["FSEdoRevivalist", [
+					{
+						fs: "FSSlimnessEnthusiast",
+						msg: `The arcology's Edo Revivalist culture <span class="yellow">pushes it towards Slimness Enthusiasm,</span> since slim and elegant slaves are already fashionable there.`
+					},
+				]],
+				["FSArabianRevivalist", [
+					{
+						fs: "FSChattelReligionist",
+						msg: `The arcology's Arabian Revivalist culture <span class="yellow">pushes it towards Chattel Religionism,</span> since the word of God is already a matter of daily significance there.`
+					},
+				]],
+				["FSChineseRevivalist", [
+					{
+						fs: "FSSlaveProfessionalism",
+						msg: `The arcology's Chinese Revivalist culture <span class="yellow">pushes it towards Slave Professionalism,</span> since well-educated, dispassionate slave leaders are more effective.`
+					},
+					{
+						fs: "FSPaternalist",
+						msg: `The arcology's Chinese Revivalist culture <span class="yellow">pushes it towards Paternalism,</span> since traditional beliefs about duty and order have become accepted.`
+					},
+				]],
+			]);
+			const validChoice = /** @param {crossFSDest} dest */ (dest) => validFSes.includes(dest.fs) && (!dest.prereqs || dest.prereqs());
+			const candidates = [];
+			for (const [source, destArray] of crossFS) {
+				if (arc[source] > random(50, 200)) {
+					for (const dest of destArray) {
+						if (Array.isArray(dest)) {
+							// pick one at random
+							const choice = dest.filter(x => validChoice(x)).random();
+							if (choice) {
+								candidates.push(choice);
+								break; // only select one dest per source
+							}
+						} else if (validChoice(dest)) {
+							candidates.push(dest);
+							break; // only select one dest per source
+						}
+					}
 				}
 			}
-			if (arc.FSChineseRevivalist > random(50, 200)) {
-				if (validFSes.includes("FSPaternalist")) {
-					r.push(`The arcology's Chinese Revivalist culture <span class="yellow">pushes it towards Paternalism,</span> since traditional beliefs about duty and order have become accepted.`);
-					arc.FSPaternalist = 5;
-					return;
-				}
+			if (candidates.length > 0) {
+				const candidate = candidates.random();
+				r.push(candidate.msg);
+				arc[candidate.fs] = 5;
+				return;
 			}
 
 			/* NEIGHBOR ADOPTION*/
+			const influencedBy = [];
+			const aligned = [];
+			const opposed = [];
+			const usableCandidates = [];
 			for (const arc2 of V.arcologies) {
 				if (arc.direction !== arc2.direction) {
 					let influenceBonus = 0;
 					if (arc.direction === arc2.influenceTarget) {
-						r.push(`${arc2.name}'s directed cultural influence gives it some input over ${arc.name}'s choice of direction.`);
+						influencedBy.push(arc2.name);
 						influenceBonus = 20;
 					}
 
 					const opinion = App.Neighbor.opinion(arc, arc2);
 					if (opinion >= 50) {
-						r.push(`${arc.name} is aligned with ${arc2.name} socially, encouraging it to consider adopting all its cultural values.`);
+						aligned.push(arc2.name);
 						influenceBonus += opinion - 50;
 					} else if (opinion <= -50) {
-						r.push(`${arc.name} is culturally opposed to ${arc2.name}, encouraging it to resist adopting its cultural values.`);
+						opposed.push(arc2.name);
 						influenceBonus += opinion + 50;
 					}
 
+					if (arc2.direction === 0 && V.baseDifficulty < 3) {
+						// 10 points of bonus influence for player per level below normal
+						influenceBonus += (3 - V.baseDifficulty) * 10;
+					} else if (arc2.rival === 1 && V.baseDifficulty > 3) {
+						// 10 points of bonus influence for rival per level above normal
+						influenceBonus += (V.baseDifficulty - 3) * 10;
+					}
+
 					for (const candidate of validFSes) {
-						if (candidate === "FSSubjugationist") {
-							if ((arc.FSSupremacist === "unset") || (arc.FSSupremacistRace !== arc2.FSSubjugationistRace)) {
-								if (arc2.FSSubjugationist > random(0, 200) - influenceBonus) {
-									r.push(`It <span class="yellow">adopts ${arc2.FSSubjugationistRace} Subjugation</span> due to influence from its trading partner ${arc2.name}.`);
-									arc.FSSubjugationist = 5;
-									arc.FSSubjugationistRace = arc2.FSSubjugationistRace;
-									return;
+						if (arc2[candidate] > random(0, 200) - influenceBonus) {
+							// equal weight by default (at normal difficulty, or the arc is neither player nor rival)
+							usableCandidates.push({arc2, candidate});
+							if (arc2.direction === 0) {
+								// easier than normal: player FS gets bonus chance
+								if (V.baseDifficulty < 3) {
+									usableCandidates.push({arc2, candidate});
 								}
-							}
-						} else if (candidate === "FSSupremacist") {
-							if ((arc.FSSubjugationist === "unset") || (arc.FSSubjugationistRace !== arc2.FSSupremacistRace)) {
-								if (arc2.FSSupremacist > random(0, 200) - influenceBonus) {
-									r.push(`It <span class="yellow">adopts ${arc2.FSSupremacistRace} Supremacy</span> due to influence from its trading partner ${arc2.name}.`);
-									arc.FSSupremacist = 5;
-									arc.FSSupremacistRace = arc2.FSSupremacistRace;
-									return;
+								// very easy: player FS gets another bonus chance
+								if (V.baseDifficulty < 2) {
+									usableCandidates.push({arc2, candidate});
+								}
+							} else if (arc2.rival > 0) {
+								// harder than normal: rival FS gets bonus chance
+								if (V.baseDifficulty > 3) {
+									usableCandidates.push({arc2, candidate});
+								}
+								// nightmare: rival FS gets another bonus chance
+								if (V.baseDifficulty > 4) {
+									usableCandidates.push({arc2, candidate});
 								}
-							}
-						} else {
-							if (arc2[candidate] > random(0, 200) - influenceBonus) {
-								r.push(`It <span class="yellow">adopts ${FutureSocieties.displayName(candidate)}</span> due to influence from its trading partner ${arc2.name}.`);
-								arc[candidate] = 5;
-								return;
 							}
 						}
 					}
 				}
 			}
+			if (influencedBy.length > 0) {
+				r.push(`Directed cultural influence from ${toSentence(influencedBy)} gives ${influencedBy.length > 1 ? 'them' : 'it'} some input over ${arc.name}'s choice of direction.`);
+			}
+			if (aligned.length > 0) {
+				r.push(`${arc.name} is aligned with ${toSentence(aligned)} socially, encouraging it to consider adopting more of ${aligned.length > 1 ? 'their' : 'its'} cultural values.`);
+			}
+			if (opposed.length > 0) {
+				r.push(`${arc.name} is culturally opposed with ${toSentence(opposed)} socially,  encouraging it to resist adopting ${opposed.length > 1 ? 'their' : 'its'} cultural values.`);
+			}
+			if (usableCandidates.length > 0) {
+				const chosen = usableCandidates.random();
+				if (chosen.candidate === "FSSubjugationist") {
+					r.push(`It <span class="yellow">adopts ${chosen.arc2.FSSubjugationistRace} Subjugation</span> due to influence from its trading partner ${chosen.arc2.name}.`);
+					arc.FSSubjugationist = 5;
+					arc.FSSubjugationistRace = chosen.arc2.FSSubjugationistRace;
+				} else if (chosen.candidate === "FSSupremacist") {
+					r.push(`It <span class="yellow">adopts ${chosen.arc2.FSSupremacistRace} Supremacy</span> due to influence from its trading partner ${chosen.arc2.name}.`);
+					arc.FSSupremacist = 5;
+					arc.FSSupremacistRace = chosen.arc2.FSSupremacistRace;
+				} else {
+					r.push(`It <span class="yellow">adopts ${FutureSocieties.displayName(chosen.candidate)}</span> due to influence from its trading partner ${chosen.arc2.name}.`);
+					arc[chosen.candidate] = 5;
+				}
+				return;
+			}
 
 			/* RANDOM ADOPTION*/
 			if (random(0, 4) === 1) {
diff --git a/src/endWeek/economics/persBusiness.js b/src/endWeek/economics/persBusiness.js
index 91dc5b53e669e8bae694741894774423556409c4..ad5172e4019b29373974f4cb7acf603d688a62cd 100644
--- a/src/endWeek/economics/persBusiness.js
+++ b/src/endWeek/economics/persBusiness.js
@@ -548,7 +548,7 @@ App.EndWeek.personalBusiness = function() {
 	}
 	*/
 
-	if (V.PC.health.shortDamage < 30) {
+	if (V.PC.actualAge > 3) { // Always true for now. Need to finish this later, using the following as the condition. (!onBedRest(V.PC, true))
 		let oldSkill;
 		switch (V.personalAttention.task) {
 			case PersonalAttention.TRADE:
diff --git a/src/endWeek/economics/personalNotes.js b/src/endWeek/economics/personalNotes.js
index 307d97a6db21477cb5b6838df5abe69ad4dd46dd..de0869c2201b1067d0ed56f573cc7f6efca57864 100644
--- a/src/endWeek/economics/personalNotes.js
+++ b/src/endWeek/economics/personalNotes.js
@@ -50,6 +50,7 @@ App.EndWeek.personalNotes = function() {
 	}
 
 	r.push(App.EndWeek.Player.longTermEffects());
+	r.push(App.EndWeek.Player.mobility());
 
 	App.Events.addParagraph(el, r);
 	r = [];
diff --git a/src/endWeek/economics/reputation.js b/src/endWeek/economics/reputation.js
index 4e280d0a7c64a656eaba8f604ba5e2d830f9ddbf..f9c40e257fd147fe3b45108b5f23b82483f9d614 100644
--- a/src/endWeek/economics/reputation.js
+++ b/src/endWeek/economics/reputation.js
@@ -446,7 +446,7 @@ App.EndWeek.reputation = function() {
 			repX(forceNeg(10 * V.PC.buttImplant), "PCappearance");
 		}
 		if (V.PC.ballsImplant > 0) {
-			r.push(`Society finds everything unnatural disgusting and the grotesque bulge in your crotch is no exception; your gel filled balls <span class="red">harm</span> your public image.`);
+			r.push(`Society finds everything unnatural disgusting and the grotesque bulge in your crotch is no exception; your gel-filled balls <span class="red">harm</span> your public image.`);
 			repX(forceNeg(10 * V.PC.ballsImplant), "PCappearance");
 		}
 		if (V.arcologies[0].FSRepopulationFocus !== "unset" && V.PC.boobs >= 1000 && V.PC.boobsImplant === 0) {
diff --git a/src/endWeek/healthFunctions.js b/src/endWeek/healthFunctions.js
index e3f75667a1b075607ccd1353b5c97418eac36700..ef9f85fe1cc322c444f6490279090b27cf5715cc 100644
--- a/src/endWeek/healthFunctions.js
+++ b/src/endWeek/healthFunctions.js
@@ -420,7 +420,7 @@ globalThis.endWeekHealthDamage = function(slave) {
 				H.longDamage += chemToLong;
 			} else {
 				slave.chem = Math.clamp(slave.chem - 0.2, 0, 1000); // note that it lingers, causing issues
-				chemToShort += Math.max(Math.trunc(slave.chem * 0.05), 1);
+				chemToShort += Math.min(Math.max(Math.trunc(slave.chem * 0.05), 1), 5); // capped at 5 for now
 				H.shortDamage += chemToShort;
 				chemToLong += Math.trunc(slave.chem * 0.01);
 				H.longDamage += chemToLong;
@@ -429,12 +429,14 @@ globalThis.endWeekHealthDamage = function(slave) {
 
 		// recovering and converting short term damage to long term
 		if (H.shortDamage > 0) {
-			// short term damage reduces at a constant rate
-			// 40+ long term damage begins to harm short term recovery
-			// at 360+, you're ability to heal properly is completely crippled
+			// short term damage begins converting to long term damage at 20+
+			shortToLong += Math.trunc(H.shortDamage * 0.1);
+			H.longDamage += shortToLong;
+			// short term damage reduces by half each week normally
+			// 100+ long term damage begins to harm short term recovery
+			// at 400+, you're ability to heal properly is completely crippled
 			// but, keep in mind, that short and long damage do not directly influence health, sans illness
-			shortRecovery += 10 - Math.trunc(H.longDamage * 0.025);
-			shortRecovery = Math.max(shortRecovery, 1);
+			shortRecovery = Math.max(Math.trunc(H.shortDamage * (0.5 + Math.min(0.4, H.longDamage * 0.001))), 1);
 			if (V.personalAttention.task === PersonalAttention.RELAX) {
 				shortRecovery += 5;
 			}
@@ -442,9 +444,6 @@ globalThis.endWeekHealthDamage = function(slave) {
 				shortRecovery += 5;
 			}
 			H.shortDamage = Math.max(H.shortDamage - shortRecovery, 0);
-			// short term damage begins converting to long term damage at 20+
-			shortToLong += Math.trunc(H.shortDamage * 0.1);
-			H.longDamage += shortToLong;
 		}
 
 		// Reducing longDamage for easier difficulties
@@ -457,6 +456,11 @@ globalThis.endWeekHealthDamage = function(slave) {
 			H.longDamage = Math.max(H.longDamage, 0);
 		}
 
+		// Temporarily disabled for balancing. healthDamage() is causing too much shortDamage right now, need to think on things.
+		H.longDamage = 0;
+		H.shortDamage = 0;
+		slave.chem = 0;
+
 		// The player gets an automatic 5 condition recovery each week up to 100
 		// relaxation and diet is handled in its respective locations
 		H.condition = Math.min(H.condition + 5, 100);
diff --git a/src/endWeek/nextWeek/nextWeek.js b/src/endWeek/nextWeek/nextWeek.js
index 0c1c8b3d6fee1597126502e6e79261401a439824..38fba02bc6d292e18cc6a362f77f24915339f809 100644
--- a/src/endWeek/nextWeek/nextWeek.js
+++ b/src/endWeek/nextWeek/nextWeek.js
@@ -4,11 +4,21 @@ App.EndWeek.nextWeek = function() {
 	V.upgradeMultiplierMedicine = upgradeMultiplier('medicine');
 	V.upgradeMultiplierTrade = upgradeMultiplier('trading');
 
-	const rival = V.arcologies.find(function(s) { return s.direction !== 0 && s.rival === 1; });
+	const rival = V.arcologies.find(s => s.direction !== 0 && s.rival === 1);
 	if (rival && V.rival.prosperity !== 0) {
 		V.rival.prosperity = rival.prosperity;
 	} else if (!rival) {
-		V.rival.state = 1;
+		if (V.slaves.filter(s => s.newGamePlus === 0 && s.origin.includes("$He was once an arcology owner like yourself.")).length > 0) {
+			V.rival.state = 5;
+		} else if (V.plot > 0 && V.rival.prosperity > 0) {
+			if (V.arcologies.length > 1) {
+				V.rival.state = 2;
+			} else if (V.arcologies.length === 1) {
+				V.rival.state = 1;
+			}
+		} else {
+			V.rival.state = 4;
+		}
 	}
 
 	if (V.playerAging !== 0) {
@@ -36,6 +46,9 @@ App.EndWeek.nextWeek = function() {
 			}
 		}
 	}
+	if (V.PC.majorInjury > 0) {
+		V.PC.majorInjury--;
+	}
 	if (V.PC.induceLactation > 0) {
 		V.PC.induceLactation--;
 	}
@@ -55,9 +68,6 @@ App.EndWeek.nextWeek = function() {
 	} else if (V.PC.fertPeak !== 0) {
 		V.PC.fertPeak = 0;
 	}
-	if (V.PC.health.shortDamage > 0) {
-		V.PC.health.shortDamage--;
-	}
 
 	// Adding random changes to the economy
 	if (V.difficultySwitch === 1) {
diff --git a/src/endWeek/player/prDiet.js b/src/endWeek/player/prDiet.js
index dc428a71812cfb189e5e261c51848c9af14545b3..cb8a28486a133e8df797db241d776ad1168d7cbe 100644
--- a/src/endWeek/player/prDiet.js
+++ b/src/endWeek/player/prDiet.js
@@ -32,7 +32,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 				weightLoss = 4;
 				if (PC.weightDirection === -1) {
 					PC.weight -= (weightLoss + 3);
-					r.push(`You stick to a strict diet,<span class="change positive">losing a lot of weight.</span>`);
+					r.push(`You stick to a strict diet, <span class="change positive">losing a lot of weight.</span>`);
 				} else if (PC.weightDirection === 1) {
 					PC.weight -= (weightLoss - 3);
 					r.push(`Despite sticking to a strict diet, <span class="change positive">you barely lose any weight.</span>`);
@@ -67,10 +67,10 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 				PC.weight = Math.min(PC.weight, 200);
 				break;
 			case "muscle building": // Muscle Gain
-				r.push(gainMuscle());
+				gainMuscle();
 				break;
 			case "slimming": // Muscle Loss
-				r.push(loseMuscle());
+				loseMuscle();
 				break;
 			case "exotic":
 				r.push(`You stick to an unusual diet full of exotic foods and drinks, both rumored and proven, to boost your sexual energy.`);
@@ -83,6 +83,15 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 					r.push(`The <span class="change positive">added heft to your balls</span> is a pleasant side-effect.`);
 					PC.balls += 1;
 				}
+				if (PC.vagina >= 0 && PC.vaginaLube < 2) {
+					if (PC.vagina >= 0 && PC.vaginaLube === 0 && PC.energy > 20 && random(1, 100) > (100 - (PC.energy / 4))) {
+						r.push(`It also gets the juices flowing; <span class="change positive">your pussy is no longer so dry.</span>`);
+						PC.vaginaLube = 1;
+					} else if (PC.energy > 95 && random(1, 100) >  40 + ((100 - PC.energy) * 10)) {
+						r.push(`It also gets the juices really flowing; <span class="change positive">your pussy has become so wet</span> that you're soaked with arousal by the end of your meal.`);
+						PC.vaginaLube = 2;
+					}
+				}
 				break;
 			case "medicinal":
 				r.push(`You stick to an unusual diet full of exotic foods and drinks known for <span class="health inc">fortifying health, healing ailments, and cleansing the body.</span>`);
@@ -116,7 +125,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 				weightLoss = 5 + (V.feeder * 2);
 				if (PC.weightDirection === -1) {
 					PC.weight -= (weightLoss + 3);
-					r.push(`You stick to a strict diet,<span class="change positive">losing a lot of weight.</span>`);
+					r.push(`You stick to a strict diet, <span class="change positive">losing a lot of weight.</span>`);
 				} else if (PC.weightDirection === 1) {
 					PC.weight -= (weightLoss - 3) - (V.feeder);
 					r.push(`Despite sticking to a strict diet, <span class="change positive">you barely lose any weight.</span>`);
@@ -235,15 +244,15 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 					}
 				}
 				if (PC.weight >= -10 && PC.weight <= 10) {
-					r.push(`Since you have now accomplished your goal, you're going<span class="noteworthy">back to a normal diet.</span>`);
+					r.push(`Since you have now accomplished your goal, you're going <span class="noteworthy">back to a normal diet.</span>`);
 					PC.diet = "healthy";
 				}
 				break;
 			case "muscle building": // Muscle Gain
-				r.push(gainMuscle());
+				gainMuscle();
 				break;
 			case "slimming": // Muscle Loss
-				r.push(loseMuscle());
+				loseMuscle();
 				break;
 			case "cum production":
 				// This should increase .need
@@ -548,7 +557,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 					PC.inflationType = "undigested food";
 					PC.inflationMethod = 1;
 					PC.belly += 300;
-					PC.bellyInflation += 300;
+					PC.bellyFluid += 300;
 					SetBellySize(PC);
 				} else if (PC.weaningDuration < 14) {
 					r.push(`Your body is improving at absorbing nutrients from it, but still <span class="change negative">breaks down some fat and muscle tissue</span> to make up for what it can't.`);
@@ -577,7 +586,10 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 	}
 
 	function gainMuscle() {
-		if (isAmputee(PC)) {
+		if (onBedRest(PC)) {
+			r.push(`You aren't capable of actively working out, so you're <span class="noteworthy">back on a normal diet.</span>`);
+			PC.diet = "healthy";
+		} else if (isAmputee(PC)) {
 			r.push(`You can't work out with no limbs, so you're <span class="noteworthy">back on a normal diet.</span>`);
 			PC.diet = "healthy";
 		} else {
@@ -605,7 +617,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 				r.push(`but with the natural testosterone and artificial female hormones clashing in your system, <span class="change positive">gain muscle slowly.</span>`);
 				PC.muscles += 3 + PC.geneticQuirks.mGain;
 			} else if (PC.balls > 0 && PC.ballType !== "sterile" && PC.hormoneBalance <= -100) {
-				r.push(`and with the natural testosterone and artificial male hormones in your system,<span class="change positive">rapidly bulk up.</span>`);
+				r.push(`and with the natural testosterone and artificial male hormones in your system, <span class="change positive">rapidly bulk up.</span>`);
 				PC.muscles += 8;
 			} else if (PC.balls > 0 && PC.ballType !== "sterile") {
 				r.push(`and with the natural testosterone in your system, <span class="change positive">efficiently bulk up.</span>`);
@@ -655,7 +667,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 			}
 			PC.muscles = Math.clamp(PC.muscles, -100, 100);
 			if (PC.muscles >= 100) {
-				r.push(`There is just no more room for muscle on your frame, so you will be<span class="noteworthy">resuming a normal diet</span> next week.`);
+				r.push(`There is just no more room for muscle on your frame, so you will be <span class="noteworthy">resuming a normal diet</span> next week.`);
 				PC.diet = "healthy";
 			}
 		}
@@ -827,7 +839,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 			roll = 75;
 			target = Math.trunc(Math.clamp(weightMod * 2 - (boobSize - growthGoal) / 20, 0, 68));
 		}
-		if (PC.geneMods.NCS === 1) {
+		if (PC.geneMods.NCS === 1 || (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(PC))) {
 			roll *= 2;
 		}
 		// PC food is not laced with hormones normally, so galactorrhea is not triggered here.
@@ -844,7 +856,7 @@ App.EndWeek.Player.diet = function(PC = V.PC) {
 			roll = 80000;
 			target = Math.trunc(Math.clamp(weightMod * 1000 - (buttSize * 1000 - growthGoal) * 4, 0, 72000));
 		}
-		if (PC.geneMods.NCS === 1) {
+		if (PC.geneMods.NCS === 1 || (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(PC))) {
 			roll *= 2;
 		}
 		if (random(1, roll) <= target) {
diff --git a/src/endWeek/player/prHealth.js b/src/endWeek/player/prHealth.js
index b2dd16909e77db42c95660c22a5be546fb736ba1..4d7f6a4475b38a11337ffe08e7602e695ecaaddd 100644
--- a/src/endWeek/player/prHealth.js
+++ b/src/endWeek/player/prHealth.js
@@ -5,6 +5,9 @@ App.EndWeek.Player.health = function(PC = V.PC) {
 
 	PC.chem = Math.clamp(PC.chem - 0.01, 0, 1000);
 
+	if (PC.diet !== "medicinal") {
+		healthBlips();
+	}
 	illness();
 	addiction();
 	endWeekHealthDamage(PC);
@@ -12,6 +15,83 @@ App.EndWeek.Player.health = function(PC = V.PC) {
 
 	return r.join(" ");
 
+	function healthBlips() {
+		if (PC.chem > 5) {
+			if (random(1, 220) < (PC.chem * 2) + PC.physicalAge - PC.health.condition) {
+				healthDamage(PC, 5);
+				switch (random(1, 10)) {
+					case 1:
+						r.push(`A bout of foreplay was interrupted when your partner discovered a small lump in your ${PC.boobs >= 300 ? "breast" : "chest"}. Your doctor removed it easily enough, <span class="cash">for a small fee,</span> with testing revealing it as benign.`);
+						cashX(forceNeg(500), "PCmedical");
+						break;
+					case 2:
+						r.push(`A bout of intense vertigo kept you stuck in bed, unwilling to move. Eventually the feeling passes on its own, just as suddenly as it arrived.`);
+						break;
+					case 3:
+						r.push(`You spent the morning experiencing an unshakable sense of dread. Eventually the feeling passes on its own, just as suddenly as it arrived.`);
+						break;
+					case 4:
+						r.push(`You're plagued by a series of severe headaches that are calmed easily enough by a dose of aspirin each.`);
+						break;
+					case 5:
+						r.push(`You experience recurrent nausea each morning this week.`);
+						if (PC.preg.isBetween(0, 4)) {
+							if (PC.pregKnown === 0) {
+								r.push(`It turns out <span class="pregnant">you're pregnant,</span> but it still didn't feel like ${PC.counter.birthsTotal > 0 ? "your morning sickness did last pregnancy" : "morning sickness to you"}.`);
+								PC.pregKnown = 1;
+							} else {
+								r.push(`You have been experiencing morning sickness already, and this is not helping matters.`);
+							}
+						} else {
+							r.push(`Your stomach is soothed with a little medication, but it was still unpleasant.`);
+						}
+						break;
+					case 6:
+						r.push(`You had trouble sleeping without taking anything before bed, several nights in a row.`);
+						break;
+					case 7:
+						r.push(`After a vigorous lovemaking session, you discover your heart rate is not coming down. A minor dose of medication resolves it, but it was still alarming.`);
+						break;
+					case 8:
+						r.push(`Much to your dismay, you discover that your blood isn't clotting properly. Eventually the cut stops bleeding on its own, but it does not bode well should anything worse happen to you.`);
+						break;
+					case 9:
+						r.push(`You've developed several ugly little ${PC.skin} skin tags. The autosurgery has everything you need to trivially remove them, but they are still annoying.`);
+						break;
+					default:
+						r.push(`Often you just feel wrong for a short spell before recovering.`);
+				}
+				r.push(`This likely was <span class="health dec">a side effect</span> of some treatment you've undergone.`);
+			}
+		}
+
+		if (PC.weight > 190) {
+			r.push(`Your extreme obesity <span class="health dec">directly impacts</span> your health, but since you let yourself get this large, it's not really that bothersome.`);
+			healthDamage(PC, 2);
+			if (random(1, 100 + PC.health.condition) < 5) {
+				r.push(`Unfortunately, this week ushered in <span class="health dec">severe health complications</span> related to it. After extensive, <span class="cash">and very costly,</span> heart surgery, your life was saved, though you'd better set aside some ¤ for when it happens again.`);
+				cashX(forceNeg(15000), "PCmedical");
+				healthDamage(PC, 80);
+			}
+		} else if (PC.weight > 160) {
+			if (random(1, 150 + PC.health.condition) < 5) {
+				r.push(`Your obesity has brought <span class="health dec">severe health complications</span> upon you this week. They required extensive, <span class="cash">and costly,</span> surgery to correct, so it may be time to pay more mind to your wellbeing.`);
+				cashX(forceNeg(5000), "PCmedical");
+				healthDamage(PC, 40);
+			}
+		} else if (PC.weight > 130) {
+			if (random(1, 175 + PC.health.condition) < 5) {
+				r.push(`Your weight caused you some <span class="health dec">severe health complications</span> this week. They passed after some time, but are rather concerning.`);
+				healthDamage(PC, 20);
+			}
+		} else if (PC.weight > 95) {
+			if (random(1, 200 + PC.health.condition) < 5) {
+				r.push(`Your weight caused you some <span class="health dec">minor health complications</span> this week. It passed quickly enough, and shouldn't be a real problem.`);
+				healthDamage(PC, 5);
+			}
+		}
+	}
+
 	function illness() {
 		const sicknessDegree = ["fine", "minor illness", "illness", "bad illness", "severe illness", "life-threatening illness"];
 
diff --git a/src/endWeek/player/prHormones.js b/src/endWeek/player/prHormones.js
index f229f5215932860520020f8f9576f0b1c1343b0b..3092dc196038a7b164524bfe6145bb27fad1375f 100644
--- a/src/endWeek/player/prHormones.js
+++ b/src/endWeek/player/prHormones.js
@@ -122,9 +122,11 @@ App.EndWeek.Player.hormones = function(PC, selfManufactured, hormonePower) {
 	function hormonesEffects() {
 		if (Math.abs(PC.hormoneBalance) >= 50) {
 			if (PC.hormoneBalance > 30 && PC.geneMods.NCS !== 1) {
+				const slimModBreasts = (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(PC)) ? 0.45 : 1; // 600 average breast target, 270 target, 475 @ 350 hormone
+				const slimModButts = (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(PC)) ? 0.6 : 1; // 2.5 average butt, 1.5 target
 				/* 'Expected' breast size based on weight for feminine-bodied player. Masculine-bodied takes a small hit. */
-				normBreasts = Math.trunc((100 + (PC.weight + 100) * 5 + 2 * PC.lactationAdaptation) * (0.85 + PC.hormoneBalance / 400) * gigantomastiaMod / Math.max(PC.title * 1.25,  1));
-				normButt = ((PC.weight + 100) * 0.025 * (0.9 + PC.hormoneBalance / 600) * (rearLipedemaMod / 2 + 1) / Math.max(PC.title * 1.10,  1));
+				normBreasts = Math.trunc((100 + (PC.weight + 100) * 5 + 2 * PC.lactationAdaptation) * (0.85 + PC.hormoneBalance / 400) * gigantomastiaMod * slimModBreasts / Math.max(PC.title * 1.25,  1));
+				normButt = ((PC.weight + 100) * 0.025 * (0.9 + PC.hormoneBalance / 600) * (rearLipedemaMod / 2 + 1) * slimModButts / Math.max(PC.title * 1.10,  1));
 			}
 
 			if (PC.hormoneBalance >= 350) {
diff --git a/src/endWeek/player/prLongTermPhysicalEffects.js b/src/endWeek/player/prLongTermPhysicalEffects.js
index 4938c9b4b99ce2e648d0a9822201222c6870c1e8..e141c20d2011e029a943da9c321abaf1a8dfde43 100644
--- a/src/endWeek/player/prLongTermPhysicalEffects.js
+++ b/src/endWeek/player/prLongTermPhysicalEffects.js
@@ -32,10 +32,6 @@ App.EndWeek.Player.longTermPhysicalEffects = function(PC = V.PC) {
 	lactationEffects();
 	boobsEffects(); // Moved up from middle of the mobility and oversized asset set of text.
 	bellyEffects(); // Moved up from middle of the mobility and oversized asset set of text.
-	// player mobility function goes here.
-	if (PC.diet !== "medicinal") {
-		healthBlips();
-	}
 
 	return r.join(" ");
 
@@ -312,6 +308,15 @@ App.EndWeek.Player.longTermPhysicalEffects = function(PC = V.PC) {
 			PC.energy++;
 		}
 		PC.energy = Math.max(PC.energy, 0);
+		if (PC.pubertyXX === 1 && PC.vagina >= 0) {
+			if (PC.energy > 60 && PC.vaginaLube === 0 && (V.policies.sexualOpenness === 1 || averageDicking.length > 0) && random(1, 100) > 95) {
+				r.push(`With all the excitement in your life, your formerly dry pussy <span class="change positive">starts moistening up.</span>`);
+				PC.vaginaLube++;
+			} else if (PC.energy <= 20 && PC.vaginaLube > 0 && V.policies.sexualOpenness === 0 && averageDicking.length === 0 && random(1, 100) <= 5) {
+				r.push(`Since you aren't getting any and have no interest in doing so, your naturally wet pussy <span class="change negative">cuts back on fluid production.</span>`);
+				PC.vaginaLube--;
+			}
+		}
 	}
 
 	function sexualSatisfaction() {
@@ -947,81 +952,4 @@ App.EndWeek.Player.longTermPhysicalEffects = function(PC = V.PC) {
 			}
 		}
 	}
-
-	function healthBlips() {
-		if (PC.chem > 5) {
-			if (random(1, 220) < (PC.chem * 2) + PC.physicalAge - PC.health.condition) {
-				healthDamage(PC, 5);
-				switch (random(1, 10)) {
-					case 1:
-						r.push(`A bout of foreplay was interrupted when your partner discovered a small lump in your ${PC.boobs >= 300 ? "breast" : "chest"}. Your doctor removed it easily enough, <span class="cash">for a small fee,</span> with testing revealing it as benign.`);
-						cashX(forceNeg(500), "PCmedical");
-						break;
-					case 2:
-						r.push(`A bout of intense vertigo kept you stuck in bed, unwilling to move. Eventually the feeling passes on its own, just as suddenly as it arrived.`);
-						break;
-					case 3:
-						r.push(`You spent the morning experiencing an unshakable sense of dread. Eventually the feeling passes on its own, just as suddenly as it arrived.`);
-						break;
-					case 4:
-						r.push(`You're plagued by a series of severe headaches that are calmed easily enough by a dose of aspirin each.`);
-						break;
-					case 5:
-						r.push(`You experience recurrent nausea each morning this week.`);
-						if (PC.preg.isBetween(0, 4)) {
-							if (PC.pregKnown === 0) {
-								r.push(`It turns out <span class="pregnant">you're pregnant,</span> but it still didn't feel like ${PC.counter.birthsTotal > 0 ? "your morning sickness did last pregnancy" : "morning sickness to you"}.`);
-								PC.pregKnown = 1;
-							} else {
-								r.push(`You have been experiencing morning sickness already, and this is not helping matters.`);
-							}
-						} else {
-							r.push(`Your stomach is soothed with a little medication, but it was still unpleasant.`);
-						}
-						break;
-					case 6:
-						r.push(`You had trouble sleeping without taking anything before bed, several nights in a row.`);
-						break;
-					case 7:
-						r.push(`After a vigorous lovemaking session, you discover your heart rate is not coming down. A minor dose of medication resolves it, but it was still alarming.`);
-						break;
-					case 8:
-						r.push(`Much to your dismay, you discover that your blood isn't clotting properly. Eventually the cut stops bleeding on its own, but it does not bode well should anything worse happen to you.`);
-						break;
-					case 9:
-						r.push(`You've developed several ugly little ${PC.skin} skin tags. The autosurgery has everything you need to trivially remove them, but they are still annoying.`);
-						break;
-					default:
-						r.push(`Often you just feel wrong for a short spell before recovering.`);
-				}
-				r.push(`This likely was <span class="health dec">a side effect</span> of some treatment you've undergone.`);
-			}
-		}
-
-		if (PC.weight > 190) {
-			r.push(`Your extreme obesity <span class="health dec">directly impacts</span> your health, but since you let yourself get this large, it's not really that bothersome.`);
-			healthDamage(PC, 2);
-			if (random(1, 100 + PC.health.condition) < 5) {
-				r.push(`Unfortunately, this week ushered in <span class="health dec">severe health complications</span> related to it. After extensive, <span class="cash">and very costly,</span> heart surgery, your life was saved, though you'd better set aside some ¤ for when it happens again.`);
-				cashX(forceNeg(15000), "PCmedical");
-				healthDamage(PC, 80);
-			}
-		} else if (PC.weight > 160) {
-			if (random(1, 150 + PC.health.condition) < 5) {
-				r.push(`Your obesity has brought <span class="health dec">severe health complications</span> upon you this week. They required extensive, <span class="cash">and costly,</span> surgery to correct, so it may be time to pay more mind to your wellbeing.`);
-				cashX(forceNeg(5000), "PCmedical");
-				healthDamage(PC, 40);
-			}
-		} else if (PC.weight > 130) {
-			if (random(1, 175 + PC.health.condition) < 5) {
-				r.push(`Your weight caused you some <span class="health dec">severe health complications</span> this week. They passed after some time, but are rather concerning.`);
-				healthDamage(PC, 20);
-			}
-		} else if (PC.weight > 95) {
-			if (random(1, 200 + PC.health.condition) < 5) {
-				r.push(`Your weight caused you some <span class="health dec">minor health complications</span> this week. It passed quickly enough, and shouldn't be a real problem.`);
-				healthDamage(PC, 5);
-			}
-		}
-	}
 };
diff --git a/src/endWeek/player/prMobility.js b/src/endWeek/player/prMobility.js
new file mode 100644
index 0000000000000000000000000000000000000000..a982cdca9ee423882ccde79745f2c2f9727b0e69
--- /dev/null
+++ b/src/endWeek/player/prMobility.js
@@ -0,0 +1,552 @@
+App.EndWeek.Player.mobility = function(PC = V.PC) {
+	const r = [];
+
+	const immobilities = [];
+	const noWalking = [];
+
+	const {hisP, girlP} = getPronouns(PC).appendSuffix("P");
+
+	mobility();
+	muscularAtrophy();
+	bodyAccessibility();
+	hugeBreasts();
+	boobAccessibility();
+	hugeBelly();
+	bellyAccessibility();
+	hugeDick();
+	dickAccessibility();
+	hugeBalls();
+	ballsAccessibility();
+	hugeHips();
+	hugeButt();
+	buttAccessibility();
+	hindrance();
+
+	return r.join(" ");
+
+	function mobility() {
+		if (PC.weight >= 300) {
+			immobilities.push("fat body");
+		}
+		if (PC.belly >= 1100000) {
+			immobilities.push("belly");
+		}
+		if (PC.boobs >= 1500000) {
+			immobilities.push("breasts");
+		}
+		if (PC.balls >= 160) {
+			immobilities.push("balls");
+		}
+		if (immobilities.length > 0) {
+			r.push(`You have been rendered <span class="immobile">completely immobile</span> by the size and weight of your`);
+			r.push(toSentence(immobilities));
+			r.push(r.pop() + `, leaving you stuck on your bed. Nothing short of industrial equipment is capable of lifting you, and the logistics of getting something like that into the penthouse make it pretty clear that you aren't going to be going anywhere until you deal with all of this.`);
+		}
+		if (tooFatSlave(PC) && !immobilities.includes("fat body")) {
+			noWalking.push("fat body");
+		}
+		if (tooBigBreasts(PC) && !immobilities.includes("breasts")) {
+			noWalking.push("breasts");
+		}
+		if (tooBigBelly(PC) && !immobilities.includes("belly")) {
+			noWalking.push("belly");
+		}
+		if (tooBigButt(PC) && !immobilities.includes("butt")) {
+			noWalking.push("butt");
+		}
+		if (tooBigDick(PC) && !immobilities.includes("dick")) {
+			noWalking.push("dick");
+		}
+		if (tooBigBalls(PC) && !immobilities.includes("balls")) {
+			noWalking.push("balls");
+		}
+		if (PC.physicalImpairment > 1 || noWalking.length > 0) {
+			if (immobilities.length > 0) {
+				r.push(`Ignoring the obvious,`);
+				if (noWalking.length > 0) {
+					r.push(`the weight of your ${toSentence(noWalking)} would prevent you from walking anyway.`);
+					if (PC.physicalImpairment > 1) {
+						r.push(`Your injuries may also be contributing to that, but it's hard to tell when you can't even try.`);
+					}
+				} else {
+					r.push(`it's not like you could walk anyway, having never regained the ability after being injured.`);
+				}
+				if (isMovable(PC)) {
+					r.push(`You have to use a wheelchair if you want to get anywhere, which is subject to its own host of day-to-day problems.`);
+				}
+			} else {
+				r.push(`You've <span class="hindrance mid">lost the ability to walk</span> due to`);
+				if (noWalking.length > 0) {
+					r.push(`the size and weight of your ${toSentence(noWalking)}, forcing you to rely on a wheelchair to get around.`);
+					if (PC.physicalImpairment > 1) {
+						r.push(`Your injuries may also be contributing to that, but it's hard to tell when you can't even try.`);
+					}
+					if (canMove(PC)) {
+						r.push(`At the very least, you can still crawl if needed, so you aren't completely helpless.`);
+					}
+				} else {
+					r.push(`crippling injuries, forcing you to rely on a wheelchair to get around.`);
+					if (canMove(PC)) {
+						r.push(`At the very least, you can still crawl if needed, so you aren't completely helpless.`);
+					}
+				}
+			}
+		}
+		if (isTrapped(PC)) {
+			if (!isMovable(PC)) {
+				r.push(`It's not like you could leave your room anyway; the door is too small.`);
+			} else {
+				r.push(`To make matters even worse, you can't leave your room; the door is too small to fit through.`);
+			}
+		}
+
+		if (onBedRest(PC)) {
+			// One would assume that the player will realize that being unmovable/trapped also means they are more or less on bed rest.
+			if (isInduced(PC)) {
+				r.push(`<span class="hindrance high">You are on bed rest,</span> getting ready to give birth, so you are a little too preoccupied to focus on anything else at the moment.`);
+			} else if (PC.preg > PC.pregData.normalBirth / 1.05 && PC.pregControl !== "labor suppressors") {
+				r.push(`You're past your due date and having contractions, so until you give birth, you'll be <span class="hindrance high">staying in bed</span> and focusing on that over anything else.`);
+			} else if (PC.majorInjury > 0) {
+				r.push(`<span class="hindrance high">You are on mandatory bed rest due to serious injury.</span> You won't be able to do much until your body recovers.`);
+			} else if (PC.health.condition < -90) {
+				r.push(`<span class="hindrance high">You are on mandatory bed rest due to your poor health.</span> You won't be doing much other than sleeping until you recover.`);
+			} else if ((PC.womb.find((ft) => ft.genetics.geneticQuirks.polyhydramnios === 2 && ft.age >= 20)) || (PC.bellyPreg >= PC.pregAdaptation * 2200)) {
+				r.push(`<span class="hindrance high">You are on bed rest</span> in an attempt to not further complicate your already troublesome pregnancy. While it is not compulsory, it does cut into both your work and play time.`);
+			}
+		}
+	}
+
+	function muscularAtrophy() {
+		if (!isMovable(PC)) {
+			if (PC.muscles > -80) {
+				r.push(`Being bedbound takes its toll on your musculature, as what limited, awkward movements you are capable of can do little to sustain it.`);
+				if (PC.muscles > 5) {
+					r.push(`You <span class="change negative">lose some muscle definition.</span>`);
+					PC.muscles -= 2;
+				} else {
+					r.push(`What's left of your <span class="change negative">muscles steadily atrophy.</span>`);
+					PC.muscles--;
+				}
+			}
+		} else if (onBedRest(PC, true)) {
+			if (PC.health.shortDamage >= 50 || PC.health.condition < -90) {
+				r.push(`Stuck completely unable to move, your <span class="change negative">muscles rapidly atrophy.</span>`);
+				PC.muscles -= 3;
+			} else if (PC.muscles > 5) {
+				r.push(`Without proper maintenance, your <span class="change negative">muscles slowly soften.</span>`);
+				PC.muscles--;
+			}
+		} else if (!canWalk(PC) && PC.diet !== "muscle building") {
+			if (PC.muscles.isBetween(-80, 6)) {
+				r.push(`Without any muscle definition to maintain, and an electric wheelchair alleviating most of the effort of getting around, your unused <span class="change negative">muscles slowly atrophy.</span>`);
+			}
+		}
+	}
+
+	function bodyAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.physicalImpairment !== 0) {
+				r.push(`Due to the lasting effects of your injuries, any exertion you undertake requires plenty of rest afterward. Understandably, <span class="hindrance mid">this limits how much you can get done in a day.</span>`);
+			}
+			if (PC.weight >= 130 || (PC.weight >= 95 + ((PC.physicalAge - 9) * 5))) {
+				r.push(`You're so overweight that any <span class="hindrance low">physical activity needs to be followed by a breather</span> and a little snack to get your energy back.`);
+			}
+			if (PC.muscles > 95 && PC.height <= (Height.mean(PC) + 10)) {
+				r.push(`Your frame is inadequate to properly support your musculature, <span class="hindrance low">limiting your range of motion.</span> Frankly, this hinders you more in the gym than it does your other work.`);
+			} else if (PC.muscles < -30) {
+				r.push(`You're physically frail and can't do too much without having to stop and get your strength back, <span class="hindrance low">limiting how much you can accomplish in a day.</span>`);
+			}
+		}
+	}
+
+	function hugeBreasts() {
+		if (canWalk(PC) && !(onBedRest(PC, true))) {
+			if (PC.physicalAge >= 18) {
+				if (PC.boobs > 25000) {
+					if (PC.muscles <= 30) {
+						r.push(`Your giant tits are debilitatingly big and exceedingly heavy. It's difficult to keep yourself from hunching forward while standing and slouching while sitting, so you often find your back <span class="health dec">rather sore</span> by evening.`);
+						healthDamage(PC, 2);
+					} else {
+						r.push(`Your giant tits are debilitatingly big, but you know how to properly manage them. Needless to say, you do a lot of back exercises.`);
+					}
+				} else if (PC.boobs > 10000) {
+					if (PC.muscles <= 5) {
+						r.push(`Your huge boobs are troublesome for your slight form; your back is often quite <span class="health dec">sore</span> by evening.`);
+						healthDamage(PC, 1);
+					} else {
+						r.push(`Some people would say boobs as huge as yours would be uncomfortable, but with proper exercise and support, their weight is no trouble at all.`);
+					}
+				} else if (PC.boobs > 4000) {
+					if (PC.muscles <= 5) {
+						r.push(`The weight of your big boobs is a little uncomfortable, but nothing you can't handle.`);
+					}
+				}
+			} else if (PC.physicalAge > 12) {
+				if (PC.boobs > 15000) {
+					if (PC.muscles <= 50) {
+						r.push(`Your giant tits are debilitatingly big and exceedingly heavy. Your youthful body can barely keep upright with them, and by day's end, your <span class="health dec">back aches</span> considerably.`);
+						healthDamage(PC, 2);
+					} else {
+						r.push(`Your giant tits are debilitatingly big, but you know how to properly manage them; your back muscles are ripped, to say the least.`);
+					}
+				} else if (PC.boobs > 7500) {
+					if (PC.muscles <= 30) {
+						r.push(`Your huge boobs are troublesome for your youthful body; your back is often quite <span class="health dec">sore</span> by evening.`);
+						healthDamage(PC, 1);
+					} else {
+						r.push(`Some people say huge boobs on a young ${girlP} like you must be uncomfortable, but with proper support and plenty of back exercise, their weight doesn't bother you at all.`);
+					}
+				} else if (PC.boobs > 3000) {
+					if (PC.muscles <= 5) {
+						r.push(`The weight of your big boobs is a little uncomfortable, but nothing you can't handle.`);
+					}
+				}
+			} else {
+				if (PC.boobs > 10000) {
+					if (PC.muscles <= 95) {
+						r.push(`Your enormous tits are nearly crippling you; your childish body just can't support that much weight hanging from your chest. You savor every moment you get to rest them on something and take the strain off your back, but each morning you still wake up with a <span class="health dec">variety of aches and pains.</span>`);
+						healthDamage(PC, 3);
+					} else {
+						r.push(`As a preteen ${girlP} with a pair of enormous boobs wobbling from ${hisP} chest, you catch a lot of stares and the occasional comment over how much pain your back must be in. A simple flex of your muscles tends to quell those worries quickly enough.`);
+					}
+				} else if (PC.boobs > 8000) {
+					if (PC.muscles <= 50) {
+						r.push(`Your giant tits are debilitatingly big and exceedingly heavy for your childish body. You can barely keep upright with them, and by day's end, your <span class="health dec">back aches</span> considerably from carrying them around.`);
+						healthDamage(PC, 2);
+					} else {
+						r.push(`Your giant tits are debilitatingly big for your preteen body, but you know how to properly carry them; your back muscles are ripped, to say the least.`);
+					}
+				} else if (PC.boobs > 5000) {
+					if (PC.muscles <= 30) {
+						r.push(`Your huge boobs are troublesome for your childish body; your back is often quite <span class="health dec">sore</span> by evening.`);
+						healthDamage(PC, 1);
+					} else {
+						r.push(`As a preteen ${girlP} with boobs bigger than ${hisP} head, you get a lot of comments about how they'll ruin your back, but with proper support and a muscular back, you're doing just fine.`);
+					}
+				} else if (PC.boobs > 2000) {
+					if (PC.muscles <= 5) {
+						r.push(`Your big boobs are uncomfortably heavy for your childish body, but a little back pain is nothing you can't handle.`);
+					}
+				}
+			}
+		}
+	}
+
+	function boobAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.boobs > 5000) {
+				r.push(`Your breasts tend to <span class="hindrance low">get in the way when conducting business;</span> using a tablet is awkward, you smother traditional keyboards, video calls have to be adjusted around your bust, and that's not even to mention the trouble of carrying out your daily affairs throughout the arcology.`);
+				if (V.boobAccessibility === 1) {
+					r.push(`Luckily, the penthouse has been adapted for life with gigantic boobs, so you feel right at home.`);
+				} else if (PC.boobs > 25000) {
+					r.push(`Life at home is no better:`);
+					if (V.buttAccessibility === 1 || V.pregAccessibility === 1 || V.ballsAccessibility === 1) {
+						r.push(`the appliances are always out of reach, the furniture tough to get out of, and things are the perfect height to jab you right in the tits. At least the doors are wide enough for you to get through.`);
+					} else {
+						r.push(`the appliances are always out of reach, the furniture tough to get out of, things are the perfect height to jab you right in the tits, and you cause traffic just trying to move between rooms.`);
+					}
+				}
+			}
+		}
+	}
+
+	function hugeBelly() {
+		let resting = onBedRest(PC) ? 2 : 1;
+		let RCGmod = 1 + PC.geneMods.rapidCellGrowth;
+		if (PC.belly > (PC.pregAdaptation * 4500)) {
+			r.push(`You may have made a mistake; your bloated`);
+			if (PC.mpreg === 0 && PC.ovaries === 0) {
+				r.push(`implant-filled middle`);
+			} else {
+				r.push(`womb`);
+			}
+			r.push(`is under immense strain and puts <span class="health dec">overwhelming pressure on your skin and organs.</span> It's turned black and blue from the tension and the deep stretch marks are truly worrying.`);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2 && PC.preg > 0) {
+				r.push(`You're trapped in a constant state of mixed pleasure and pain,`);
+				if (V.geneticMappingUpgrade >= 1) {
+					r.push(`thanks to your uterine hypersensitivity,`);
+				}
+				r.push(`making it difficult to focus on anything other than orgasming.`);
+			} else {
+				r.push(`The pain is excruciating, and each`);
+				if (PC.bellyPreg > 100) {
+					r.push(`movement within you`);
+				} else {
+					r.push(`breath`);
+				}
+				r.push(`feels like it could force you to burst.`);
+			}
+			healthDamage(PC, 30, 2);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2) {
+				PC.pregAdaptation += 5 * RCGmod;
+			} else {
+				PC.pregAdaptation += 1 * RCGmod;
+			}
+		} else if (PC.belly > (PC.pregAdaptation * 3200)) {
+			r.push(`You may have overdone it a little; your`);
+			if (PC.mpreg === 0 && PC.ovaries === 0) {
+				r.push(`implant filled abdominal cavity`);
+			} else {
+				r.push(`straining womb`);
+			}
+			r.push(`takes up all the available space in your body, putting <span class="health dec">tremendous pressure on your skin and crushing your organs.</span>`);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2 && PC.preg > 0) {
+				if (V.geneticMappingUpgrade >= 1) {
+					r.push(`Your uterine hypersensitivity renders it extremely pleasurable, often forcing you to become lost in playing with your belly.`);
+				} else {
+					r.push(`The uncanny way you rub, tease and grab at your belly, even in public, is becoming rather disturbing to people.`);
+				}
+			} else {
+				r.push(`You feel a distinct, stabbing pain alongside`);
+				if (PC.bellyPreg > 100) {
+					r.push(`each movement inside you;`);
+				} else {
+					r.push(`each breath;`);
+				}
+				r.push(`your body can't take much more of this.`);
+			}
+			healthDamage(PC, 20);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2) {
+				PC.pregAdaptation += 4 * RCGmod;
+			} else {
+				PC.pregAdaptation += .4 * RCGmod;
+			}
+		} else if (PC.belly > (PC.pregAdaptation * 2000)) {
+			r.push(`Your body cavity is completely filled by your`);
+			if (PC.mpreg === 0 && PC.ovaries === 0) {
+				r.push(`belly implant,`);
+			} else {
+				r.push(`womb,`);
+			}
+			r.push(`<span class="health dec">putting pressure on your skin and organs.</span>`);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2 && PC.preg > 0) {
+				if (V.geneticMappingUpgrade >= 1) {
+					r.push(`The pleasure derived from your uterine hypersensitivity completely masks any discomfort.`);
+				} else {
+					r.push(`The pressure makes you really horny for some reason.`);
+				}
+			} else {
+				r.push(`It's really uncomfortable, but mostly limited to when`);
+				if (PC.bellyPreg > 100) {
+					r.push(`your babies are active.`);
+				} else {
+					r.push(`you have to move.`);
+				}
+			}
+			healthDamage(PC, (10 / resting));
+			if (PC.geneticQuirks.uterineHypersensitivity === 2) {
+				PC.pregAdaptation += 3 * RCGmod;
+			} else {
+				PC.pregAdaptation += .3 * RCGmod;
+			}
+		} else if (PC.belly > (PC.pregAdaptation * 1000)) {
+			r.push(`Your body is filled by your`);
+			if (PC.mpreg === 0 && PC.ovaries === 0) {
+				r.push(`belly implant,`);
+			} else {
+				r.push(`womb,`);
+			}
+			r.push(`<span class="health dec">compressing your internal organs.</span>`);
+			if (PC.geneticQuirks.uterineHypersensitivity === 2 && PC.preg > 0) {
+				if (V.geneticMappingUpgrade >= 1) {
+					r.push(`Your uterine hypersensitivity renders having such a stretched womb rather enjoyable.`);
+				} else {
+					r.push(`It feels pretty good, in fact.`);
+				}
+			} else {
+				r.push(`There's no way to get comfortable around it, so all you can do is bear it.`);
+			}
+			healthDamage(PC, (2 / resting));
+			if (PC.geneticQuirks.uterineHypersensitivity === 2) {
+				PC.pregAdaptation += 2 * RCGmod;
+			} else {
+				PC.pregAdaptation += .2 * RCGmod;
+			}
+		} else if (PC.belly > (PC.pregAdaptation * 750)) {
+			if (PC.geneticQuirks.uterineHypersensitivity === 2) {
+				PC.pregAdaptation += 1 * RCGmod;
+			} else {
+				PC.pregAdaptation += .1 * RCGmod;
+			}
+		}
+		if (PC.wombImplant === "restraint" && PC.belly >= 400000) {
+			r.push(`The mesh implanted into the walls of your uterus is nearing its limit and <span class="health dec">beginning to strangle</span> the organ it is meant to support. While it is still structurally sound, it may fail on you if it is forced to stretch much more.`);
+			healthDamage(PC, 15, 2);
+		}
+
+		/* body inconvenience */
+		if (canWalk(PC) && !(onBedRest(PC, true))) {
+			const belly = bellyAdjective(PC);
+			if (PC.physicalAge >= 18) {
+				if (PC.belly >= 300000) {
+					r.push(`Your ${belly} belly is debilitatingly large; waddling around is a challenge, and you need to take things extra slow to make sure you don't accidentally bump into anything.`);
+				} else if (PC.belly >= 150000) {
+					r.push(`Your ${belly} belly is troublesome; each step is slow and ponderous, and you have to be careful not to accidentally drive the bulbous mass into anything.`);
+				} else if (PC.belly >= 75000) {
+					r.push(`Your ${belly} belly juts out heavily from your frame, messing with your sense of balance and leaving you second guessing what you can fit through.`);
+				}
+			} else if (PC.physicalAge > 12) {
+				if (PC.belly >= 300000) {
+					r.push(`Your ${belly} belly constantly threatens to drag you to the floor, which would be nice to take the weight off your teenage body, but would also mean you'd need help getting back to your feet.`);
+				} else if (PC.belly >= 200000) {
+					r.push(`Your ${belly} belly is debilitatingly large on your teenage body; waddling around is a challenge, and you need to take things extra slow to make sure you don't accidentally bump into anything.`);
+				} else if (PC.belly >= 80000) {
+					r.push(`Your ${belly} belly is troublesome for your teenage body; each step is slow and ponderous, and you have to be careful not to accidentally drive the bulbous mass into anything.`);
+				} else if (PC.belly >= 30000) {
+					r.push(`Your ${belly} belly juts out heavily from your teenage frame, messing with your sense of balance and just how big you actually are.`);
+				}
+			} else {
+				if (PC.belly >= 200000) {
+					r.push(`Your ${belly} belly is overwhelming on your immature body. You really would like to let it rest on the floor and take its weight off you, but then you'd need help getting back upright.`);
+				} else if (PC.belly >= 120000) {
+					r.push(`Your ${belly} belly is debilitatingly large on your immature body; you can barely waddle at all, and you need to take things extra slow since it blocks you from seeing the floor ahead of you.`);
+				} else if (PC.belly >= 60000) {
+					r.push(`Your ${belly} belly is troublesome for your immature body; each step is slow and ponderous, and you have to be careful not to accidentally drive the bulbous mass into anything.`);
+				} else if (PC.belly >= 30000) {
+					r.push(`Your ${belly} belly juts out heavily from your juvenile frame, messing with your sense of balance and making you feel absolutely enormous.`);
+				}
+			}
+		}
+	}
+
+	function bellyAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.belly >= 60000 || PC.belly >= 60000 / (1 + Math.pow(Math.E, -0.4 * (PC.physicalAge - 14))) || PC.belly >= Math.max(10000, ((12500 / 19) * PC.height) - (1172500 / 19))) {
+				r.push(`Your middle <span class="hindrance low">gets in the way of your typical routine;</span> it's tough to get comfortable, you have to dress around it if you don't want to look like a harlot, and it takes way more effort than it ever should to sit at any sort of furniture.`);
+				if (V.pregAccessibility === 1) {
+					r.push(`Good thing the penthouse has been adapted for heavily pregnant life, alleviating most of your concerns, so long as you don't need to leave it.`);
+				} else if (PC.belly >= 100000) {
+					r.push(`Homelife is full of frustrations too:`);
+					if (V.buttAccessibility === 1 || V.boobAccessibility === 1 || V.ballsAccessibility === 1) {
+						r.push(`appliances are most easily reached sideways, you've gotten stuck sitting down, and one too many corners have made contact with your sensitive bump. At least there's plenty of room to maneuver in the halls.`);
+					} else {
+						r.push(`appliances are most easily reached sideways, you've gotten stuck sitting down, one too many corners have made contact with your sensitive bump, and slaves keep getting stuck behind you in the halls.`);
+					}
+				}
+			}
+		}
+	}
+
+	function hugeDick() {
+		if (canWalk(PC) && !(onBedRest(PC, true))) {
+			const dickLength = dickToCM(PC.dick);
+			if (dickLength >= ((PC.height / 2) + 30)) {
+				r.push(`Left unrestrained, your enormous penis rests on the ground, even while standing. It's easy to manage at least, though that probably wouldn't be the case if you became erect.`);
+			} else if (dickLength >= (PC.height / 2)) {
+				r.push(`When left hanging, your cockhead grazes the ground as you stand. It's easy to manage,`);
+				if (canAchieveErection(PC)) {
+					r.push(`though erections complicate things a bit; if you get too hard, there's no way you can contain it, and`);
+					if (PC.belly >= 100000) {
+						r.push(`it ends up painfully trapped under your belly until you deal with it.`);
+					} else if (PC.weight > 130) {
+						r.push(`it inadvertently presses against your gut. Attending a business meeting is pretty risky when every motion pushes your self-inflicted bellyfuck closer to completion.`);
+					} else if (PC.boobs >= 300) {
+						r.push(`you end up inadvertently giving yourself a titfuck. Attending a business meeting coated in your own load doesn't make you look good.`);
+					} else {
+						r.push(`you're stuck with your own dick prodding your face until you deal with it.`);
+					}
+				} else {
+					r.push(`all things considered, though you doubt that would be the case if you could get erect.`);
+				}
+			} else if (dickLength >= (PC.height / 4)) {
+				r.push(`When let loose, your cockhead hangs past your knees. It may get in the way at times, but attention your bulge gets makes it all worthwhile.`);
+			}
+		}
+	}
+
+	function dickAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.dick >= 20) {
+				if (V.dickAccessibility === 1) {
+					r.push(`It was a good move having your living space redesigned around enormous dicks; taking a piss should never be that complicated.`);
+				} else {
+					r.push(`The penthouse itself is tolerable to live in with your cock, but the bathrooms are an unspeakable horror, for both yourself and the slaves that have to clean them.`);
+				}
+			}
+		}
+	}
+
+	function hugeBalls() {
+		if (canWalk(PC) && !(onBedRest(PC, true))) {
+			const estimatedSackSag= ballsToCM(PC.balls) * .8 * (1 + ((PC.scrotum - PC.balls) * .5)); // Oval shape + scrotal sag
+			if (estimatedSackSag > (PC.height / 2)) {
+				r.push(`Your titanic balls never leave the floor, even when standing, unless you make an effort to lift them yourself. Once they're situated, getting around isn't too bad, though they are pretty heavy.`);
+			} else if (estimatedSackSag >= (PC.height / 2) - 10) {
+				r.push(`Your enormous balls hang down to the floor when you stand, and rest on it when you sit. You can get around with some sturdy supports, but you might need a cart soon.`);
+			} else if (estimatedSackSag >= (PC.height / 4)) {
+				r.push(`Your huge balls hang past your knees when you stand. Having them bouncing around while walking usually results in you kneeing yourself in the nuts, so supportive underwear is a must when touring your domain.`);
+			}
+		}
+	}
+
+	function ballsAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.balls >= 14) {
+				r.push(`It <span class="hindrance low">takes extra time to get anywhere</span> carrying a sack like yours around, limiting the number of potential places you can be in a day, and seating is often an issue with them in the way.`);
+				if (V.ballsAccessibility === 1) {
+					r.push(`You never have to deal with that in the penthouse after having refitted for the comfort of those with sizable testicles.`);
+				} else if (PC.balls >= 50) {
+					r.push(`The latter issue follows you back to the penthouse, giving you no real place to relax and unwind; the number of rotations you need to do in the bathroom is irritating.`);
+					if (V.buttAccessibility === 1 || V.pregAccessibility === 1 || V.boobAccessibility === 1) {
+						r.push(`At least there is plenty of room to maneuver, due to the other structural renovations you've had done.`);
+					} else {
+						r.push(`You are also starting to become painfully aware of just how wide the doorframes are compared to you.`);
+					}
+				}
+			}
+		}
+	}
+
+	function hugeHips() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.hips > 2) {
+				r.push(`Your inhumanly wide hips <span class="hindrance low">frequently get in the way</span> as your try to work and conduct business.`);
+			}
+		}
+	}
+
+	function hugeButt() {
+		if (canWalk(PC) && !(onBedRest(PC, true))) {
+			if (PC.butt > 10) {
+				r.push(`Your butt is a wonderful burden; it fills out whatever you wear, but also is a real pain to dress around, and then there is the looming chance of getting chairs stuck around it when you sit down. It also substantially juts out from you, leading to a tendency of accidentally bumping people with it as you walk by; more than one person has taken this as an invitation to give it a good feel.`);
+			}
+		}
+	}
+
+	function buttAccessibility() {
+		if (isMovable(PC) && !(onBedRest(PC, true))) {
+			if (PC.butt > 6) {
+				r.push(`Your rear <span class="hindrance low">slows you down considerably,</span> and you have to plan ahead of time where to meet people to avoid any embarrassing situations involving it.`);
+				if (V.buttAccessibility === 1) {
+					r.push(`You're free from any of those concerns in the penthouse, so long as your slaves know how to get out of your junk filled trunk's way.`);
+				} else if (PC.butt > 15) {
+					r.push(`Too bad the same can't be said for the penthouse; chairs constantly follow you when you try to leave them, you're always trying to avoid knocking things over,`);
+					if (V.boobAccessibility === 1 || V.pregAccessibility === 1 || V.ballsAccessibility === 1) {
+						r.push(`but your ass has the clearance it demands due to the widened doors and halls.`);
+					} else {
+						r.push(`and you swear it is impossible to get anywhere without bouncing off door frames, walls, and bewildered slaves.`);
+					}
+				}
+			}
+		}
+	}
+
+	function hindrance() {
+		const degree = isHinderedDegree(PC);
+
+		if (degree !== 1 && !onBedRest(PC, true)) {
+			r.push(`Overall,`);
+			if (onBedRest(PC)) {
+				r.push(`<span class="hindrance high">you're pretty limited,</span> but since you're working from bed, that's to be expected.`);
+			} else if (degree <= .3) {
+				r.push(`your body is <span class="hindrance max">a crippling hindrance to you.</span> It may be better to stop trying to live a normal life and just keep growing until you can no longer leave your bed; this way you'll never be expected to do things outside the penthouse and can work around your body.`);
+			} else if (degree <= .5) {
+				r.push(`your body is <span class="hindrance high">a major hindrance to you.</span>`);
+			} else if (degree <= .7) {
+				r.push(`your body is <span class="hindrance mid">a hindrance to you.</span>`);
+			} else {
+				r.push(`your body is only a <span class="hindrance low">minor hindrance.</span>`);
+			}
+		}
+	}
+};
diff --git a/src/endWeek/player/prPregnancy.js b/src/endWeek/player/prPregnancy.js
index 40e78c80fe0cda3a06239402296cc2c953a47b51..eceaf20e7065684e97a4636a63407553f4608d2e 100644
--- a/src/endWeek/player/prPregnancy.js
+++ b/src/endWeek/player/prPregnancy.js
@@ -269,6 +269,7 @@ App.EndWeek.Player.pregnancy = function(PC = V.PC) {
 
 	function pregnancyPhysicalEffects() {
 		let boobTarget;
+		const slimnessFoodMod = (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(PC)) ? 0.5 : 1;
 		if (PC.geneMods.NCS === 1) {
 			// NCS: always working against secondary sexual characteristics even in pregnancies.
 			boobTarget = 0;
@@ -322,6 +323,7 @@ App.EndWeek.Player.pregnancy = function(PC = V.PC) {
 			}
 		}
 		boobTarget *= gigantomastiaMod;
+		boobTarget *= slimnessFoodMod;
 		if (PC.geneMods.NCS === 0) {
 			if (PC.pregType >= 30) {
 				if (PC.weight <= 65) {
@@ -381,6 +383,16 @@ App.EndWeek.Player.pregnancy = function(PC = V.PC) {
 				PC.butt += 1;
 			}
 		}
+		if (PC.preg > PC.pregData.normalBirth / 1.42 && PC.vagina >= 0 && PC.vaginaLube < 1 && PC.energy > 20 && random(1, 100) > 80) {
+			r.push(`You heard sex tends to be a little wet during pregnancy, and you now know why;`);
+			if (random(1, 100) > 75) {
+				r.push(`your <span class="change positive">pussy has gotten really moist.</span>`);
+				PC.vaginaLube += 1;
+			} else {
+				r.push(`your pussy <span class="change positive">liberally soaks you, your partner, and your surroundings</span> during any sort of intimacy.`);
+				PC.vaginaLube += 2;
+			}
+		}
 		if (PC.preg === PC.pregData.normalBirth / 2.66) { // change me when nipple color gets hardset
 			if (PC.pregKnown === 0) {
 				r.push(`Your areolae have gotten dark. Some cursory tests reveal <span class="pregnant">you are about fifteen weeks pregnant.</span> How did that manage to slip past you?`);
diff --git a/src/endWeek/reports/arcadeReport.js b/src/endWeek/reports/arcadeReport.js
index 8c6bb588bbc50948b1a3605434b12cf1cfde5f12..ac525bb6afbfc9bf1df9480c28e54f4e80a426aa 100644
--- a/src/endWeek/reports/arcadeReport.js
+++ b/src/endWeek/reports/arcadeReport.js
@@ -85,17 +85,9 @@ App.EndWeek.arcadeReport = function() {
 		const oldCash = V.cash;
 		if (V.showEWD !== 0) {
 			const {He} = getPronouns(slave);
-			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			r = [];
-			r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-			if (slave.choosesOwnAssignment === 2) {
-				r.push(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				r.push(`is confined in ${V.arcadeName}.`);
-			}
-			App.Events.addNode(slaveEntry, r);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is confined in ${V.arcadeName}.`));
 
 			App.Events.addNode(
 				slaveEntry,
@@ -109,7 +101,6 @@ App.EndWeek.arcadeReport = function() {
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.workAGloryHole(slave);
 		}
 		profits += V.cash - oldCash;
diff --git a/src/endWeek/reports/brothelReport.js b/src/endWeek/reports/brothelReport.js
index 3713800278ac40aa075f885cb00d3eac16edd938..f35c44f06324b64de1a45e6fb928056ec2ef24aa 100644
--- a/src/endWeek/reports/brothelReport.js
+++ b/src/endWeek/reports/brothelReport.js
@@ -63,7 +63,11 @@ App.EndWeek.brothelReport = function() {
 			} = getPronouns(S.Madam);
 
 			r = [];
-			r.push(`${SlaveFullName(S.Madam)} is serving as the madam.`);
+			const popup = App.UI.DOM.referenceSlaveWithPreview(S.Madam, SlaveFullName(S.Madam));
+
+			popup.classList.add("slave-name", "bold");
+			r.push(popup, `is serving as the madam.`);
+
 			if (S.Madam.relationship === -3 && S.Madam.devotion > 50) {
 				r.push(`As your loving ${wife}, ${he} does ${his} best to attract attention to your brothel.`);
 			}
@@ -262,17 +266,10 @@ App.EndWeek.brothelReport = function() {
 
 	if (madam) {
 		tired(madam);
-		if (V.showEWD !== 0) {
-			const madamEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+		if (V.showEWD) {
+			const madamEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", madamEntry);
-			App.SlaveAssignment.appendSlaveLinks(madamEntry, madam);
-			App.Events.addNode(
-				madamEntry,
-				[
-					App.UI.DOM.makeElement("span", SlaveFullName(madam), "slave-name"),
-					`is serving as the Madam.`
-				]
-			);
+			madamEntry.append(App.SlaveAssignment.saSlaveIntro(madam, `is serving as the Madam.`));
 			madamEntry.append(App.SlaveAssignment.standardSlaveReport(madam, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, madam);
 		} else {
@@ -327,19 +324,11 @@ App.EndWeek.brothelReport = function() {
 				slave.energy++;
 			}
 
-			if (V.showEWD !== 0) {
+			if (V.showEWD) {
 				const {He} = getPronouns(slave);
-				const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+				const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 				const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-				App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-				r = [];
-				r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-				if (slave.choosesOwnAssignment === 2) {
-					r.push(App.SlaveAssignment.choosesOwnJob(slave));
-				} else {
-					r.push(`is working out of ${V.brothelName}.`);
-				}
-				App.Events.addNode(slaveEntry, r);
+				slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is working out of ${V.brothelName}.`));
 
 				App.Events.addNode(
 					slaveEntry,
@@ -354,7 +343,6 @@ App.EndWeek.brothelReport = function() {
 				App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 			} else {
 				// discard return values silently
-				App.SlaveAssignment.choosesOwnJob(slave);
 				App.SlaveAssignment.whore(slave);
 				App.SlaveAssignment.standardSlaveReport(slave, true);
 			}
diff --git a/src/endWeek/reports/cellblockReport.js b/src/endWeek/reports/cellblockReport.js
index cb063ff01ffec5dcbd7cfc7df7304ae87ad3bfb5..131fad1448a12fbb9a9d09cf7cf8f56ad786009d 100644
--- a/src/endWeek/reports/cellblockReport.js
+++ b/src/endWeek/reports/cellblockReport.js
@@ -3,7 +3,7 @@
  */
 App.EndWeek.cellblockReport = function() {
 	const el = new DocumentFragment();
-	let r;
+	let r = [];
 
 	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.cellblock);
 	let brokenSlaves = 0;
@@ -67,7 +67,10 @@ App.EndWeek.cellblockReport = function() {
 			trustMalus++;
 			idleBonus++;
 		}
-		r.push(`${SlaveFullName(S.Wardeness)} is serving as the Wardeness.`);
+		const popup = App.UI.DOM.slaveDescriptionDialog(S.Wardeness, SlaveFullName(S.Wardeness));
+		popup.classList.add("slave-name", "bold");
+		r.push(popup, `is serving as the Wardeness.`);
+
 		if (S.Wardeness.relationship === -3 && S.Wardeness.devotion > 50) {
 			devBonus++;
 			trustMalus++;
@@ -179,14 +182,7 @@ App.EndWeek.cellblockReport = function() {
 		if (V.showEWD !== 0) {
 			const wardenessEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
 			const artSpan = App.UI.DOM.appendNewElement("span", wardenessEntry);
-			App.SlaveAssignment.appendSlaveLinks(wardenessEntry, slave);
-			App.Events.addNode(
-				wardenessEntry,
-				[
-					App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"),
-					`is serving as the Wardeness in ${V.cellblockName}.`,
-				]
-			);
+			wardenessEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as the Wardeness in ${V.cellblockName}.`));
 			wardenessEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -296,18 +292,10 @@ App.EndWeek.cellblockReport = function() {
 			improveCondition(slave, 3);
 		}
 
-		if (V.showEWD !== 0) {
-			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+		if (V.showEWD) {
+			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			r = [];
-			r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-			if (slave.choosesOwnAssignment === 2) {
-				r.push(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				r.push(`is confined in ${V.cellblockName}.`);
-			}
-			App.Events.addNode(slaveEntry, r);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is confined in ${V.cellblockName}.`));
 
 			confinedResults = App.SlaveAssignment.stayConfined(slave);
 			App.Events.addNode(slaveEntry, [He, confinedResults.text], "div", "indent");
@@ -319,7 +307,6 @@ App.EndWeek.cellblockReport = function() {
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			confinedResults = App.SlaveAssignment.stayConfined(slave);
 			if (confinedResults.broken) {
 				brokenSlaves++;
diff --git a/src/endWeek/reports/childrenReport.js b/src/endWeek/reports/childrenReport.js
index 7785b082a0be98b343ff73a1544df77f292e92c5..ccc9f7411f05e75e6f6d90b7b5d6d8a59cc2f004 100644
--- a/src/endWeek/reports/childrenReport.js
+++ b/src/endWeek/reports/childrenReport.js
@@ -14,7 +14,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 	const medianNannyIntelligenceImplant = NL ? findMedianNannyIntelligenceImplant() : null;
 
 	for (const child of V.cribs) {
-		const childDiv = App.UI.DOM.appendNewElement("div", frag, '', "child-section");
+		const childDiv = App.UI.DOM.appendNewElement("div", frag, '', ["child-section"]);
 
 		childDiv.append(childGrowTime(child));
 
@@ -25,7 +25,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				}
 
 				childDiv.append(matronEducationEffects(child));
-				// childDiv.append(matronFitnessEffects(child));
 			}
 
 			if (NL > 0) {
@@ -37,7 +36,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				}
 
 				childDiv.append(nannyEducationEffects(child));
-				// childDiv.append(nannyFitnessEffects(child));
 			}
 
 			if (multipleChildrenOverTargetAge(V.cribs.findIndex(c => c.ID === child.ID))) {
@@ -54,10 +52,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 		}
 	}
 
-
-
-	// MARK: Matron Effects
-
 	function matronFetishEffects(child) {
 		const chance = jsRandom(1, 100);
 
@@ -88,7 +82,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 			return `Though ${Matron.slaveName} has had little to no formal education, ${his} natural brilliance allows ${him} to teach ${theChildren} quite effectively, and so ${CL > 1 ? `they grow` : `${child.slaveName} grows`} a bit smarter. `;
 		} else {
 			const totalSpan = App.UI.DOM.makeElement("span", `${Matron.slaveName} isn't the brightest and not well educated, `);
-			const damageSpan = App.UI.DOM.makeElement("span", `damaging the amount of real education ${theChildren} receive. `, "red");
+			const damageSpan = App.UI.DOM.makeElement("span", `damaging the amount of real education ${theChildren} receive. `, ["red"]);
 
 			child.intelligenceImplant--;
 
@@ -98,15 +92,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 		}
 	}
 
-	// function matronFitnessEffects(child) {
-	// 	// TODO:
-	// 	return;
-	// }
-
-
-
-	// MARK: Nanny Effects
-
 	function nannyFetishEffects(child, slave) {
 		const {he} = getPronouns(child);
 		const chance = jsRandom(1, 100);
@@ -152,15 +137,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 		}
 	}
 
-	// function nannyFitnessEffects(child) {
-	// 	// TODO:
-	// 	return;
-	// }
-
-
-
-	// MARK: Nursery Rules Effects
-
 	function weightRulesEffects(child) {
 		// TODO: redo this entire section
 		// TODO: double check these classes, make sure they make sense
@@ -180,14 +156,14 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 
 				span.append(`${He} is being fed an excessive amount of food, causing`, weightSpan);
 			} else if (V.nurseryWeightSetting === 2) {
-				const weightSpan = App.UI.DOM.makeElement("span", `decreases the amount of food ${he} eats. `, "improvement");
+				const weightSpan = App.UI.DOM.makeElement("span", `decreases the amount of food ${he} eats. `, ["improvement"]);
 
 				if (child.weight > 10) {
 					child.weight--;
 
 					span.append(`${caretaker} notices ${he} is overweight and `, weightSpan);
 				} else if (child.weight <= -10) {
-					const weightSpan = App.UI.DOM.makeElement("span", `increases the amount of food ${he} eats. `, "improvement");
+					const weightSpan = App.UI.DOM.makeElement("span", `increases the amount of food ${he} eats. `, ["improvement"]);
 
 					child.weight++;
 
@@ -229,13 +205,12 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 			const caretaker = Matron ? Matron.slaveName : NL > 1 ? `A nanny` : firstNanny.slaveName;
 			const {His, He, he} = getPronouns(child);
 
-
-			const muscleSpan = App.UI.DOM.makeElement("div", 'rapid muscle development.', "improvement");
+			const muscleSpan = App.UI.DOM.makeElement("div", 'rapid muscle development.', ["improvement"]);
 
 			div.append(`${He} is being worked out as often as possible, resulting in `, muscleSpan);
 
 			if (V.nurseryMusclesSetting === 2) {
-				const muscleSpan = App.UI.DOM.makeElement("span", `decreases the amount of exercise ${he} receives. `, "improvement");
+				const muscleSpan = App.UI.DOM.makeElement("span", `decreases the amount of exercise ${he} receives. `, ["improvement"]);
 
 				if (child.muscles > 100) {
 					child.muscles -= 5;
@@ -244,7 +219,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				div.append(`${caretaker} notices ${he} is overly muscular and `, muscleSpan);
 			} else if (V.nurseryMusclesSetting === 1) {
 				if (child.muscles < -10) {
-					const muscleSpan = App.UI.DOM.makeElement("span", `increases the amount of exercise ${he} receives. `, "improvement");
+					const muscleSpan = App.UI.DOM.makeElement("span", `increases the amount of exercise ${he} receives. `, ["improvement"]);
 
 					child.muscles--;
 
@@ -273,10 +248,6 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 		return div;
 	}
 
-
-
-	// MARK: Miscellaneous Functions
-
 	function childFriendshipRivalries(child) {
 		const el = new DocumentFragment();
 		const cribsCopy = Array.from(V.cribs);
@@ -417,7 +388,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				case "pregnancy":
 					return `The idea of pregnancy titillates both ${child.slaveName} and ${target.slaveName}`;
 				default:
-					throw Error(`Unexpected value ${child.fetish} in sameFetish(). Please report this.`);
+					throw Error(`Unexpected .fetish value of "${child.fetish}" in sameFetish(). Please report this.`);
 			}
 		}
 
@@ -442,7 +413,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				case "advocate":
 					return `${child.slaveName} and ${target.slaveName} can both make a strong case for slavery`;
 				default:
-					throw Error(`Unexpected value ${child.behavioralQuirk} in sameBehavioralQuirk(). Please report this.`);
+					throw Error(`Unexpected .behavioralQuirk value of "${child.behavioralQuirk}" in sameBehavioralQuirk(). Please report this.`);
 			}
 		}
 
@@ -468,7 +439,7 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 				case "size queen":
 					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} have a love for huge cock`;
 				default:
-					throw Error(`Unexpected value ${child.fetish} in sameSexualQuirk(). Please report this.`);
+					throw Error(`Unexpected .sexualQuirk value of "${child.sexualQuirk}" in sameSexualQuirk(). Please report this.`);
 			}
 		}
 	}
@@ -494,13 +465,13 @@ App.Facilities.Nursery.childrenReport = function childrenReport() {
 			case "pregnancy":
 				return `has developed a fascination for all things pregnancy-related`;
 			default:
-				throw Error(`Unexpected fetish value of "${fetish}" in newChildFetish(). Please report this.`);
+				throw Error(`Unexpected .fetish value of "${fetish}" in newChildFetish(). Please report this.`);
 		}
 	}
 
 	function childGrowTime(child) {
-		const nameSpan = App.UI.DOM.makeElement("span", child.slaveName, "pink");
-		const limeSpan = App.UI.DOM.makeElement("span", 'ready for release.', "lime");
+		const nameSpan = App.UI.DOM.makeElement("span", child.slaveName, ["pink"]);
+		const limeSpan = App.UI.DOM.makeElement("span", 'ready for release.', ["lime"]);
 		const mainSpan = document.createElement("span");
 
 		const {He} = getPronouns(child);
diff --git a/src/endWeek/reports/clinicReport.js b/src/endWeek/reports/clinicReport.js
index 9d559ae2137250d01cf1992be2b7b0662478240c..884d2836e15e9aeb657b0142d4dd464b6f162c1a 100644
--- a/src/endWeek/reports/clinicReport.js
+++ b/src/endWeek/reports/clinicReport.js
@@ -256,10 +256,9 @@ App.EndWeek.clinicReport = function() {
 		tired(slave);
 		/* apply following SA passages to facility leader */
 		if (V.showEWD !== 0) {
-			const nurseEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+			const nurseEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", nurseEntry);
-			App.SlaveAssignment.appendSlaveLinks(nurseEntry, slave);
-			$(nurseEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> is serving as the clinical nurse.`);
+			nurseEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as the clinical nurse.`));
 			nurseEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -404,38 +403,33 @@ App.EndWeek.clinicReport = function() {
 		}
 
 		if (V.showEWD !== 0) {
-			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			$(slaveEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> `);
-			if (slave.choosesOwnAssignment === 2) {
-				$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				$(slaveEntry).append(`is receiving treatment in ${V.clinicName}.`);
-			}
-			const patientContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', "indent");
-			$(patientContent).append(`${He} ${App.SlaveAssignment.rest(slave)} `);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is receiving treatment in ${V.clinicName}.`));
+
+			let r = [];
+			r.push(He, App.SlaveAssignment.rest(slave));
 			if (remainReasons.length > 0) {
-				$(patientContent).append(`${He} stays in the clinic ${toSentence(remainReasons)}.`);
+				r.push(`${He} stays in the clinic ${toSentence(remainReasons)}.`);
 			}
+			App.Events.addNode(slaveEntry, r, "div", "indent");
 			slaveEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.rest(slave);
 			App.SlaveAssignment.standardSlaveReport(slave, true);
 		}
 	}
 
 	if (restedSlaves > 0) {
-		const rested = App.UI.DOM.appendNewElement("p", frag, '', "indent");
+		const rested = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
 		rested.append((restedSlaves === 1) ? `One slave has` : `${restedSlaves} slaves have`, " been returned to ");
 		App.UI.DOM.appendNewElement("span", rested, `health${(S.Nurse && V.clinicUpgradeFilters > 0) ? ' and purity' : ''}`, "green");
 		rested.append(` and will be released from the clinic before the end of the week.`);
 
 		if (V.clinicDecoration !== "standard") {
-			const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
+			const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
 			$(decorationEffects).append(`${capFirstChar(V.clinicName)}'s ${V.clinicDecoration} atmosphere <span class="hotpink">had an impact on them</span> while they were getting treatment.`);
 		}
 	}
diff --git a/src/endWeek/reports/clubReport.js b/src/endWeek/reports/clubReport.js
index acd6bdcef368c86ab7fe3cbe1c09ad8e4adce2a1..c491aa5b064ed43b4020982742aa32fbbe312b2b 100644
--- a/src/endWeek/reports/clubReport.js
+++ b/src/endWeek/reports/clubReport.js
@@ -145,16 +145,9 @@ App.EndWeek.clubReport = function() {
 		tired(dj);
 		/* apply following SA passages to facility leader */
 		if (V.showEWD !== 0) {
-			const DJEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			const DJEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", DJEntry);
-			App.SlaveAssignment.appendSlaveLinks(DJEntry, dj);
-			App.Events.addNode(
-				DJEntry,
-				[
-					App.UI.DOM.makeElement("span", SlaveFullName(dj), "slave-name"),
-					`is performing as the DJ in ${V.clubName}.`,
-				]
-			);
+			DJEntry.append(App.SlaveAssignment.saSlaveIntro(dj, `is performing as the DJ in ${V.clubName}.`));
 			DJEntry.append(App.SlaveAssignment.standardSlaveReport(dj, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, dj);
 		} else {
@@ -191,18 +184,10 @@ App.EndWeek.clubReport = function() {
 				slave.rules.living = "normal";
 			}
 
-			if (V.showEWD !== 0) {
-				const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			if (V.showEWD) {
+				const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 				const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-				App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-				r = [];
-				r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-				if (slave.choosesOwnAssignment === 2) {
-					r.push(App.SlaveAssignment.choosesOwnJob(slave));
-				} else {
-					r.push(`is serving in ${V.clubName}.`);
-				}
-				App.Events.addNode(slaveEntry, r);
+				slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving in ${V.clubName}.`));
 
 				const {He} = getPronouns(slave);
 				App.Events.addNode(
@@ -218,7 +203,6 @@ App.EndWeek.clubReport = function() {
 				App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 			} else {
 				// discard return values silently
-				App.SlaveAssignment.choosesOwnJob(slave);
 				App.SlaveAssignment.serveThePublic(slave);
 				App.SlaveAssignment.standardSlaveReport(slave, true);
 			}
diff --git a/src/endWeek/reports/dairyReport.js b/src/endWeek/reports/dairyReport.js
index 7cb56b5d6c2c7af2af608eb31eb7f0071b071db6..90e28bff17a031561e27457cecd89fc0a03ccae0 100644
--- a/src/endWeek/reports/dairyReport.js
+++ b/src/endWeek/reports/dairyReport.js
@@ -348,21 +348,14 @@ App.EndWeek.dairyReport = function() {
 		App.Events.addNode(el, r, "div");
 	}
 
-	if (V.MilkmaidID !== 0) {
+	if (S.Milkmaid) {
 		const slave = App.SlaveAssignment.reportSlave(S.Milkmaid);
 		tired(slave);
 		/* apply following SA passages to facility leader */
 		if (V.showEWD !== 0) {
-			const milkMaidEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			const milkMaidEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", milkMaidEntry);
-			App.SlaveAssignment.appendSlaveLinks(milkMaidEntry, slave);
-			App.Events.addNode(
-				milkMaidEntry,
-				[
-					App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"),
-					`is serving as your Milkmaid.`,
-				]
-			);
+			milkMaidEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as your Milkmaid.`));
 			milkMaidEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -460,17 +453,9 @@ App.EndWeek.dairyReport = function() {
 		milkWeek += milkResults.milk;
 		cumWeek += milkResults.cum;
 		if (V.showEWD !== 0) {
-			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			r = [];
-			r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-			if (slave.choosesOwnAssignment === 2) {
-				r.push(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				r.push(`is serving as a cow in ${V.dairyName}.`);
-			}
-			App.Events.addNode(slaveEntry, r);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as a cow in ${V.dairyName}.`));
 
 			const {He} = getPronouns(slave);
 			App.Events.addNode(
@@ -486,7 +471,6 @@ App.EndWeek.dairyReport = function() {
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.standardSlaveReport(slave, true);
 		}
 
diff --git a/src/endWeek/reports/farmyardReport.js b/src/endWeek/reports/farmyardReport.js
index 0b28bc74c0d5a12fc7e240585b8258f18d1df639..6ea06f82aa0e8b7f95f7db21d60be43f681b31a8 100644
--- a/src/endWeek/reports/farmyardReport.js
+++ b/src/endWeek/reports/farmyardReport.js
@@ -26,14 +26,11 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 	V.mods.food.amount += food;
 
 	if (Farmer) {
-		const farmerEffects = App.UI.DOM.appendNewElement("p", frag, null, ["indent"]);
-
 		if (V.showEWD) {
 			const farmerEntry = App.UI.DOM.appendNewElement("div", frag, null, ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", farmerEntry);
-			App.SlaveAssignment.appendSlaveLinks(farmerEntry, Farmer);
-			$(farmerEntry).append(`<span class="slave-name">${SlaveFullName(Farmer)}</span> is serving as the Farmer.`);
-			farmerEntry.append(App.SlaveAssignment.standardSlaveReport(Farmer, false));
+			App.Events.addNode(farmerEntry, [App.SlaveAssignment.saSlaveIntro(Farmer, `is serving as the Farmer.`), farmerText()]);
+			farmerEntry.append(App.SlaveAssignment.standardSlaveReport(Farmer));
 			App.SlaveAssignment.appendSlaveArt(artSpan, Farmer);
 		} else {
 			App.SlaveAssignment.standardSlaveReport(Farmer, true);
@@ -42,7 +39,6 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 		getSlaveStatisticData(S.Farmer, V.facility.farmyard);
 
 		farmerChanges();
-		$(farmerEffects).append(farmerText());
 	}
 
 	if (slaves) {
@@ -56,14 +52,7 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 			if (V.showEWD) {
 				const slaveEntry = App.UI.DOM.appendNewElement("div", frag, null, ["slave-report"]);
 				const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-				App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-				$(slaveEntry).append(`<span class="slave-name">${SlaveFullName(slave)}</span> `);
-
-				if (slave.choosesOwnAssignment) {
-					$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
-				} else {
-					$(slaveEntry).append(`is working out of ${V.farmyardName}.`);
-				}
+				slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is working out of ${V.farmyardName}.`));
 
 				farmhandLivingRules(slave);
 				farmhandHealth(slave);
@@ -72,10 +61,10 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 				farmhandEnergy(slave);
 				farmhandFood(slave);
 
-				const farmhandContent = App.UI.DOM.appendNewElement("div", slaveEntry, null, ["indent"]);
-
-				$(farmhandContent).append(App.SlaveAssignment.workTheFarm(slave));
-				slaveEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
+				App.Events.addNode(slaveEntry, [
+					App.SlaveAssignment.workTheFarm(slave),
+					App.SlaveAssignment.standardSlaveReport(slave, false)
+				], "div", ["indent"]);
 				App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 			} else {	// silently discard return values
 				App.SlaveAssignment.workTheFarm(slave);
@@ -175,7 +164,6 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 		const r = [];
 
 		r.push(
-			farmerIntro(Farmer),
 			farmerRelationshipPC(Farmer),
 			farmerFetishEffects(Farmer, farmerFetish(Farmer)),
 			farmerSkill(Farmer),
@@ -336,10 +324,6 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 		}
 	}
 
-	function farmerIntro(slave) {
-		return `<span class="indent">${SlaveFullName(slave)} is serving as the Farmer.</span>`;
-	}
-
 	// Farmhands
 
 	function farmhandCount(count) {
diff --git a/src/endWeek/reports/incubatorReport.js b/src/endWeek/reports/incubatorReport.js
index 88f6a7eb1f99072bb2c75b12aa9d4d4be3a0661a..ac5dc09d1fc551356cea0e6c5c5451797cc7f6b7 100644
--- a/src/endWeek/reports/incubatorReport.js
+++ b/src/endWeek/reports/incubatorReport.js
@@ -183,8 +183,8 @@ App.EndWeek.incubatorReport = function() {
 					r.push(`The monitoring system floods ${his} body with growth stimulants, but ${his} <span class="orange">NCS prevents an increase in ${his} growth rate.</span>`);
 					tank.height = heightLimitAge;
 				} else {
-					r.push(`The monitoring system floods ${his} body with growth stimulants, causing <span class="green">a sharp increase in growth rate.</span>`);
 					if (V.incubator.setting.weight >= 1 && V.incubator.setting.muscles <= 1 && V.incubator.setting.reproduction <= 1) {
+						r.push(`The monitoring system floods ${his} body with growth stimulants. ${His} caloric intake and expenditure rates are ideal for maximum response, causing <span class="green">explosive growth.</span>`);
 						if (V.incubator.upgrade.speed === 52) {
 							tank.height += random(3, 6);
 						} else if (V.incubator.upgrade.speed === 18) {
@@ -197,6 +197,7 @@ App.EndWeek.incubatorReport = function() {
 							tank.height += random(1, 2);
 						}
 					} else {
+						r.push(`The monitoring system floods ${his} body with growth stimulants, causing <span class="green">a sharp increase in growth rate.</span>`);
 						if (V.incubator.upgrade.speed === 52) {
 							tank.height += random(2, 5);
 						} else if (V.incubator.upgrade.speed === 18) {
diff --git a/src/endWeek/reports/masterSuiteReport.js b/src/endWeek/reports/masterSuiteReport.js
index 492d10676a487bd6c6fdb67d00f3dbd172851b62..ece7e1579348577a73a9cf953b7bb5c417390cbe 100644
--- a/src/endWeek/reports/masterSuiteReport.js
+++ b/src/endWeek/reports/masterSuiteReport.js
@@ -1,5 +1,5 @@
 App.EndWeek.masterSuiteReport = function() {
-	let frag = document.createDocumentFragment();
+	const frag = new DocumentFragment();
 	const concubine = S.Concubine ? App.SlaveAssignment.reportSlave(S.Concubine) : undefined;
 	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.masterSuite);
 	const msAvg = App.Utils.masterSuiteAverages();
@@ -7,10 +7,11 @@ App.EndWeek.masterSuiteReport = function() {
 	const pregnantSlaves = V.masterSuiteUpgradePregnancy ? slaves.filter((s) => s.pregKnown > 0).length : 0;
 
 	function concubineText() {
+		const frag = new DocumentFragment();
 		let r = [];
 		const {He, he, his, him, himself} = getPronouns(S.Concubine);
-
-		r.push(`Your concubine <span class='slave-name'>${SlaveFullName(S.Concubine)}</span> is serving you in ${V.masterSuiteName}. More than any other slave, ${his} sexual brilliance and physical appeal are <span class="green">critical</span> to your reputation.`);
+		r.push(App.SlaveAssignment.saSlaveIntro(S.Concubine, `is serving as your concubine in ${V.masterSuiteName}.`));
+		r.push(`More than any other slave, ${his} sexual brilliance and physical appeal are <span class="green">critical</span> to your reputation.`);
 
 		if (S.Concubine.prestigeDesc === "You bankrupted and enslaved $him in revenge for $his part in the attack on your arcology by the Daughters of Liberty." && S.Concubine.newGamePlus === 0) {
 			r.push(`${He} was once your rival, and your relationship is widely thought to be <span class="green">the perfect modern romance.</span>`);
@@ -88,21 +89,20 @@ App.EndWeek.masterSuiteReport = function() {
 			S.Concubine.trust += 2;
 		}
 		repX(Beauty(S.Concubine) * 5 + (S.Concubine.skill.vaginal || 0) + (S.Concubine.skill.anal || 0) + (S.Concubine.skill.oral || 0) + (S.Concubine.skill.whoring || 0) + (S.Concubine.skill.entertainment || 0), "concubine", S.Concubine);
-		return r.join(' ');
+
+		App.Events.addNode(frag, r);
+
+		return frag;
 	}
 
 	/** Generate text specific to non-concubine MS slaves
 	 * @param {App.Entity.SlaveState} slave
-	 * @returns {string}
+	 * @returns {DocumentFragment}
 	 */
 	function nonConcubineText(slave) {
-		let r = [];
-		r.push(`<span class='slave-name'>${SlaveFullName(slave)}</span>`);
-		if (slave.choosesOwnAssignment === 2) {
-			r.push(App.SlaveAssignment.choosesOwnJob(slave));
-		} else {
-			r.push(`sees to your pleasure in ${V.masterSuiteName}.`);
-		}
+		const frag = new DocumentFragment();
+		frag.append(App.SlaveAssignment.saSlaveIntro(slave, `sees to your pleasure in ${V.masterSuiteName}.`));
+
 		/* Perform facility based rule changes - FIXME - dev/trust living condition changes probably should be in saRules; there's no text reporting these changes here */
 		if (V.masterSuiteUpgradeLuxury === 1) {
 			slave.rules.living = "luxurious";
@@ -147,7 +147,8 @@ App.EndWeek.masterSuiteReport = function() {
 		if (V.masterSuiteDecoration !== "standard") {
 			slave.devotion++;
 		}
-		return r.join(' ');
+
+		return frag;
 	}
 
 	/** Generate text shared by concubine and non-concubine MS slaves
@@ -155,7 +156,7 @@ App.EndWeek.masterSuiteReport = function() {
 	 * @returns {DocumentFragment}
 	 */
 	function commonText(slave) {
-		const smallFrag = document.createDocumentFragment();
+		const frag = new DocumentFragment();
 		let r = [];
 		const {He, he, His, his, him, himself} = getPronouns(slave);
 
@@ -328,24 +329,22 @@ App.EndWeek.masterSuiteReport = function() {
 			}
 		}
 
-		$(smallFrag).append(r.join(' '));
+		App.Events.addNode(frag, r);
 
 		if (V.verboseDescriptions === 1) {
-			const msContent = App.UI.DOM.appendNewElement("div", smallFrag, '', "indent");
-			$(msContent).append(`${He} ${App.SlaveAssignment.pleaseYou(slave)}`);
+			App.Events.addNode(frag, [He, App.SlaveAssignment.pleaseYou(slave)], "div", ["indent"]);
 
 			if (V.servantMilkers === 1 && slave.lactation > 0 && slave.fuckdoll === 0 && slave.fetish !== Fetish.MINDBROKEN && canMove(slave) && slave.intelligence + slave.intelligenceImplant >= -90) {
 				const milkingResults = App.SlaveAssignment.getMilked(slave, 0.25);
-				const milkDiv = App.UI.DOM.appendNewElement("div", smallFrag, `When ${his} breasts begin to feel full and you aren't around, ${he} avails ${himself} to the penthouse milkers and gives ${milkingResults.milk} liters of milk over the week, which is sold for `, "indent");
+				const milkDiv = App.UI.DOM.appendNewElement("div", frag, `When ${his} breasts begin to feel full and you aren't around, ${he} avails ${himself} to the penthouse milkers and gives ${milkingResults.milk} liters of milk over the week, which is sold for `, ["indent"]);
 				App.UI.DOM.appendNewElement("span", milkDiv, `${cashFormat(milkingResults.milkSale)}.`, ["cash", "inc"]);
 			}
-			App.Events.addNode(smallFrag, [
+			App.Events.addNode(frag, [
 				App.SlaveAssignment.choosesOwnClothes(slave),
 				...App.SlaveAssignment.individualSlaveReport(slave),
-			], "div", "indent");
+			], "div", ["indent"]);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.pleaseYou(slave);
 			if (V.servantMilkers === 1 && slave.lactation > 0 && slave.fuckdoll === 0 && slave.fetish !== Fetish.MINDBROKEN && canMove(slave) && slave.intelligence + slave.intelligenceImplant >= -90) {
 				App.SlaveAssignment.getMilked(slave, 0.25);
@@ -353,8 +352,8 @@ App.EndWeek.masterSuiteReport = function() {
 			App.SlaveAssignment.choosesOwnClothes(slave);
 			App.SlaveAssignment.individualSlaveReport(slave);
 		}
-		smallFrag.append(App.PersonalAttention.slaveReport(slave));
-		App.Events.addNode(smallFrag, [App.SlaveAssignment.devotion(slave)], "div", "indent");
+		frag.append(App.PersonalAttention.slaveReport(slave));
+		App.Events.addNode(frag, [App.SlaveAssignment.devotion(slave)], "div", ["indent"]);
 
 		if (slave.health.condition < 80) {
 			if (V.masterSuiteUpgradeLuxury === 1) {
@@ -364,11 +363,11 @@ App.EndWeek.masterSuiteReport = function() {
 			}
 		}
 
-		return smallFrag;
+		return frag;
 	}
 
 	if (slaves.length > 0) {
-		const intro = App.UI.DOM.appendNewElement("p", frag, '', "indent");
+		const intro = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
 		let r = [];
 		if (S.Concubine) {
 			r.push(`<strong>${SlaveFullName(S.Concubine)} and ${numberWithPluralOne(slaves.length, "other slave")} are`);
@@ -428,35 +427,31 @@ App.EndWeek.masterSuiteReport = function() {
 				r.push(`relatively normal.`);
 			}
 		}
-		$(intro).append(r.join(' '));
+		App.Events.addNode(intro, r);
 	}
 
 	if (concubine) {
 		tired(concubine);
-		const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
-		const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-		App.SlaveAssignment.appendSlaveLinks(slaveEntry, concubine);
-		App.Events.addNode(slaveEntry, [concubineText(), commonText(concubine)]);
+		const concubineEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
+		const artSpan = App.UI.DOM.appendNewElement("span", concubineEntry);
+		App.Events.addNode(concubineEntry, [concubineText(), commonText(concubine)]);
 		App.SlaveAssignment.appendSlaveArt(artSpan, concubine);
 	}
 
 	for (const slave of App.SlaveAssignment.reportSlaves(slaves)) {
-		const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+		const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 		const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-		App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
 		App.Events.addNode(slaveEntry, [nonConcubineText(slave), commonText(slave)]);
 		App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 	}
 
 	if (pregnantSlaves > 0 && V.arcologies[0].FSRestart !== "unset" && V.propOutcome !== 1 && V.eugenicsFullControl !== 1) {
-		const eliteEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		$(eliteEffects).append(`The Societal Elite know what you are doing with your bedslaves. <span class="red">They do not approve.</span>`);
+		App.Events.addNode(frag, [`The Societal Elite know what you are doing with your bedslaves. <span class="red">They do not approve.</span>`], "p", ["indent"]);
 		V.failedElite += (5 * pregnantSlaves);
 	}
 
 	if (V.masterSuiteDecoration !== "standard") {
-		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		$(decorationEffects).append(`${capFirstChar(V.masterSuiteName)}'s ${V.masterSuiteDecoration} atmosphere <span class="hotpink">has a minor impact on your fucktoys.</span>`);
+		App.Events.addNode(frag, [`${capFirstChar(V.masterSuiteName)}'s ${V.masterSuiteDecoration} atmosphere <span class="hotpink">has a minor impact on your fucktoys.</span>`], "p", ["indent"]);
 	}
 
 	return frag;
diff --git a/src/endWeek/reports/nurseryReport.js b/src/endWeek/reports/nurseryReport.js
index 1637a2c615e651c92b1d5d38a4569c1a9e524db9..0b7690e487f131cf51ce8fb9a371c6f82d274fe6 100644
--- a/src/endWeek/reports/nurseryReport.js
+++ b/src/endWeek/reports/nurseryReport.js
@@ -45,13 +45,12 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 	}
 
 	function matronText() {
+		const frag = new DocumentFragment();
+
 		if (S.Matron) {
 			const {He, he, His, his, him} = getPronouns(S.Matron);
 
 			let r = [];
-
-			r.push(`${SlaveFullName(S.Matron)} is serving as your Matron.`);
-
 			if (S.Matron.relationship === -3 && S.Matron.devotion > 50) {
 				r.push(`${He} does ${his} best to ${V.nurseryChildren
 					? `properly raise and look after the children in ${V.nurseryName}`
@@ -110,18 +109,14 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 				r.push(`Society <span class='green'>loves</span> the way you are raising more children for ${arcology.name}.`);
 				FutureSocieties.Change("Repopulationist", 2);
 			}
-			return r.join(' ');
-		}
-	}
 
-	const matronEffects = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
+			App.Events.addNode(frag, r);
+		}
 
-	matronChanges();
-	$(matronEffects).append(matronText());
+		return frag;
+	}
 
 	if (slaves) {
-		const intro = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
-
 		let r = [];
 
 		r.push(`${slaves.length > 1 ? `There are ${slaves.length} slaves` : `There is one slave`} working in ${V.nurseryName}.</strong>`);
@@ -132,17 +127,18 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 			r.push(`Society <span class="green">approves</span> of your assigning slaves to a traditionally feminine role.`);
 		}
 
-		$(intro).append(r.join(' '));
+		App.Events.addNode(frag, r);
 	}
 
 	if (S.Matron) {
 		const slave = App.SlaveAssignment.reportSlave(S.Matron);
 
-		if (V.showEWD !== 0) {
-			const matronEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+		matronChanges();
+
+		if (V.showEWD) {
+			const matronEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", matronEntry);
-			App.SlaveAssignment.appendSlaveLinks(matronEntry, slave);
-			$(matronEntry).append(`<span class="slave-name">${SlaveFullName(slave)}</span> is serving as your Matron.`);
+			App.Events.addNode(matronEntry, [App.SlaveAssignment.saSlaveIntro(slave, `is serving as your Matron.`), matronText()]);
 			matronEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -196,21 +192,11 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 
 		if (V.showEWD) {
 			const {He} = getPronouns(slave);
-			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			$(slaveEntry).append(`<span class="slave-name">${SlaveFullName(slave)}</span> `);
-
-			if (slave.choosesOwnAssignment === 2) {
-				$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				$(slaveEntry).append(`is working out of ${V.nurseryName}.`);
-			}
-
-			const nannyContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', ["indent"]);
-
-			$(nannyContent).append(`${He} ${App.SlaveAssignment.nanny(slave)}`);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is working out of ${V.nurseryName}.`));
 
+			App.Events.addNode(slaveEntry, [He, App.SlaveAssignment.nanny(slave)], "div", ["indent"]);
 			slaveEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {	// silently discard return values
@@ -220,9 +206,7 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 	}
 
 	if (V.nurseryDecoration !== "standard") {
-		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', ["indent"]);
-
-		$(decorationEffects).append(`${capFirstChar(V.nurseryName)}'s ${V.nurseryDecoration} atmosphere <span class="devotion inc">has a minor impact on your servants.</span>`);
+		App.Events.addNode(frag, [`${capFirstChar(V.nurseryName)}'s ${V.nurseryDecoration} atmosphere <span class="devotion inc">has a minor impact on your servants.</span>`]);
 	}
 
 	return frag;
diff --git a/src/endWeek/reports/penthouseReport.js b/src/endWeek/reports/penthouseReport.js
index 37e2985b3b9b45c53fa96b4fda3ce43c8de6dc73..7cc99c17e459679f8f4618fd60ff1b3861e98c3f 100644
--- a/src/endWeek/reports/penthouseReport.js
+++ b/src/endWeek/reports/penthouseReport.js
@@ -18,31 +18,27 @@ App.EndWeek.penthouseReport = function() {
 	}
 
 	for (const slave of App.SlaveAssignment.reportSlaves(penthouseSlaves)) {
-		const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+		const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 		if (penthouseArtRenderer) {
 			App.UI.DOM.drawOneSlaveRight(slaveEntry, slave, penthouseArtRenderer);
 		}
-		App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
 		slaveEntry.append(fullReport(slave));
 
 		if (slave.ID === V.HeadGirlID && hgSlave) {
 			/* Output the HG's slave immediately after the hg */
-			const {He2, he2} = getPronouns(hgSlave).appendSuffix("2");
+			const {He2} = getPronouns(hgSlave).appendSuffix("2");
 			const hgSlaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
-			if (hgSlave.assignment !== Job.HEADGIRLSUITE) {
-				App.UI.DOM.appendNewElement("span", hgSlaveEntry, `${hgSlave.slaveName} had been assigned to live with your Head Girl, but this week ${he2} was assigned to ${hgSlave.assignment}. ${He2} has been released to your penthouse for reassignment.`, ["warning"]);
-				removeJob(hgSlave, Job.HEADGIRLSUITE);
-			} else {
-				if (penthouseArtRenderer) {
-					App.UI.DOM.drawOneSlaveRight(hgSlaveEntry, hgSlave, penthouseArtRenderer);
-				}
-				App.SlaveAssignment.appendSlaveLinks(hgSlaveEntry, hgSlave);
-				App.UI.DOM.appendNewElement("span", hgSlaveEntry, SlaveFullName(hgSlave), ["slave-name"]);
-				if (hgSlave.choosesOwnAssignment === 2) {
-					hgSlaveEntry.append(App.SlaveAssignment.choosesOwnJob(hgSlave), ` ${He2}`);
-				}
-				hgSlaveEntry.append(` `, App.SlaveAssignment.liveWithHG(hgSlave));
+			const r = [];
+			if (penthouseArtRenderer) {
+				App.UI.DOM.drawOneSlaveRight(hgSlaveEntry, hgSlave, penthouseArtRenderer);
 			}
+			r.push(App.SlaveAssignment.saSlaveIntro(hgSlave, ''));
+			if (hgSlave.choosesOwnAssignment) {
+				r.push(He2); // starts new sentence
+			}
+			r.push(App.SlaveAssignment.liveWithHG(hgSlave));
+
+			App.Events.addNode(hgSlaveEntry, r);
 		}
 	}
 
@@ -65,11 +61,10 @@ App.EndWeek.penthouseReport = function() {
 		} = getPronouns(slave);
 		let r = [];
 		let milkResults;
-
-		r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), ["slave-name"]));
-		if (slave.choosesOwnAssignment === 2) {
-			r.push(App.SlaveAssignment.choosesOwnJob(slave));
-			r.push(He);
+		
+		r.push(App.SlaveAssignment.saSlaveIntro(slave, ''));
+		if (slave.choosesOwnAssignment) {
+			r.push(He); // starts new sentence
 		}
 
 		switch (slave.assignment) {
@@ -191,6 +186,8 @@ App.EndWeek.penthouseReport = function() {
 		} = getPronouns(S.HeadGirl);
 		const {he2, His2, his2, him2, himself2, girl2} = getPronouns(slave).appendSuffix("2");
 		let r = [];
+		const popup = App.UI.DOM.slaveDescriptionDialog(slave, SlaveFullName(S.HeadGirl));
+		popup.classList.add("slave-name", "bold");
 
 		slave.training = Math.clamp(slave.training, 0, 150);
 		let effectiveness = S.HeadGirl.actualAge + ((S.HeadGirl.intelligence + S.HeadGirl.intelligenceImplant) / 3) - (S.HeadGirl.accent * 5) + (V.HGSeverity * 10) + ((slave.intelligence + slave.intelligenceImplant) / 4) - (slave.accent * 5);
@@ -204,7 +201,7 @@ App.EndWeek.penthouseReport = function() {
 			slave.health.tired += 25;
 		}
 
-		r.push(`<span style="font-weight: bold">Your Head Girl</span> <span class='slave-name'>${S.HeadGirl.slaveName}</span> notices that <span class='slave-name'>${slave.slaveName}</span>`);
+		r.push(`<span style="font-weight: bold">Your Head Girl</span>`, popup, ` notices that <span class='slave-name'>${slave.slaveName}</span>`);
 		switch (headGirlsTraining) {
 			case "health":
 				r.push(`is unwell.`);
diff --git a/src/endWeek/reports/personalAttention.js b/src/endWeek/reports/personalAttention.js
index cd7cf0673098f34f6bf7bb8bddf325e8568eb2f1..e720f56e42b9871e9d754d9f488a1e01801c1ba5 100644
--- a/src/endWeek/reports/personalAttention.js
+++ b/src/endWeek/reports/personalAttention.js
@@ -20,7 +20,7 @@ App.PersonalAttention.slaveReport = function(slave) {
 	const {womenP} = getPronouns(V.PC).appendSuffix("P");
 	let r = [];
 
-	if (V.PC.health.shortDamage >= 30) {
+	if (onBedRest(V.PC, true) && V.PC.dick < -4000) { // Impossible condition to prevent scope creep. Need to finish this later, not right now.
 		// too badly injured to train this week
 		r.push(`You planned to ${pa.objective === "health" ? "care for" : "train"}`);
 		r.push(App.UI.DOM.makeElement("span", slave.slaveName, ["slave-name"]));
@@ -417,7 +417,7 @@ App.PersonalAttention.slaveReport = function(slave) {
 						break;
 					case "judgemental":
 						r.push(`has a bad habit of being sexually judgemental, belittling anyone who doesn't live up to ${his} pretensions of standards. You do your best to train ${him} to perform regardless of ${his} partners' endowments, aiming for a delicate balance that will allow ${him} to get off with anyone while permitting ${him} to retain and even build on ${his} appetite for big dicks. You permit ${him} to achieve release only when ${he}'s done well with`);
-						if (V.PC.dick !== 0) {
+						if (V.PC.dick > 3) {
 							r.push(`your thick cock`);
 						} else {
 							r.push(`a fat dildo`);
diff --git a/src/endWeek/reports/schoolroomReport.js b/src/endWeek/reports/schoolroomReport.js
index 340968a42715ded4e5ca3a0cc93d8b3aeed3039c..6ec84de5bbac6edd72aefade445cd9c413451d3a 100644
--- a/src/endWeek/reports/schoolroomReport.js
+++ b/src/endWeek/reports/schoolroomReport.js
@@ -1,11 +1,13 @@
 App.EndWeek.schoolroomReport = function() {
-	let frag = document.createDocumentFragment();
+	const frag = new DocumentFragment();
 
 	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.schoolroom);
 	const devBonus = (V.schoolroomDecoration !== "standard") ? 1 : 0;
 	App.EndWeek.saVars.flSex = App.EndWeek.getFLSex(App.Entity.facilities.schoolroom);
 
 	function schoolteacherText() {
+		const frag = new DocumentFragment();
+
 		let r = [];
 		let FLsFetish = 0;
 		let idleBonus = 0;
@@ -51,7 +53,6 @@ App.EndWeek.schoolroomReport = function() {
 			}
 
 			const {He, he, His, his, him, himself, wife} = getPronouns(S.Schoolteacher);
-			r.push(`${SlaveFullName(S.Schoolteacher)} is serving as your Schoolteacher.`);
 			if (S.Schoolteacher.relationship === -3 && S.Schoolteacher.devotion > 50) {
 				r.push(`As your loving ${wife}, ${he} tries ${his} best to teach ${his} pupils how to please you.`);
 			}
@@ -130,20 +131,21 @@ App.EndWeek.schoolroomReport = function() {
 				r.push(`<div class="indent">Since ${he} doesn't have enough students to occupy all of ${his} time, ${V.schoolroomName} takes in citizens' slaves on a contract basis and ${he} teaches them too, earning <span class="yellowgreen">${cashFormat(idlePay)}.</span></div>`);
 			}
 
-			return r.join(" ");
+			App.Events.addNode(frag, r);
 		}
-	}
 
-	const schoolteacherEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-	$(schoolteacherEffects).append(schoolteacherText());
+		return frag;
+	}
 
 	if (slaves.length > 0) {
 		const intro = App.UI.DOM.appendNewElement("p", frag, '', "indent");
+		const r = [];
 		if (slaves.length > 1) {
-			$(intro).append(`<strong>There are ${slaves.length} slaves studying in ${V.schoolroomName}.</strong>`);
+			r.push(`<strong>There are ${slaves.length} slaves studying in ${V.schoolroomName}.</strong>`);
 		} else {
-			$(intro).append(`<strong>There is one slave studying in ${V.schoolroomName}.</strong>`);
+			r.push(`<strong>There is one slave studying in ${V.schoolroomName}.</strong>`);
 		}
+		App.Events.addNode(intro, r);
 	}
 
 	if (S.Schoolteacher) {
@@ -153,8 +155,8 @@ App.EndWeek.schoolroomReport = function() {
 		if (V.showEWD !== 0) {
 			const schoolteacherEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
 			const artSpan = App.UI.DOM.appendNewElement("span", schoolteacherEntry);
-			App.SlaveAssignment.appendSlaveLinks(schoolteacherEntry, slave);
-			$(schoolteacherEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> is serving as your Schoolteacher.`);
+			schoolteacherEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as your Schoolteacher.`));
+			App.Events.addNode(schoolteacherEntry, [schoolteacherText()], "div", ["indent"]);
 			schoolteacherEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -225,52 +227,47 @@ App.EndWeek.schoolroomReport = function() {
 			}
 			r.push(`</span>`);
 			restedSlaves++;
-			$(reassignment).append(r.join(" "));
+			App.Events.addNode(reassignment, r);
 			continue;
 		}
 
-		if (V.showEWD !== 0) {
+		if (V.showEWD) {
 			const {He} = getPronouns(slave);
 			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			$(slaveEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> `);
-			if (slave.choosesOwnAssignment === 2) {
-				$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				let leaderTraining = '';
-				for (const role of Object.keys(V.slaveTutor)) {
-					if (V.slaveTutor[role].contains(slave.ID)) {
-						leaderTraining = ` on being a ${role}`; break;
-					}
+			let leaderTraining = '';
+			for (const role of Object.keys(V.slaveTutor)) {
+				if (V.slaveTutor[role].includes(slave.ID)) {
+					leaderTraining = ` on being a ${role}`; break;
 				}
-				$(slaveEntry).append(`is studying in ${V.schoolroomName}${leaderTraining}.`);
 			}
-			const studentContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', "indent");
-			$(studentContent).append(`${He} ${App.SlaveAssignment.takeClasses(slave)}`);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is studying in ${V.schoolroomName}${leaderTraining}.`));
+
+			App.Events.addNode(slaveEntry, [He, App.SlaveAssignment.takeClasses(slave)], "div", ["indent"]);
 			slaveEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.takeClasses(slave);
 			App.SlaveAssignment.standardSlaveReport(slave, true);
 		}
 	}
 
 	if (restedSlaves > 0) {
-		const rested = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		rested.append((restedSlaves === 1) ? `One slave has ` : `${restedSlaves} slaves have `);
-		App.UI.DOM.appendNewElement("span", rested, "learned", "green");
-		rested.append(` all they can, and will be released from the schoolroom before the end of the week.`);
+		const r = [];
+		r.push((restedSlaves === 1) ? `One slave has ` : `${restedSlaves} slaves have`);
+		r.push(App.UI.DOM.makeElement("span", "learned", ["green"]));
+		r.push(`all they can, and will be released from the schoolroom before the end of the week.`);
+		App.Events.addNode(frag, r, "p", ["indent"]);
 	}
 
 	if (V.schoolroomDecoration !== "standard") {
-		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		$(decorationEffects).append(`${capFirstChar(V.schoolroomName)}'s ${V.schoolroomDecoration} atmosphere <span class="hotpink">has a minor impact on the students.</span>`);
+		const r = [];
+		r.push(`${capFirstChar(V.schoolroomName)}'s ${V.schoolroomDecoration} atmosphere <span class="hotpink">has a minor impact on the students.</span>`);
 		if (App.Entity.facilities.schoolroom.revivalistLanguageDecorationBonus()) {
-			$(decorationEffects).append(` They also <span class="positive">learn ${V.language} more quickly</span> in this environment.`);
+			r.push(`They also <span class="positive">learn ${V.language} more quickly</span> in this environment.`);
 		}
+		App.Events.addNode(frag, r, "p", ["indent"]);
 	}
 
 	return frag;
diff --git a/src/endWeek/reports/servantsQuartersReport.js b/src/endWeek/reports/servantsQuartersReport.js
index ea2c9eb26adc5e7483aa860de57fc103d52a9098..44bf43b1e08dde85848ec91b45140a6b9befa184 100644
--- a/src/endWeek/reports/servantsQuartersReport.js
+++ b/src/endWeek/reports/servantsQuartersReport.js
@@ -1,11 +1,13 @@
 App.EndWeek.servantsQuartersReport = function() {
-	let frag = document.createDocumentFragment();
+	const frag = new DocumentFragment();
 
 	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.servantsQuarters);
 	const devBonus = (V.servantsQuartersDecoration !== "standard") ? 1 : 0;
 	let stewardessBonus = 0;
 
 	function stewardessText() {
+		const frag = new DocumentFragment();
+
 		let r = [];
 		let FLsFetish = 0;
 		let stewardessImpregnated = 0;
@@ -52,7 +54,6 @@ App.EndWeek.servantsQuartersReport = function() {
 			}
 
 			const {He, he, His, his, him, wife} = getPronouns(S.Stewardess);
-			r.push(`${SlaveFullName(S.Stewardess)} is serving as your Stewardess.`);
 			if (S.Stewardess.relationship === -3 && S.Stewardess.devotion > 50) {
 				r.push(`${He} does ${his} best to be your perfect lovely house${wife}.`);
 			}
@@ -215,35 +216,35 @@ App.EndWeek.servantsQuartersReport = function() {
 				r.push(`<br>The Societal Elite know you've ordered ${S.Stewardess.slaveName} to impregnate your maids. <span class="red">They are not amused by your disinterest in eugenics.</span>`);
 				V.failedElite += 10;
 			}
+			App.Events.addNode(frag, r);
 		}
-		return r.join(' ');
+		return frag;
 	}
 
 	const stewardessEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
 	$(stewardessEffects).append(stewardessText());
 
 	if (slaves.length > 0) {
-		const intro = App.UI.DOM.appendNewElement("p", frag, '', "indent");
 		let r = [];
 		if (slaves.length > 1) {
-			r.push(`<strong>There are ${slaves.length} slaves working out of the servants' quarters.</strong> They work to`);
+			r.push(`<strong>There are ${num(slaves.length)} slaves working out of the servants' quarters.</strong> They work to`);
 		} else {
 			const {He} = getPronouns(slaves[0]);
-			r.push(`<strong>There is one slave working out of the servants' quarters.</strong> ${He} works to`);
+			r.push(`<strong>There is ${num(1)} slave working out of the servants' quarters.</strong> ${He} works to`);
 		}
 		r.push(`<span class="yellowgreen">reduce</span> your household expenses; having a well-staffed house slightly <span class="green">increases</span> your reputation.`);
-		$(intro).append(r.join(' '));
+		App.Events.addNode(frag, r);
 	}
 
 	if (S.Stewardess) {
 		const slave = App.SlaveAssignment.reportSlave(S.Stewardess);
 		tired(slave);
 		/* apply following SA passages to facility leader */
-		if (V.showEWD !== 0) {
+		if (V.showEWD) {
 			const stewardessEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
 			const artSpan = App.UI.DOM.appendNewElement("span", stewardessEntry);
-			App.SlaveAssignment.appendSlaveLinks(stewardessEntry, slave);
-			$(stewardessEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> is serving as your Stewardess.`);
+			stewardessEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as your Stewardess.`));
+			App.Events.addNode(stewardessEntry, [stewardessText()], "div", ["indent"])
 			stewardessEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
@@ -312,23 +313,15 @@ App.EndWeek.servantsQuartersReport = function() {
 				slave.rules.living = "normal";
 		}
 
-		if (V.showEWD !== 0) {
+		if (V.showEWD) {
 			const {He} = getPronouns(slave);
-			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			$(slaveEntry).append(`<span class='slave-name'>${SlaveFullName(slave)}</span> `);
-			if (slave.choosesOwnAssignment === 2) {
-				$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				$(slaveEntry).append(`is working out of ${V.servantsQuartersName}.`);
-			}
-			const servantContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', "indent");
-			$(servantContent).append(`${He} ${App.SlaveAssignment.servant(slave, stewardessBonus)}`);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is working out of ${V.servantsQuartersName}.`));
+			App.Events.addNode(slaveEntry, [He, App.SlaveAssignment.servant(slave, stewardessBonus)], "div", ["indent"]);
 			if (V.servantMilkers === 1 && slave.lactation > 0) {
-				const milkContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', "indent");
 				const milkResults = App.SlaveAssignment.getMilked(slave, 0.5);
-				$(milkContent).append(`${He} ${milkResults.text}`);
+				App.Events.addNode(slaveEntry, [He, milkResults.text], "div", ["indent"]);
 				SQMilk += milkResults.milk;
 				SQMilkSale += milkResults.milkSale;
 			}
@@ -336,7 +329,6 @@ App.EndWeek.servantsQuartersReport = function() {
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
 			App.SlaveAssignment.servant(slave, stewardessBonus);
 			if (V.servantMilkers === 1 && slave.lactation > 0) {
 				const milkResults = App.SlaveAssignment.getMilked(slave, 0.5);
@@ -349,12 +341,12 @@ App.EndWeek.servantsQuartersReport = function() {
 
 	if (SQMilk > 0) {
 		const milkEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		$(milkEffects).append(`Since your lactating servants spend most of their time working in the penthouse, they use the milkers there, giving ${SQMilk} liters of milk over the week, which is sold for <span class="yellowgreen">${cashFormat(SQMilkSale)}.</span>`);
+		App.Events.addNode(milkEffects, [`Since your lactating servants spend most of their time working in the penthouse, they use the milkers there, giving ${SQMilk} liters of milk over the week, which is sold for <span class="yellowgreen">${cashFormat(SQMilkSale)}.</span>`]);
 	}
 
 	if (V.servantsQuartersDecoration !== "standard") {
 		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
-		$(decorationEffects).append(`${capFirstChar(V.servantsQuartersName)}'s ${V.servantsQuartersDecoration} atmosphere <span class="hotpink">has a minor impact on your servants.</span>`);
+		App.Events.addNode(decorationEffects, [`${capFirstChar(V.servantsQuartersName)}'s ${V.servantsQuartersDecoration} atmosphere <span class="hotpink">has a minor impact on your servants.</span>`]);
 	}
 
 	repX(slaves.length * 20, "servantsQuarters");
diff --git a/src/endWeek/reports/spaReport.js b/src/endWeek/reports/spaReport.js
index 60e76e009804b443a62a52e7719bf7e21970ffac..a95e13675d4b35fe86a3d9a94a5a9878c279702e 100644
--- a/src/endWeek/reports/spaReport.js
+++ b/src/endWeek/reports/spaReport.js
@@ -55,7 +55,9 @@ App.EndWeek.spaReport = function() {
 			He, His,
 			he, his, him, himself, wife
 		} = getPronouns(S.Attendant);
-		r.push(`${SlaveFullName(S.Attendant)} is serving as the spa attendant.`);
+		const popup = App.UI.DOM.slaveDescriptionDialog(S.Attendant, SlaveFullName(S.Attendant));
+		popup.classList.add("slave-name", "bold");
+		r.push(popup, `is serving as the spa attendant.`);
 		if (S.Attendant.relationship === -3 && S.Attendant.devotion > 50) {
 			r.push(`${He} tries ${his} best to be your perfect attentive, caring and loving ${wife}.`);
 		}
@@ -291,15 +293,8 @@ App.EndWeek.spaReport = function() {
 		if (V.showEWD !== 0) {
 			const attendantEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
 			const artSpan = App.UI.DOM.appendNewElement("span", attendantEntry);
-			App.SlaveAssignment.appendSlaveLinks(attendantEntry, slave);
-			App.Events.addNode(
-				attendantEntry,
-				[
-					App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"),
-					`is serving as the Attendant in ${V.spaName}.`,
-					App.SlaveAssignment.standardSlaveReport(slave, false),
-				]
-			);
+			attendantEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is serving as the Attendant in ${V.spaName}.`));
+			attendantEntry.append(App.SlaveAssignment.standardSlaveReport(slave, false));
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			App.SlaveAssignment.standardSlaveReport(slave, true);
@@ -375,17 +370,9 @@ App.EndWeek.spaReport = function() {
 		}
 
 		if (V.showEWD !== 0) {
-			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', "slave-report");
+			const slaveEntry = App.UI.DOM.appendNewElement("div", el, '', ["slave-report"]);
 			const artSpan = App.UI.DOM.appendNewElement("span", slaveEntry);
-			App.SlaveAssignment.appendSlaveLinks(slaveEntry, slave);
-			r = [];
-			r.push(App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
-			if (slave.choosesOwnAssignment === 2) {
-				r.push(App.SlaveAssignment.choosesOwnJob(slave));
-			} else {
-				r.push(`is resting in ${V.spaName}.`);
-			}
-			App.Events.addNode(slaveEntry, r);
+			slaveEntry.append(App.SlaveAssignment.saSlaveIntro(slave, `is resting in ${V.spaName}.`));
 
 			r = [];
 			r.push(He);
@@ -407,7 +394,7 @@ App.EndWeek.spaReport = function() {
 			App.SlaveAssignment.appendSlaveArt(artSpan, slave);
 		} else {
 			// discard return values silently
-			App.SlaveAssignment.choosesOwnJob(slave);
+			App.SlaveAssignment.rest(slave);
 			App.SlaveAssignment.standardSlaveReport(slave, true);
 		}
 	}
diff --git a/src/endWeek/saChoosesOwnJob.js b/src/endWeek/saChoosesOwnJob.js
index 4f8c9677f8f70db178dbeab38d8286bd07857bf9..48d99989e359274de3370016afe122f5935bec8c 100644
--- a/src/endWeek/saChoosesOwnJob.js
+++ b/src/endWeek/saChoosesOwnJob.js
@@ -1,4 +1,6 @@
 /**
+ * This function is the old "first pass", which actually picks the job.
+ * The slaves' reasoning is saved in saVars for later use.
  * @param {App.Entity.SlaveState} slave
  * @returns {string}
  */
@@ -21,27 +23,25 @@ App.SlaveAssignment.choosesOwnJob = function saChoosesOwnJob(slave) {
 		He, he, him, his, himself, girl,
 	} = getPronouns(slave);
 
-	/*
-	"I suspect something might be awry with that too" - Pregmodder - 2021-09-26
-	*/
-	if (slave.choosesOwnAssignment === 0 || slave.fuckdoll > 0 || slave.fetish === Fetish.MINDBROKEN) {
-		// nothing to do
-	} else if (slave.choosesOwnAssignment === 2) {
-		// second pass happens visibly during weekly report for the location where this slave decided to go (or stay)
-		// display text but don't change assignment (already done)
-		r.push(V.choosesOwnAssignmentText[slave.ID]);
-		delete V.choosesOwnAssignmentText[slave.ID];
-		slave.choosesOwnAssignment = 1;
-		// continue cycle for next week
+	if (slave.fuckdoll > 0 || slave.fetish === Fetish.MINDBROKEN) {
+		// deal with slaves who are incapable of actually choosing their own assignment
+		r.push(`was assigned to ${slave.assignment}. ${He}'s allowed to choose ${his} own job, but is <span style="warning">mentally incapable</span> of doing so,`);
+		if (slave.assignment === Job.CHOICE) {
+			r.push(`and <span class="job change">rests for the week</span> instead.`);
+			removeJob(slave, slave.assignment);
+		} else {
+			r.push(`and just keeps doing the same thing this week.`);
+		}
+		slave.choosesOwnAssignment = 0;
+		App.EndWeek.saVars.choosesOwnAssignmentText[slave.ID] = r.join(' ');
 	} else {
-		// first pass happens silently before all reports: give stats bonus, construct decision string for display during second pass, actually change assignment
+		// give stats bonus, construct decision string for display during slave report, and actually change the assignment
 		slave.devotion++;
 		slave.trust++;
-		V.choosesOwnAssignmentText[slave.ID] = jobSelection(slave);
+		App.EndWeek.saVars.choosesOwnAssignmentText[slave.ID] = jobSelection(slave);
 	}
 
-	return r.join(" ");
-
+	return;
 
 	/**
 	 * @param {App.Entity.SlaveState} slave
@@ -554,8 +554,7 @@ App.SlaveAssignment.choosesOwnJob = function saChoosesOwnJob(slave) {
 			}
 		}
 
-		slave.choosesOwnAssignment = 2;
-		// ready for second pass
+		slave.choosesOwnAssignment = 1; // removeJob may have cleared this, but we want it to stay
 
 		return choice.join(" ");
 	}
diff --git a/src/endWeek/saDiet.js b/src/endWeek/saDiet.js
index 76e5c995842ac647722710012bd6b285331b3a84..745fdc9679d4209e1a5e323b80306f494138e6d0 100644
--- a/src/endWeek/saDiet.js
+++ b/src/endWeek/saDiet.js
@@ -1443,7 +1443,7 @@ App.SlaveAssignment.diet = function saDiet(slave) {
 			roll = 75;
 			target = Math.trunc(Math.clamp(weightGain * 2 - (boobSize - growthGoal) / 20, 0, 68));
 		}
-		if (slave.geneMods.NCS === 1) {
+		if (slave.geneMods.NCS === 1 || V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1) {
 			roll *= 2;
 		}
 		if (random(1, roll) <= target) {
@@ -1464,7 +1464,7 @@ App.SlaveAssignment.diet = function saDiet(slave) {
 			roll = 80000;
 			target = Math.trunc(Math.clamp(weightGain * 1000 - (buttSize * 1000 - growthGoal) * 4, 0, 72000));
 		}
-		if (slave.geneMods.NCS === 1) {
+		if (slave.geneMods.NCS === 1 || V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1) {
 			roll *= 2;
 		}
 		if (random(1, roll) <= target) {
diff --git a/src/endWeek/saDrugs.js b/src/endWeek/saDrugs.js
index 4acad87ebc56de8d05d61e7f936ece4b7c7d7be9..103ebfaccb3fb6fb680a9808d98d1e3995779429 100644
--- a/src/endWeek/saDrugs.js
+++ b/src/endWeek/saDrugs.js
@@ -1790,7 +1790,7 @@ App.SlaveAssignment.drugs = function saDrugs(slave) {
 				slave.addict -= 2;
 				slave.devotion -= 10;
 			} else {
-				r += ` ${He} gets ${his} fix from ${his} aphrodisiac filled belly.`;
+				r += ` ${He} gets ${his} fix from ${his} aphrodisiac-filled belly.`;
 			}
 		} else {
 			if (slave.aphrodisiacs > 0) {
diff --git a/src/endWeek/saGuardYou.js b/src/endWeek/saGuardYou.js
index 533d6777d7e7699be6d4d94399150967ecae53ac..9ab821d8d74e5baf931818ad7e3b71eef470dceb 100644
--- a/src/endWeek/saGuardYou.js
+++ b/src/endWeek/saGuardYou.js
@@ -164,21 +164,21 @@ App.SlaveAssignment.guardYou = function saGuardYou(slave) {
 			}
 		} else if (slave.bellyImplant >= 1500) {
 			if (slave.bellyImplant >= 750000) {
-				r.push(`${His} monolithic, ${slave.bellyImplant}cc implant filled belly greatly restricts ${his} movement and renders ${him} nearly useless in combat. ${He} can barely waddle after you, and when ${he} does, finds doors and small passages don't agree with ${his} bloated figure.`);
+				r.push(`${His} monolithic, ${slave.bellyImplant}cc implant-filled belly greatly restricts ${his} movement and renders ${him} nearly useless in combat. ${He} can barely waddle after you, and when ${he} does, finds doors and small passages don't agree with ${his} bloated figure.`);
 			} else if (slave.bellyImplant >= 450000) {
-				r.push(`${His} gigantic, ${slave.bellyImplant}cc implant filled belly greatly hinders ${his} movement and terribly reduces ${his} effectiveness in combat. It also limits where ${he} can follow you, as doors and small passages don't agree with ${his} bloated figure.`);
+				r.push(`${His} gigantic, ${slave.bellyImplant}cc implant-filled belly greatly hinders ${his} movement and terribly reduces ${his} effectiveness in combat. It also limits where ${he} can follow you, as doors and small passages don't agree with ${his} bloated figure.`);
 			} else if (slave.bellyImplant >= 300000) {
-				r.push(`${His} massive, ${slave.bellyImplant}cc implant filled belly obstructs ${his} movement and greatly hinders ${his} ability to protect you. It also limits where ${he} can follow you, as doors and small passages don't agree with ${his} bloated figure.`);
+				r.push(`${His} massive, ${slave.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly hinders ${his} ability to protect you. It also limits where ${he} can follow you, as doors and small passages don't agree with ${his} bloated figure.`);
 			} else if (slave.bellyImplant >= 150000) {
-				r.push(`${His} giant, ${slave.bellyImplant}cc implant filled belly obstructs ${his} movement and greatly slows ${him} down. It also limits where ${he} can follow you, as ${he} has trouble waddling through crowds.`);
+				r.push(`${His} giant, ${slave.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down. It also limits where ${he} can follow you, as ${he} has trouble waddling through crowds.`);
 			} else if (slave.bellyImplant >= 100000) {
-				r.push(`${His} giant, ${slave.bellyImplant}cc implant filled belly is very heavy and unwieldy, frequently getting in the way of ${his} job.`);
+				r.push(`${His} giant, ${slave.bellyImplant}cc implant-filled belly is very heavy and unwieldy, frequently getting in the way of ${his} job.`);
 			} else if (slave.bellyImplant >= 10000) {
-				r.push(`${His} huge, ${slave.bellyImplant}cc implant filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
+				r.push(`${His} huge, ${slave.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
 			} else if (slave.bellyImplant >= 5000) {
-				r.push(`${His} large, ${slave.bellyImplant}cc implant filled belly is heavy and unwieldy, limiting ${his} effectiveness.`);
+				r.push(`${His} large, ${slave.bellyImplant}cc implant-filled belly is heavy and unwieldy, limiting ${his} effectiveness.`);
 			} else if (slave.bellyImplant >= 1500) {
-				r.push(`${His} swollen, ${slave.bellyImplant}cc implant filled belly is heavy and occasionally distracts ${him}.`);
+				r.push(`${His} swollen, ${slave.bellyImplant}cc implant-filled belly is heavy and occasionally distracts ${him}.`);
 			}
 		}
 		if (isInLabor(slave)) {
diff --git a/src/endWeek/saHormonesEffects.js b/src/endWeek/saHormonesEffects.js
index ea7dd59d90a4226c5db690e240cd7469db95d848..55077381d9c84584b31eaf89057571b0e464260c 100644
--- a/src/endWeek/saHormonesEffects.js
+++ b/src/endWeek/saHormonesEffects.js
@@ -318,9 +318,11 @@ App.SlaveAssignment.hormonesEffects = function saHormonesEffects(slave) {
 			let normBreasts = 0;
 			let normButt = 0;
 			if (slave.hormoneBalance > 30 && slave.geneMods.NCS !== 1) {
+				const slimModBreasts = (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1) ? 0.45 : 1; // 600 average breast target, 270 target, 475 @ 350 hormone
+				const slimModButts = (V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1) ? 0.6 : 1; // 2.5 average butt, 1.5 target
 				/* 'Expected' breast size based on weight for feminine-bodied slaves */
-				normBreasts = Math.trunc((100 + (slave.weight + 100) * 5 + 2 * slave.lactationAdaptation) * (0.85 + slave.hormoneBalance / 400) * gigantomastiaMod);
-				normButt = ((slave.weight + 100) * 0.025 * (0.9 + slave.hormoneBalance / 600) * (rearLipedemaMod / 2 + 1));
+				normBreasts = Math.trunc((100 + (slave.weight + 100) * 5 + 2 * slave.lactationAdaptation) * (0.85 + slave.hormoneBalance / 400) * gigantomastiaMod * slimModBreasts);
+				normButt = ((slave.weight + 100) * 0.025 * (0.9 + slave.hormoneBalance / 600) * (rearLipedemaMod / 2 + 1) * slimModButts);
 			}
 
 			if (slave.hormoneBalance >= 350) {
diff --git a/src/endWeek/saInflation.js b/src/endWeek/saInflation.js
index 4fe7f6776402d01645b0d5f2dce46cf3d032a869..6a6e26785ac152cf015ee335eb26bf334c10ec85 100644
--- a/src/endWeek/saInflation.js
+++ b/src/endWeek/saInflation.js
@@ -241,7 +241,7 @@ App.SlaveAssignment.inflation = function saInflation(slave) {
 				} else if (slave.inflation === 2) {
 					r.push(`four liters of an aphrodisiac solution, leaving ${him} looking pregnant, whenever ${he} leaks or ${his} body absorbs too much. ${He} is full enough to be distended but not enough to grow taut. While having ${his} body bloated with aphrodisiacs doesn't make ${him} additionally submissive, it does amplify the effects of them. ${His} overfilled aphrodisiac belly`);
 				} else if (slave.inflation === 1) {
-					r.push(`two liters of an aphrodisiac solution, leaving ${his} belly noticeably distended, whenever ${he} leaks or ${his} body absorbs too much. ${He} is full enough to be swollen but not enough to visibly jiggle. ${His} aphrodisiac filled belly`);
+					r.push(`two liters of an aphrodisiac solution, leaving ${his} belly noticeably distended, whenever ${he} leaks or ${his} body absorbs too much. ${He} is full enough to be swollen but not enough to visibly jiggle. ${His} aphrodisiac-filled belly`);
 				}
 				if (slave.energy <= 95) {
 					r.push(`<span class="libido inc">rapidly boosts ${his} sex drive.</span>`);
diff --git a/src/endWeek/saLiveWithHG.js b/src/endWeek/saLiveWithHG.js
index dcbb142ce2b9792721ad1035cc7ac44de273845a..a6c8c9c141708e09071bc404f2618dc9f0648b6f 100644
--- a/src/endWeek/saLiveWithHG.js
+++ b/src/endWeek/saLiveWithHG.js
@@ -485,7 +485,7 @@ App.SlaveAssignment.liveWithHG = function saliveWithHG(slave) {
 							HG.devotion += 3;
 							slave.devotion += 3;
 							HG.trust += 2;
-							HG.devotion += 2;
+							slave.trust += 2;
 						}
 					} else {
 						r.push(`Since ${HG.slaveName} and ${slave.slaveName} are`);
@@ -498,7 +498,7 @@ App.SlaveAssignment.liveWithHG = function saliveWithHG(slave) {
 						HG.devotion += 4;
 						slave.devotion += 4;
 						HG.trust += 3;
-						HG.devotion += 3;
+						slave.trust += 3;
 					}
 				}
 				HG.relationship = slave.relationship;
diff --git a/src/endWeek/saLongTermEffects.js b/src/endWeek/saLongTermEffects.js
index e41ef2539e97e4628b30453a72b0138d3c199e56..4dd86d4f0024868cc86093932bab54784e1b53f8 100644
--- a/src/endWeek/saLongTermEffects.js
+++ b/src/endWeek/saLongTermEffects.js
@@ -59,7 +59,7 @@ App.SlaveAssignment.longTermEffects = function saLongTermEffects(slave) {
 			solidSlaveFoodEffects(slave);
 		}
 	}
-	r.push(App.SlaveAssignment.saSocialEffects(slave));
+	r.push(App.SlaveAssignment.saSocialEffects(slave).report());
 	if (slave.fuckdoll === 0) { // swap to fuckdoll suit in the future
 		brandEffects(slave);
 		if (slave.fetish !== Fetish.MINDBROKEN) {
diff --git a/src/endWeek/saLongTermMentalEffects.js b/src/endWeek/saLongTermMentalEffects.js
index 9b0b83914299634ac79c1a21560554ce4c8af016..663c6913ec5761e697c4f6fe3e68105733100ec5 100644
--- a/src/endWeek/saLongTermMentalEffects.js
+++ b/src/endWeek/saLongTermMentalEffects.js
@@ -1169,6 +1169,7 @@ App.SlaveAssignment.longTermMentalEffects = function saLongTermMentalEffects(sla
 						slave.sexualFlaw = "none";
 					} else if (slave.fetish === "pregnancy" && slave.fetishKnown === 1 && (slave.ovaries === 1 || slave.mpreg === 1)) {
 						r.push(`It would be unreasonable to expect to become pregnant with out being penetrated, so <span class="flaw break">${his} previous hesitations about getting fucked vanish.</span>`);
+						slave.sexualFlaw = "none";
 					} else if (slave.energy > 95) {
 						r.push(`${He} needs sex like ${he} needs air, so <span class="flaw break">${his} previous hesitations about getting fucked vanish.</span>`);
 						slave.sexualFlaw = "none";
diff --git a/src/endWeek/saLongTermPhysicalEffects.js b/src/endWeek/saLongTermPhysicalEffects.js
index f7e65119c1eafbe6a3f751350b94a37f500bb056..725074a2f2a3059d990bfd917215629658bba563 100644
--- a/src/endWeek/saLongTermPhysicalEffects.js
+++ b/src/endWeek/saLongTermPhysicalEffects.js
@@ -215,19 +215,16 @@ App.SlaveAssignment.longTermPhysicalEffects = function saLongTermPhysicalEffects
 	 *
 	 */
 	function holeRelaxation(slave) {
-		if (!["be confined in the arcade", "serve in the club", "serve the public", "whore", "work a glory hole", "work in the brothel"].includes(slave.assignment)) {
-			if (slave.assignment !== Job.MASTERSUITE || V.masterSuiteUpgradeLuxury < 2) {
-				if (slave.assignment !== Job.DAIRY || V.dairyStimulatorsSetting === 0) {
-					if (slave.geneMods.rapidCellGrowth !== 1) {
-						if (slave.vagina >= 3 && dildoWidth(slave) < 2) {
-							r.push(`With a rest from strenuous use, <span class="improvement">${his} loose vagina recovers a little.</span>`);
-							slave.vagina -= 1;
-						} else if (slave.anus >= 3 && plugWidth(slave) < 2) {
-							r.push(`With a rest from continual sodomy, <span class="improvement">${his} gaping anus recovers a little.</span>`);
-							slave.anus -= 1;
-						}
-					}
-				}
+		const jobStressesHoles = [Job.ARCADE, Job.CLUB, Job.PUBLIC, Job.WHORE, Job.GLORYHOLE, Job.BROTHEL].includes(slave.assignment) ||
+			(slave.assignment === Job.MASTERSUITE && V.masterSuiteUpgradeLuxury === 2) ||
+			(slave.assignment === Job.DAIRY && V.dairyStimulatorsSetting > 0);
+		if (slave.geneMods.rapidCellGrowth !== 1) {
+			if (slave.vagina >= 3 && dildoWidth(slave) < 2 && (!jobStressesHoles || slave.chastityVagina === 1)) {
+				r.push(`With a rest from strenuous use, <span class="improvement">${his} loose vagina recovers a little.</span>`);
+				slave.vagina -= 1;
+			} else if (slave.anus >= 3 && plugWidth(slave) < 2 && (!jobStressesHoles || slave.chastityAnus === 1)) {
+				r.push(`With a rest from continual sodomy, <span class="improvement">${his} gaping anus recovers a little.</span>`);
+				slave.anus -= 1;
 			}
 		}
 		if (slave.anus >= slave.analArea) {
@@ -1422,7 +1419,7 @@ App.SlaveAssignment.longTermPhysicalEffects = function saLongTermPhysicalEffects
 					}
 				}
 			} else {
-				r.push(`${His} high-calorie and nutrient filled diet allows ${his} body to handle its demanding pregnancy, though being stuffed only compounds the pressure within ${his} abdomen. ${He} <span class="devotion dec">resents</span> needing to have ${his} stomach bloated with food at all times, but <span class="trust inc">appreciates</span> the effort you are putting into keeping ${him} healthy.`);
+				r.push(`${His} high-calorie and nutrient-filled diet allows ${his} body to handle its demanding pregnancy, though being stuffed only compounds the pressure within ${his} abdomen. ${He} <span class="devotion dec">resents</span> needing to have ${his} stomach bloated with food at all times, but <span class="trust inc">appreciates</span> the effort you are putting into keeping ${him} healthy.`);
 				slave.devotion -= 1;
 				slave.trust += 2;
 			}
@@ -2189,7 +2186,7 @@ App.SlaveAssignment.longTermPhysicalEffects = function saLongTermPhysicalEffects
 		} else if (slave.belly > (slave.pregAdaptation * 3200)) {
 			r.push(`${His}`);
 			if (slave.mpreg === 0 && slave.ovaries === 0) {
-				r.push(`implant filled abdominal cavity`);
+				r.push(`implant-filled abdominal cavity`);
 			} else {
 				r.push(`straining womb`);
 			}
diff --git a/src/endWeek/saPleaseYou.js b/src/endWeek/saPleaseYou.js
index bc06ef2e27328f6712761319165aa9e147f41a46..ed6692c4789b88e0f2d80205ee0565c72775d17f 100644
--- a/src/endWeek/saPleaseYou.js
+++ b/src/endWeek/saPleaseYou.js
@@ -1790,7 +1790,7 @@ App.SlaveAssignment.pleaseYou = function saPleaseYou(slave) {
 				slave.fetishStrength += 4;
 			}
 		} else if (fetishChange > random(0, 100) && (V.PC.preg >= 20 || (V.PC.preg >= 16 && V.PC.career === "escort"))) {
-			r.push(`At first ${he} found the prospect of being used by ${his} increasingly pregnant ${getWrittenTitle(slave)} a turn off, but being so close to your gravid form serves to be more erotic than ${he} anticipated. Soon ${he} finds ${himself} aroused less from the prospect of sex and more <span class="lightcoral">the chance to be near your child laden belly.</span>`);
+			r.push(`At first ${he} found the prospect of being used by ${his} increasingly pregnant ${getWrittenTitle(slave)} a turn off, but being so close to your gravid form serves to be more erotic than ${he} anticipated. Soon ${he} finds ${himself} aroused less from the prospect of sex and more <span class="lightcoral">the chance to be near your child-laden belly.</span>`);
 			slave.fetish = "pregnancy";
 			slave.fetishKnown = 1;
 			slave.fetishStrength = 10;
diff --git a/src/endWeek/saPorn.js b/src/endWeek/saPorn.js
index 246dd03b18271fc20704997010d1b765182c4464..56f99456b4fadc0ebf6e46c37d4d8f83754f1671 100644
--- a/src/endWeek/saPorn.js
+++ b/src/endWeek/saPorn.js
@@ -28,6 +28,7 @@ App.SlaveAssignment.porn = function saPorn(slave) {
 		prestigeCommentary(slave);
 		faceCommentary(slave);
 		hack();
+		checkFocus();
 
 		allGenreViews(slave);
 		updateViewerCount(slave);
@@ -212,6 +213,16 @@ App.SlaveAssignment.porn = function saPorn(slave) {
 		}
 	}
 
+	function checkFocus() {
+		if (slave.porn.focus !== "none") {
+			const focusGenre = App.Porn.getGenreByFocusName(slave.porn.focus);
+			if (!focusGenre || !focusGenre.valid(slave)) {
+				r += `${He} has been instructed to focus on ${slave.porn.focus} aspects of ${his} sex life to improve the porn ${he} produces, but ${he} <span class="red">can no longer do so.</span>`;
+				slave.porn.focus = "none";
+			}
+		}
+	}
+
 	function hack() {
 		if (V.PC.skill.hacking > 10) {
 			r += `With your hacking skills, you manage to tweak search algorithms to display ${his} content more often. `;
diff --git a/src/endWeek/saPregnancy.js b/src/endWeek/saPregnancy.js
index e5bd63bc7657224f08b9fd147e74096c401c6131..daa206a85c9efbd7e00be2b2d84231d893a807af 100644
--- a/src/endWeek/saPregnancy.js
+++ b/src/endWeek/saPregnancy.js
@@ -615,6 +615,7 @@ App.SlaveAssignment.pregnancy = function saPregnancy(slave) {
 	 */
 	function pregnancyPhysicalEffects(slave) {
 		let boobTarget;
+		const slimnessFoodMod = V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 ? 0.5 : 1;
 		if (slave.geneMods.NCS === 1) {
 			// NCS: always working against secondary sexual characteristics even in pregnancies.
 			boobTarget = 0;
@@ -668,6 +669,7 @@ App.SlaveAssignment.pregnancy = function saPregnancy(slave) {
 			}
 		}
 		boobTarget *= gigantomastiaMod;
+		boobTarget *= slimnessFoodMod;
 		if (slave.geneMods.NCS === 0) {
 			const boobSize = slave.boobs - slave.boobsImplant - slave.boobsMilk;
 			const buttSize = slave.butt - slave.buttImplant;
diff --git a/src/endWeek/saRules.js b/src/endWeek/saRules.js
index 3159403d045d5485a83eb9b3eb8bda17c3c0a45a..673579c6180cba2948ebb9705932c0d5fcccede4 100644
--- a/src/endWeek/saRules.js
+++ b/src/endWeek/saRules.js
@@ -629,7 +629,7 @@ App.SlaveAssignment.rules = function(slave) {
 										if (!hasAnyArms(slave)) {
 											r.push(`imagination`);
 										} else {
-											r.push(`${hands}.`);
+											r.push(`${hands}`);
 										}
 										r.push(`and toys, but <span class="mediumaquamarine">understands you care about ${his} current health.</span>`);
 										slave.trust += 1;
diff --git a/src/endWeek/saSharedVariables.js b/src/endWeek/saSharedVariables.js
index 3b7255854e87076ded393192b5e12fc77c9852b0..d4c7d2942ea2b35b34452bc6f74fa075ca644e8a 100644
--- a/src/endWeek/saSharedVariables.js
+++ b/src/endWeek/saSharedVariables.js
@@ -39,6 +39,11 @@ App.EndWeek.SASharedVariables = class {
 		 *  @see App.EndWeek.getFLSex
 		 */
 		this.flSex = new Set();
+		/**
+		 * Assignments texts for slaves who choose their own assignment, set in App.SlaveAssignment.choosesOwnJob()
+		 * @type {Object.<number, string>}
+		 */
+		this.choosesOwnAssignmentText = {};
 	}
 
 	/** Compute shared subslave ratio (subslaves per ordinary slave) */
diff --git a/src/endWeek/saSocialEffects.js b/src/endWeek/saSocialEffects.js
index d1ab2bd2cb86e2c3b3b6ce5c08eea49f4795a945..f44a50ee2530698c00314dbac824a7f897a1575c 100644
--- a/src/endWeek/saSocialEffects.js
+++ b/src/endWeek/saSocialEffects.js
@@ -1,9 +1,9 @@
 /** Apply and return description of social effects
  * @param {FC.ReportSlave} slave
- * @returns {DocumentFragment}
  */
 App.SlaveAssignment.saSocialEffects = function(slave) {
 	const {His, his, him, he, girl, wife} = getPronouns(slave);
+	let netFailedElite = 0;
 
 	/** Build a social effect object
 	 * @param {FC.FutureSocietyDeco|""} FS
@@ -228,10 +228,10 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 				repopRacialPregnancy();
 			} else if (V.arcologies[0].FSSubjugationist !== "unset" && (slave.race === V.arcologies[0].FSSubjugationistRace) && slave.bellyImplant >= 1500) {
 				t.push(new SocialEffect("", 0.1, "Belly implant for inferior race (Repopulation Focus)",
-					`Society <span class="green">is satisfied</span> with ${slave.slaveName}'s implant filled belly since ${his} kind really shouldn't be breeding.`));
+					`Society <span class="green">is satisfied</span> with ${slave.slaveName}'s implant-filled belly since ${his} kind really shouldn't be breeding.`));
 			} else if (slave.bellyImplant >= 1500 && ((slave.ovaries === 0 && slave.mpreg === 0) || slave.preg < -1)) {
 				t.push(new SocialEffect("", 0.1, "Belly implant for infertile slave (Repopulation Focus)",
-					`Society <span class="green">accepts</span> ${slave.slaveName}'s implant filled belly due to ${his} infertility.`));
+					`Society <span class="green">accepts</span> ${slave.slaveName}'s implant-filled belly due to ${his} infertility.`));
 			} else if (slave.collar === "preg biometrics" && slave.preg > 0) {
 				t.push(new SocialEffect("Repopulationist", 1, "Pregnancy biometrics",
 					`Society is <span class="green">pleased</span> by ${slave.slaveName}'s collar revealing ${his} womb's secret${slave.pregType > 1 ? 's' : ''} even when ${his} body is trying its best to keep ${slave.pregType > 1 ? "them" : "it"} hidden.`));
@@ -290,7 +290,7 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 						r.push(`an Elite`);
 					}
 					r.push(`child${slave.pregType > 1 ? 'ren are' : ' is'} growing within ${him}. The mark covering ${his} lower belly, coupled with ${his} gravidity and blessing, <span class="green">enamors</span> your populace.`);
-					V.failedElite -= (5 + slave.pregType);
+					netFailedElite -= (5 + slave.pregType);
 					t.push(new SocialEffect("Eugenics", 3, "Breeder carrying elite baby", r.join(' ')));
 					if (slave.abortionTat > 0) {
 						r = [];
@@ -330,7 +330,7 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 				if (slave.pregKnown === 1 && V.eugenicsFullControl !== 1) {
 					t.push(new SocialEffect("Eugenics", 0, "Unapproved pregnancy (ELITE WARNING)",
 						`The Societal Elite <span class="red">judge you</span> for keeping pregnant slaves. It falls to the slaveowner to deal with subhuman pregnancies and you are failing in your duties as a member of the Elite.`));
-					V.failedElite += (5 + slave.pregType);
+					netFailedElite += (5 + slave.pregType);
 				}
 			}
 			if (slave.balls > 0 && slave.pubertyXY === 1 && slave.vasectomy === 0 && slave.ballType !== "sterile") {
@@ -959,6 +959,9 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 				}
 			}
 		}
+
+		// apply elite failure
+		V.failedElite += netFailedElite;
 	}
 
 	function renderTooltip() {
@@ -993,65 +996,91 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 		return el;
 	}
 
-	function displayCompressed() {
-		const positiveSum = socialEffects.filter(e => e.magnitude > 0).reduce((acc, cur) => acc += cur.magnitude, 0);
-		const negativeSum = socialEffects.filter(e => e.magnitude < 0).reduce((acc, cur) => acc += cur.magnitude, 0);
+	function report() {
+		function displayCompressed() {
+			const positiveSum = socialEffects.filter(e => e.magnitude > 0).reduce((acc, cur) => acc += cur.magnitude, 0);
+			const negativeSum = socialEffects.filter(e => e.magnitude < 0).reduce((acc, cur) => acc += cur.magnitude, 0);
 
-		const sumFrag = document.createDocumentFragment();
-		sumFrag.append(`(`);
-		App.UI.DOM.appendNewElement("span", sumFrag, '+' + positiveSum.toString(), positiveSum > 0 ? "green" : "gray");
-		sumFrag.append(`/`);
-		App.UI.DOM.appendNewElement("span", sumFrag, '-' + Math.abs(negativeSum).toString(), negativeSum < 0 ? "red" : "gray"); // literal '-' + Math.abs needed to handle 0 case
-		sumFrag.append(`)`);
+			const sumFrag = document.createDocumentFragment();
+			sumFrag.append(`(`);
+			App.UI.DOM.appendNewElement("span", sumFrag, '+' + positiveSum.toString(), positiveSum > 0 ? "green" : "gray");
+			sumFrag.append(`/`);
+			App.UI.DOM.appendNewElement("span", sumFrag, '-' + Math.abs(negativeSum).toString(), negativeSum < 0 ? "red" : "gray"); // literal '-' + Math.abs needed to handle 0 case
+			sumFrag.append(`)`);
 
-		const sum = positiveSum + negativeSum;
-		frag.append(`Society has a `);
-		if (sum > 0) {
-			const opinion = App.UI.DOM.makeElement("span", "positive", ["green", "major-link", "has-tooltip"]);
-			tippy(opinion, {content: renderTooltip(), placement: "right"});
-			frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `, which improves your reputation and advances social progress.`);
-		} else if (sum === 0) {
-			const opinion = App.UI.DOM.makeElement("span", "neutral", ["yellow", "major-link", "has-tooltip"]);
-			tippy(opinion, {content: renderTooltip(), placement: "right"});
-			frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `; ${he} had no net impact on your reputation or social progress this week.`);
-		} else {
-			const opinion = App.UI.DOM.makeElement("span", "negative", ["red", "major-link", "has-tooltip"]);
-			tippy(opinion, {content: renderTooltip(), placement: "right"});
-			frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `, which decreases your reputation and retards social progress.`);
+			const sum = positiveSum + negativeSum;
+			frag.append(`Society has a `);
+			if (sum > 0) {
+				const opinion = App.UI.DOM.makeElement("span", "positive", ["green", "major-link", "has-tooltip"]);
+				tippy(opinion, {content: renderTooltip(), placement: "right"});
+				frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `, which improves your reputation and advances social progress.`);
+			} else if (sum === 0) {
+				const opinion = App.UI.DOM.makeElement("span", "neutral", ["yellow", "major-link", "has-tooltip"]);
+				tippy(opinion, {content: renderTooltip(), placement: "right"});
+				frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `; ${he} had no net impact on your reputation or social progress this week.`);
+			} else {
+				const opinion = App.UI.DOM.makeElement("span", "negative", ["red", "major-link", "has-tooltip"]);
+				tippy(opinion, {content: renderTooltip(), placement: "right"});
+				frag.append(opinion, ` overall view of ${slave.slaveName} `, sumFrag, `, which decreases your reputation and retards social progress.`);
+			}
 		}
-	}
 
-	function displayLong() {
-		$(frag).append(socialEffects.map(e => e.longDesc).join(" "));
-	}
+		function displayLong() {
+			$(frag).append(socialEffects.map(e => e.longDesc).join(" "));
+		}
 
-	const frag = document.createDocumentFragment();
+		const frag = document.createDocumentFragment();
 
-	let socialEffects = [];
-	if (V.FSAnnounced > 0) {
-		if (V.studio === 1) {
-			if (slave.porn.viewerCount > 0) {
-				slave.pornFameBonus += (Math.ceil(slave.porn.viewerCount / 100000));
-				if (slave.porn.viewerCount >= 100000) {
-					frag.append(`${His} near-ubiquitous presence in arcology pornography greatly increases ${his} impact on society. `);
-				} else if (slave.porn.viewerCount >= 10000) {
-					frag.append(`${His} presence in arcology pornography increases ${his} impact on society. `);
-				} else {
-					frag.append(`${His} occasional presence in arcology pornography slightly increases ${his} impact on society. `);
+		if (V.FSAnnounced > 0) {
+			if (V.studio === 1) {
+				if (slave.porn.viewerCount > 0) {
+					slave.pornFameBonus += (Math.ceil(slave.porn.viewerCount / 100000));
+					if (slave.porn.viewerCount >= 100000) {
+						frag.append(`${His} near-ubiquitous presence in arcology pornography greatly increases ${his} impact on society. `);
+					} else if (slave.porn.viewerCount >= 10000) {
+						frag.append(`${His} presence in arcology pornography increases ${his} impact on society. `);
+					} else {
+						frag.append(`${His} occasional presence in arcology pornography slightly increases ${his} impact on society. `);
+					}
 				}
 			}
 		}
-		socialEffects.push(...makeSocialEffects());
+		if (socialEffects.length > 0) {
+			applySocialEffects();
+			if (!V.UI.compressSocialEffects) {
+				displayLong();
+			} else {
+				displayCompressed();
+			}
+		}
+
+		return frag;
 	}
-	socialEffects.push(...makeShelterGirlEffects());
-	if (socialEffects.length > 0) {
-		applySocialEffects();
-		if (!V.UI.compressSocialEffects) {
-			displayLong();
-		} else {
-			displayCompressed();
+
+	/** Test what new social effects this slave would gain if a new FS were added
+	 *  Note that this function does not currently take into account the social effects
+	 *  that would be *lost* if a new FS was enacted; this is a rare but extant case.
+	 * @param {FC.FutureSociety} proposedFS
+	 */
+	function newForFS(proposedFS) {
+		// make sure the FS is not currently enacted
+		if (V.arcologies[0][proposedFS] !== "unset") {
+			throw new Error(`Cannot test new FS social effects for existing FS ${proposedFS}`);
 		}
+		// temporarily enact the FS at full strength
+		V.arcologies[0][proposedFS] = 100;
+		// see what the slave's social effects would be under the proposed FS
+		const newSocialEffects =  [...makeSocialEffects(), ...makeShelterGirlEffects()];
+		// undo the temporary FS enactment
+		V.arcologies[0][proposedFS] = "unset";
+		// return the differences between the current and new states
+		return _.differenceBy(newSocialEffects, socialEffects, s => s.shortDesc);
 	}
 
-	return frag;
+	const socialEffects = [...makeSocialEffects(), ...makeShelterGirlEffects()];
+
+	return {
+		report,
+		newForFS
+	};
 };
diff --git a/src/endWeek/saStayConfined.js b/src/endWeek/saStayConfined.js
index 0d5cd6f70bd16d0e3d290bf9566f6c49632ce18c..8bdb4c15035568edd7310b2b28ec0078554b3584 100644
--- a/src/endWeek/saStayConfined.js
+++ b/src/endWeek/saStayConfined.js
@@ -12,7 +12,6 @@ App.SlaveAssignment.stayConfined = function(slave) {
 	const {
 		he, him, his, He, His
 	} = getPronouns(slave);
-	/* eslint-enable */
 
 	let t = "";
 	let brokenSlaves = false;
@@ -118,12 +117,7 @@ App.SlaveAssignment.stayConfined = function(slave) {
 	}
 
 	if (slave.sentence !== 0) {
-		t += ` ${He} has ${slave.sentence}`;
-		if (slave.sentence === 1) {
-			t += ` week remaining.`;
-		} else {
-			t += ` weeks remaining.`;
-		}
+		t += ` ${He} has ${numberWithPluralOne(slave.sentence, "week")} remaining.`;
 	} else if (slave.devotion > 20 || (slave.devotion >= -20 && slave.trust < -20) || (slave.devotion >= -50 && slave.trust < -50) || slave.fetish === Fetish.MINDBROKEN) {
 		if (slave.fetish === Fetish.MINDBROKEN) {
 			t += ` ${His} broken mind hinges entirely on other's guidance,`;
diff --git a/src/endWeek/slaveAssignmentReport.js b/src/endWeek/slaveAssignmentReport.js
index 81520140134b66176f0f31f64e0465a5b592d5b4..22c821c75c6275ab7719b46786e58ab99a254713 100644
--- a/src/endWeek/slaveAssignmentReport.js
+++ b/src/endWeek/slaveAssignmentReport.js
@@ -38,7 +38,7 @@ App.EndWeek.slaveAssignmentReport = function() {
 		// fire unqualified special slaves
 		_ensureEmployeeMeetsJobRequirements(slave);
 
-		// first pass on choosesOwnJob is silent
+		// allow slaves to choose their jobs for later output
 		if (slave.choosesOwnAssignment === 1) {
 			App.SlaveAssignment.choosesOwnJob(slave);
 		}
@@ -165,7 +165,7 @@ App.EndWeek.slaveAssignmentReport = function() {
 	if (V.HeadGirlID !== 0) {
 		App.EndWeek.saVars.HGEnergy++;
 		const slave = slaveStateById(V.HeadGirlID);
-		if (V.personalAttention.task === PersonalAttention.SUPPORTHG && V.PC.health.shortDamage < 30) {
+		if (V.personalAttention.task === PersonalAttention.SUPPORTHG) { // onBedRest trigger here!
 			App.EndWeek.saVars.HGEnergy++;
 			if (slave.trust > 95) {
 				App.EndWeek.saVars.HGEnergy++;
diff --git a/src/endWeek/standardSlaveReport.js b/src/endWeek/standardSlaveReport.js
index 9faa88abd3379699f31a845e2c4aee823546fbd2..9890556c28192c4147d8b311487fd6c9d449df12 100644
--- a/src/endWeek/standardSlaveReport.js
+++ b/src/endWeek/standardSlaveReport.js
@@ -1,5 +1,5 @@
 /**
- * Generates (and returns if not silent) a standard slave report
+ * Generates (and returns if not silent) a standard slave report.
  * This is the part after the slave's job in most facilities.
  * @param {FC.ReportSlave} slave
  * @param {boolean} silent
@@ -47,13 +47,33 @@ App.SlaveAssignment.appendSlaveArt = function(node, slave) {
 };
 
 /**
- * Render favorite and reminder links
- * @param {ParentNode} node
+ * Render slave name (with popup link) and favorite and reminder links
  * @param {App.Entity.SlaveState} slave
  */
-App.SlaveAssignment.appendSlaveLinks = function(node, slave) {
-	node.append(
+App.SlaveAssignment.saSlaveName = function(slave) {
+	const frag = new DocumentFragment();
+	const popup = App.UI.DOM.slaveDescriptionDialog(slave, SlaveFullName(slave));
+	popup.classList.add("slave-name", "bold");
+	frag.append(
 		App.UI.favoriteToggle(slave), " ",
-		App.Reminders.slaveLink(slave.ID), " "
+		App.Reminders.slaveLink(slave.ID), " ",
+		popup, " "
 	);
+	return frag;
+};
+
+/**
+ * Render linkified slave name with job assignment statement.
+ * @param {App.Entity.SlaveState} slave
+ * @param {string} def - this statement will be used if the slave ISN'T choosing her own job.  Generally, something like "is <verb>ing in <facility>."  Note that penthouse jobs do not have a default job statement, instead leading directly into the job text if the slave is not choosing her own job.
+ */
+App.SlaveAssignment.saSlaveIntro = function(slave, def) {
+	const frag = this.saSlaveName(slave);
+	const choice = App.EndWeek.saVars.choosesOwnAssignmentText[slave.ID];
+	if (slave.choosesOwnAssignment && choice) {
+		$(frag).append(choice);
+	} else {
+		$(frag).append(def);
+	}
+	return frag;
 };
diff --git a/src/events/Elites/pInsemination.js b/src/events/Elites/pInsemination.js
index 115726754551c88cdf474f51e0b52d9bfa904b26..bfaa4eb1a8d1336c0c86a264f779476ff1997f8c 100644
--- a/src/events/Elites/pInsemination.js
+++ b/src/events/Elites/pInsemination.js
@@ -122,7 +122,7 @@ App.Events.PInsemination = class PInsemination extends App.Events.BaseEvent {
 						}
 						r.push(`as she thrusts up into you, driving you wild with lust. It doesn't take long for you to start bucking with orgasm and wrapping your arms around her gravid middle. Her occupants send several kicks your way as she quickens her pace, grabs your hips, and thrusts hard, cumming deep in your pussy. Panting, you slide off her and snuggle up beside her as you catch your breath. "You're looking good after having a child, you know? But obviously you looked even better heavy with my child. I'm keeping those pictures of you close!" she says with a giggle as you rise. With a gentle pat on your bottom, she sends you on your way.`);
 					} else {
-						r.push(`You arrive once more at the apartment of the heavily pregnant futa, though this time she takes a while to reach the door by the sound of it. When it opens, you are greeted by her usual smile and an octuplets stuffed belly. She grabs your hand and pulls it to her taut middle. "Feel them kick! There's so many of them, it feels amazing!" You wrap your arms around your heavy lover for the evening and help her back to her bed, savoring the weight of her pregnancy. She stops you once she takes a seat and asks "My offer still stands, cutie. I assure you it feels amazing to be so full of babies." You shake your head "no"; being that pregnant would definitely impede your ability to run the arcology and even enjoy your slaves properly. She lies back, before shifting her weight to her side out of discomfort. Her belly is really big, and hangs low enough that reaching her needy cock is quite the challenge; you take a moment to think of a good position to receive her. You take her dick, and gently sliding yourself between her legs, fit it into your pussy. The two of you buck against each other as best you can; a struggle, seeing as you are bearing the weight of her children right now. You have no choice but to wrap your arms around the eagerly kicking mass${(V.PC.dick !== 0) ? ", trapping your dick between it and yourself," : ""} as you near your climax. You feel your nethers clamp down as she cums, hard, deep into your pussy. Her children shift under your arms as her water breaks onto you. You quickly untangle yourself and help her to her feet; you can't help but enjoy the feeling of her close contractions under your hand. She points you to her bathroom; "Water birth," she pants, struggling to not give birth where she stands. The tub is already prepared for her, so you help her into it. She refuses to let go of your hand, pleading "Join me?" You take her up on the offer and slide in behind her. You massage her taxed stomach as she struggles to bring her children into the world. A loud moan escapes her lips as the first of her children slips from her pussy and into your waiting hands. Setting her aside, you prepare for the next. After several hours, and a mutual shower, you and her recover together with her eight children; as thanks, you have one milky nipple all to yourself. When it's time to leave, she blows you a kiss and thanks you sincerely for helping her through this.`);
+						r.push(`You arrive once more at the apartment of the heavily pregnant futa, though this time she takes a while to reach the door by the sound of it. When it opens, you are greeted by her usual smile and an octuplets-stuffed belly. She grabs your hand and pulls it to her taut middle. "Feel them kick! There's so many of them, it feels amazing!" You wrap your arms around your heavy lover for the evening and help her back to her bed, savoring the weight of her pregnancy. She stops you once she takes a seat and asks "My offer still stands, cutie. I assure you it feels amazing to be so full of babies." You shake your head "no"; being that pregnant would definitely impede your ability to run the arcology and even enjoy your slaves properly. She lies back, before shifting her weight to her side out of discomfort. Her belly is really big, and hangs low enough that reaching her needy cock is quite the challenge; you take a moment to think of a good position to receive her. You take her dick, and gently sliding yourself between her legs, fit it into your pussy. The two of you buck against each other as best you can; a struggle, seeing as you are bearing the weight of her children right now. You have no choice but to wrap your arms around the eagerly kicking mass${(V.PC.dick !== 0) ? ", trapping your dick between it and yourself," : ""} as you near your climax. You feel your nethers clamp down as she cums, hard, deep into your pussy. Her children shift under your arms as her water breaks onto you. You quickly untangle yourself and help her to her feet; you can't help but enjoy the feeling of her close contractions under your hand. She points you to her bathroom; "Water birth," she pants, struggling to not give birth where she stands. The tub is already prepared for her, so you help her into it. She refuses to let go of your hand, pleading "Join me?" You take her up on the offer and slide in behind her. You massage her taxed stomach as she struggles to bring her children into the world. A loud moan escapes her lips as the first of her children slips from her pussy and into your waiting hands. Setting her aside, you prepare for the next. After several hours, and a mutual shower, you and her recover together with her eight children; as thanks, you have one milky nipple all to yourself. When it's time to leave, she blows you a kiss and thanks you sincerely for helping her through this.`);
 					}
 					V.PC.counter.preggo++;
 			}
diff --git a/src/events/PE/pePitFight.js b/src/events/PE/pePitFight.js
index 456ccc7b30e1e63c448a811d4a06ca702a9334fd..2dc2ac51f19c7f30bee69840f8cc0e3792767a84 100644
--- a/src/events/PE/pePitFight.js
+++ b/src/events/PE/pePitFight.js
@@ -117,23 +117,23 @@ App.Events.PEPitFight = class PEPitFight extends App.Events.BaseEvent {
 			}
 		} else if (slave.bellyImplant >= 1500) {
 			if (slave.bellyImplant >= 750000) {
-				r.push(`${His} monolithic, ${slave.bellyImplant}cc implant filled belly guarantees ${his} loss; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`);
+				r.push(`${His} monolithic, ${slave.bellyImplant}cc implant-filled belly guarantees ${his} loss; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`);
 			} else if (slave.bellyImplant >= 600000) {
-				r.push(`${His} titanic, ${slave.bellyImplant}cc implant filled belly is practically a guaranteed loss; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`);
+				r.push(`${His} titanic, ${slave.bellyImplant}cc implant-filled belly is practically a guaranteed loss; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`);
 			} else if (slave.bellyImplant >= 450000) {
-				r.push(`${His} gigantic, ${slave.bellyImplant}cc implant filled belly is nearly a guaranteed loss; it presents an unmissable, indefensible target for ${his} adversary.`);
+				r.push(`${His} gigantic, ${slave.bellyImplant}cc implant-filled belly is nearly a guaranteed loss; it presents an unmissable, indefensible target for ${his} adversary.`);
 			} else if (slave.bellyImplant >= 300000) {
-				r.push(`${His} massive, ${slave.bellyImplant}cc implant filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`);
+				r.push(`${His} massive, ${slave.bellyImplant}cc implant-filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`);
 			} else if (slave.bellyImplant >= 150000) {
-				r.push(`${His} giant, ${slave.bellyImplant}cc implant filled belly obstructs ${his} movement and greatly slows ${him} down.`);
+				r.push(`${His} giant, ${slave.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down.`);
 			} else if (slave.bellyImplant >= 100000) {
-				r.push(`${His} giant, ${slave.bellyImplant}cc implant filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
+				r.push(`${His} giant, ${slave.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
 			} else if (slave.bellyImplant >= 10000) {
-				r.push(`${His} huge, ${slave.bellyImplant}cc implant filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
+				r.push(`${His} huge, ${slave.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`);
 			} else if (slave.bellyImplant >= 5000) {
-				r.push(`${His} large, ${slave.bellyImplant}cc implant filled belly is heavy and unwieldy, rendering ${him} less effective.`);
+				r.push(`${His} large, ${slave.bellyImplant}cc implant-filled belly is heavy and unwieldy, rendering ${him} less effective.`);
 			} else if (slave.bellyImplant >= 1500) {
-				r.push(`${His} swollen, ${slave.bellyImplant}cc implant filled belly is heavy and makes ${him} less effective.`);
+				r.push(`${His} swollen, ${slave.bellyImplant}cc implant-filled belly is heavy and makes ${him} less effective.`);
 			}
 		}
 		if (isInLabor(slave)) {
diff --git a/src/events/RE/reAWOL.js b/src/events/RE/reAWOL.js
index a962091df7ba7a34e6eb5db225201f560b66f111..bec0e3d75ab4829d402d2bfb49c837c7f11beabc 100644
--- a/src/events/RE/reAWOL.js
+++ b/src/events/RE/reAWOL.js
@@ -32,7 +32,8 @@ App.Events.REAWOL = class REAWOL extends App.Events.BaseEvent {
 		slave.skill.combat = 1;
 		slave.behavioralFlaw = "arrogant";
 		slave.sexualFlaw = "crude";
-		slave.hStyle = "shaved into a mohawk";
+		slave.hStyle = "strip";
+		slave.hLength = 5;
 		slave.custom.tattoo = "$He has a number of tattoos from a variety of mercenary companies.";
 		slave.clothes = "a military uniform";
 
diff --git a/src/events/RE/reFullBed.js b/src/events/RE/reFullBed.js
index aa857c728e10dcd3d049885161f8698a0bfd655f..a79b378669cd25647710b3caae3ce48a829952eb 100644
--- a/src/events/RE/reFullBed.js
+++ b/src/events/RE/reFullBed.js
@@ -244,9 +244,9 @@ App.Events.REFullBed = class REFullBed extends App.Events.BaseEvent {
 			}
 			t.push(`belly and cum pooling from their thoroughly seeded holes. You slide back in between them for a well earned`);
 			if (V.PC.balls >= 30) {
-				t.push(`sleep, their middles resting on your own, their cum stuffed wombs a testament to your virility.`);
+				t.push(`sleep, their middles resting on your own, their cum-stuffed wombs a testament to your virility.`);
 			} else if (V.PC.balls >= 14) {
-				t.push(`sleep, their middles resting on your own, their cum filled wombs a testament to your virility.`);
+				t.push(`sleep, their middles resting on your own, their cum-filled wombs a testament to your virility.`);
 			} else {
 				t.push(`sleep.`);
 			}
diff --git a/src/events/RE/reLegendaryCow.js b/src/events/RE/reLegendaryCow.js
index 2ecb928cbca0aa9b5d62293f188d93a71f51ba28..bac7d53233e4691563ffbe72bbc001a34fa9f58b 100644
--- a/src/events/RE/reLegendaryCow.js
+++ b/src/events/RE/reLegendaryCow.js
@@ -28,7 +28,7 @@ App.Events.RELegendaryCow = class RELegendaryCow extends App.Events.BaseEvent {
 
 		r.push(
 			App.UI.DOM.slaveDescriptionDialog(slave),
-			`is an incredible producer of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk. ${He}'s lactating in volumes that would have been unthinkable in the days when drug treatments were limited by consent. A nascent slave dairy trade organization will be holding a public stock show tomorrow, and since they're aware you keep cows, they've sent you an invitation to enter stock to be judged.`
+			`is an incredible producer of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk. ${He}'s lactating in volumes that would have been unthinkable in the days when drug treatments were limited by consent. A nascent slave dairy trade organization will be holding a public stock show tomorrow, and since they're aware you keep cows, they've sent you an invitation to enter stock to be judged.`
 		);
 
 		App.Events.addParagraph(node, r);
@@ -109,7 +109,7 @@ App.Events.RELegendaryCow = class RELegendaryCow extends App.Events.BaseEvent {
 					id: slave.ID
 				});
 			} else {
-				r.push(`${slave.slaveName} is shown in public, closely inspected by the judging committee, and then publicly milked. You are surprised to see that the judging committee has been changed at the last minute. They choose another cow as best in show. There are persistent <span class="reputation inc">rumors</span> after the show that there was an absolute massacre of firings at the dairy organization headquarters the night before the show after it was discovered that someone, widely thought to be you, had been corrupting the judges.`);
+				r.push(`${slave.slaveName} is shown in public, closely inspected by the judging committee, and then publicly milked. You are surprised to see that the judging committee has been changed at the last minute. They choose another cow as best in show. There are persistent <span class="reputation dec">rumors</span> after the show that there was an absolute massacre of firings at the dairy organization headquarters the night before the show after it was discovered that someone, widely thought to be you, had been corrupting the judges.`);
 				repX(-100, "event", slave);
 			}
 			App.Events.addParagraph(frag, r);
diff --git a/src/events/RE/reMalefactor.js b/src/events/RE/reMalefactor.js
index fd2f9c636917ffaa3e9ae9b446233c27c1a2580e..b26f7ec9ae3501fc24764767ef7f3f6c65fa4476 100644
--- a/src/events/RE/reMalefactor.js
+++ b/src/events/RE/reMalefactor.js
@@ -859,7 +859,8 @@ App.Events.REMalefactor = class REMalefactor extends App.Events.BaseEvent {
 					setHealth(slave, jsRandom(60, 80), undefined, undefined, 0, 10);
 					slave.behavioralFlaw = "arrogant";
 					slave.sexualFlaw = "hates penetration";
-					slave.hStyle = "shaved into a mohawk";
+					slave.hStyle = "strip";
+					slave.hLength = 5;
 					slave.custom.tattoo = "$He seems to have had slave tattoos at one time, but has had them cheaply removed.";
 					break;
 				case "passfail":
diff --git a/src/events/RE/rePokerNight.js b/src/events/RE/rePokerNight.js
index d229f9428f02b766e89a1de3bcf872e25a5022a1..0cd724f22311b5b9c44662fb80318d47c9355e45 100644
--- a/src/events/RE/rePokerNight.js
+++ b/src/events/RE/rePokerNight.js
@@ -94,7 +94,8 @@ App.Events.REPokerNight = class REPokerNight extends App.Events.BaseEvent {
 				slave.accent = random(0, 1);
 				slave.behavioralFlaw = "arrogant";
 				slave.hLength = 1;
-				slave.hStyle = "shaved into a mohawk";
+				slave.hStyle = "strip";
+				slave.hLength = 5;
 				slave.custom.tattoo = "$He has a number of tattoos from a variety of mercenary companies.";
 				slave.clothes = "a military uniform";
 				App.Events.drawEventArt(frag, slave);
diff --git a/src/events/RE/rePregInventorFCTV.js b/src/events/RE/rePregInventorFCTV.js
index 0b0ae4ca2e3902f0d169e2850c444d30be564036..889ba4e23a40822b667319c754d4a317ecdeed1b 100644
--- a/src/events/RE/rePregInventorFCTV.js
+++ b/src/events/RE/rePregInventorFCTV.js
@@ -470,7 +470,7 @@ App.Events.rePregInventorFCTV = class rePregInventorFCTV extends App.Events.Base
 			}
 			App.Events.addParagraph(el, r);
 			r = [];
-			r.push(`The host quirks an eyebrow, then nods. "Alright," she says. "How about we start with that pool of yours?" She then strips her outer layer of clothing, showing off her own famously heavily pregnant figure in an inadequate bra and panties. She makes her way to the curative jelly filled pool, after your slave has been situated within it. Millie dips a toe into the substance and giggles. "Oh my, it tingles!"`);
+			r.push(`The host quirks an eyebrow, then nods. "Alright," she says. "How about we start with that pool of yours?" She then strips her outer layer of clothing, showing off her own famously heavily pregnant figure in an inadequate bra and panties. She makes her way to the curative jelly-filled pool, after your slave has been situated within it. Millie dips a toe into the substance and giggles. "Oh my, it tingles!"`);
 			App.Events.addParagraph(el, r);
 			r = [];
 			if (canTalk(slave)) {
@@ -522,7 +522,7 @@ App.Events.rePregInventorFCTV = class rePregInventorFCTV extends App.Events.Base
 			} else if (hasAnyArms(slave)) {
 				r.push(`Your slave signs that this was the best method ${he} could think of to keep ${himself} pretty for you, given ${his} size, then starts moaning as a grinning Millie seems to have started enacting her revenge.`);
 			} else {
-				r.push(`Your slave's speaker explains that this was the best method the broodmother could think of to keep ${himself} pretty for you, given ${his} size. The baby laden breeder starts moaning in the middle of ${his} assistant's description as a grinning Millie seems to have taken this opportunity to start enacting her revenge.`);
+				r.push(`Your slave's speaker explains that this was the best method the broodmother could think of to keep ${himself} pretty for you, given ${his} size. The baby-laden breeder starts moaning in the middle of ${his} assistant's description as a grinning Millie seems to have taken this opportunity to start enacting her revenge.`);
 			}
 			r.push(`Millie has turned her body sideways and snaked an arm between`);
 			if (slave.boobs >= 20000) {
diff --git a/src/events/RE/reShelterInspection.js b/src/events/RE/reShelterInspection.js
index 3035e26debb6367521314762a5c78411ba4a8f4c..9c445ee2c64da348b2319ea9e00d5d7e20b4083d 100644
--- a/src/events/RE/reShelterInspection.js
+++ b/src/events/RE/reShelterInspection.js
@@ -695,7 +695,7 @@ App.Events.REShelterInspection = class REShelterInspection extends App.Events.Ba
 							r.push(Spoken(inspectee, `"I'm a milk cow!"`));
 							r.push(`The inspector arches an eyebrow skeptically, and the slave continues,`);
 							r.push(Spoken(inspectee, `"I give milk. See?"`));
-							r.push(`${He} expresses a squirt of ${inspectee.milkFlavor === "none" ? `` : `${inspectee.milkFlavor} flavored `}milk from one nipple.`);
+							r.push(`${He} expresses a squirt of ${inspectee.milkFlavor === "none" ? `` : `${inspectee.milkFlavor}-flavored `}milk from one nipple.`);
 							r.push(Spoken(inspectee, `"It's a nice life. I'm much happier with my current owner, thank you."`));
 							r.push(`The inspector looks pleased, and ${say2}s ${he2}'ll put out a <span class="reputation inc">good word</span> about you.`);
 							repX(500, "event", inspectee);
diff --git a/src/events/RECI/milf.js b/src/events/RECI/milf.js
index d2f4d47294c4050d8f9bd632b06307deec2a618e..25d1dd749b600ec4ed0cb05de881e593827ae234 100644
--- a/src/events/RECI/milf.js
+++ b/src/events/RECI/milf.js
@@ -680,7 +680,7 @@ App.Events.RECIMilf = class RECIMilf extends App.Events.BaseEvent {
 				} else if (eventSlave.bellyImplant >= 2000) {
 					t.push(`massaging the taut skin of ${his} belly before teasing ${his} popped navel.`);
 				} else {
-					t.push(`cupping the hugely bloated expanse of ${his} fluid filled middle.`);
+					t.push(`cupping the hugely bloated expanse of ${his} fluid-filled middle.`);
 				}
 			} else if (eventSlave.weight > 130) {
 				t.push(`fondling and groping the soft mass of ${his} hugely fat belly.`);
diff --git a/src/events/REFI/reBoobslut.js b/src/events/REFI/reBoobslut.js
index b88b01ba877301d44fd4b097cd3e143b5f7c7495..66c1ef5bfffeea9a9471481c9c35bc04f53aeaad 100644
--- a/src/events/REFI/reBoobslut.js
+++ b/src/events/REFI/reBoobslut.js
@@ -53,7 +53,7 @@ App.Events.REFIBoobslut = class REFIBoobslut extends App.Events.BaseEvent {
 		} else {
 			t.push("over,");
 		}
-		t.push(`take some of ${his2} creamy, ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk straight from the source. Every time you do, ${he2} shudders convulsively,`);
+		t.push(`take some of ${his2} creamy${subSlave.milkFlavor === "none" ? `` : `, ${subSlave.milkFlavor}-flavored`} milk straight from the source. Every time you do, ${he2} shudders convulsively,`);
 		if (canTalk(subSlave)) {
 			t.push(`giving little mewling whimpers.`);
 		} else {
diff --git a/src/events/REFI/reSadist.js b/src/events/REFI/reSadist.js
index d2075b4dbbf3d2c65ce5017e33cea1184e8e20bf..b2d4d092c23507ffdbf34c69fd3f1660afd70b79 100644
--- a/src/events/REFI/reSadist.js
+++ b/src/events/REFI/reSadist.js
@@ -98,20 +98,10 @@ App.Events.REFISadist = class REFISadist extends App.Events.BaseEvent {
 
 		App.Events.addParagraph(node, t);
 		App.Events.addResponses(node, [
-			new App.Events.Result(`Show ${him} how enjoyable causing pain is`, turn, virginityWarning()),
+			new App.Events.Result(`Show ${him} how enjoyable causing pain is`, turn),
 			new App.Events.Result(`Steer ${him} away from an obsession with causing pain for the moment`, steer),
 		]);
 
-		function virginityWarning() {
-			if (canDoAnal(eventSlave) && (eventSlave.anus === 0)) {
-				return `This option will take ${his} anal virginity`;
-			} else if (!canDoAnal(eventSlave) && canDoVaginal(eventSlave) && (eventSlave.vagina === 0)) {
-				return `This option will take ${his} virginity`;
-			}
-			return null;
-		}
-
-
 		function turn() {
 			t = [];
 			if (!canTalk(eventSlave)) {
diff --git a/src/events/REFS/refsYouthPreferentialistEncounter.js b/src/events/REFS/refsYouthPreferentialistEncounter.js
index 602ade45ac05463e7c5fcbce119182850de3f80c..b6ede6649d6c130594bfc5a5dfa9f97caf4be329 100644
--- a/src/events/REFS/refsYouthPreferentialistEncounter.js
+++ b/src/events/REFS/refsYouthPreferentialistEncounter.js
@@ -32,7 +32,15 @@ App.Events.refsYouthPreferentialistEncounter = class refsYouthPreferentialistEnc
 
 		App.Events.addParagraph(node, [`Your excursions out of your penthouse and into the arcology as a whole often put you in close proximity with citizens from all levels of the social strata. After all, they themselves have their own lives to live within the walls of ${V.arcologies[0].name}.`]);
 
-		App.Events.addParagraph(node, [`On this particular outing you happen to cross paths with a nubile young ${woman}, accompanied by ${his} father. From ${his} plain clothes and rudimentary makeup, it is readily apparent that ${he} is not one of the arcology's well-to-do inhabitants. ${He} recognizes you quickly and dips ${his} head in deference to your high status, ${(V.PC.visualAge >= 50) ? `${his} cheeks flushed in embarrassment and delight at an aged arcology owner's interest in a young ${girl} like ${him}.` : `${his} expression awestruck by the presence of an arcology owner before ${him}.`}`]);
+		let womanTerm = `little ${girl}`;
+		if (slave.physicalAge > 19) {
+			womanTerm = `young ${woman}`;
+		} else if (slave.physicalAge > 12) {
+			womanTerm = `teen`;
+		} else if (slave.physicalAge > 9) {
+			womanTerm = `pre-teen`;
+		}
+		App.Events.addParagraph(node, [`On this particular outing you happen to cross paths with a nubile ${womanTerm}, accompanied by ${his} father. From ${his} plain clothes and rudimentary makeup, it is readily apparent that ${he} is not one of the arcology's well-to-do inhabitants. ${He} recognizes you quickly and dips ${his} head in deference to your high status, ${(V.PC.visualAge >= 50) ? `${his} cheeks flushed in embarrassment and delight at an aged arcology owner's interest in a young ${girl} like ${him}.` : `${his} expression awestruck by the presence of an arcology owner before ${him}.`}`]);
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Let them pass`, ignore));
@@ -52,7 +60,7 @@ App.Events.refsYouthPreferentialistEncounter = class refsYouthPreferentialistEnc
 		function pay() {
 			repX(2500, "event");
 			cashX(-cost, "event");
-			return `It takes a moment for you to convince the young ${girl} and ${his} father that you aren't playing some cruel joke on them, but once you do ${he} enthusiastically agrees to be your companion for the evening. With a pretty young thing on your arm for the rest of the night, and ${his} father trailing behind the two of you at a respectful distance, you take ${V.arcologies[0].name} by storm amidst a flurry of speculative whispers and contemplative rumors. Later that night, you conclude your date with a pleasant meal at one of ${V.arcologies[0].name}'s choicest restaurants with fine dining and even finer conversation. To the credit of ${his} father, he politely continues eating his dinner without batting an eye when you${(V.PC.dick === 0) ? ` don a strap-on and` : ''} take his ${daughter} over the dinner table. When you part ways, the young ${girl} is clearly smitten with you — so it's no wonder that by the next day the story of your encounter has <span class="reputation inc">spread across ${V.arcologies[0].name} like wildfire.</span>`;
+			return `It takes a moment for you to convince the young ${girl} and ${his} father that you aren't playing some cruel joke on them, but once you do ${he} enthusiastically agrees to be your companion for the evening. With a pretty young thing on your arm for the rest of the night, and ${his} father trailing behind the two of you at a respectful distance, you take ${V.arcologies[0].name} by storm amidst a flurry of speculative whispers and contemplative rumors. Later that night, you conclude your date with a pleasant meal at one of ${V.arcologies[0].name}'s choicest restaurants with fine dining and even finer conversation. To the credit of ${his} father, he politely continues eating his dinner without batting an eye when you${(V.PC.dick === 0) ? ` don a strap-on and` : ''} take his ${num(slave.physicalAge)}-year-old ${daughter} over the dinner table. When you part ways, the young ${girl} is clearly smitten with you — so it's no wonder that by the next day the story of your encounter has <span class="reputation inc">spread across ${V.arcologies[0].name} like wildfire.</span>`;
 		}
 
 		function fuck() {
@@ -60,7 +68,7 @@ App.Events.refsYouthPreferentialistEncounter = class refsYouthPreferentialistEnc
 			App.Events.refreshEventArt(slave);
 
 			const frag = new DocumentFragment();
-			App.Events.addParagraph(frag, [`It only takes a moment for ${V.assistant.name} to uncover the father's financial records and the copious debt therein, and only another moment for you to browbeat the terrified father into allowing his ${daughter} to sleep with you under threat of purchasing all their debt and summarily enslaving ${him}.`]);
+			App.Events.addParagraph(frag, [`It only takes a moment for ${V.assistant.name} to uncover the father's financial records and the copious debt therein, and only another moment for you to browbeat the terrified father into allowing his ${num(slave.physicalAge)}-year-old ${daughter} to sleep with you under threat of purchasing all their debt and summarily enslaving ${him}.`]);
 
 			App.Events.addParagraph(frag, [`Once you both retire to your private suite, you peel the ${girl}'s clothes off as easily as one might shed a gift of its wrapping. In the nude ${his} body is tastefully youthful, with narrow hips, firm breasts, and a delicate blush across ${his} shamefaced, rosy cheeks. Despite the circumstances of your sexual conquest of ${him}, ${he} seems to enjoy the fuck well enough by the sounds of ${his} frenzied moans — citizens like ${him} often do since sexual submission to a slave would be a crippling scandal to a prominent citizen, let alone one of ${his} diminished social stature.`]);
 			const choices = [];
diff --git a/src/events/RESS/impregnationPlease.js b/src/events/RESS/impregnationPlease.js
index 18f88753b8569409a0dd0bb3721cf0f7a0e6edb9..9f38dac2bb6213681899a9fa57018e407cece425 100644
--- a/src/events/RESS/impregnationPlease.js
+++ b/src/events/RESS/impregnationPlease.js
@@ -269,7 +269,7 @@ App.Events.RESSImpregnationPlease = class RESSImpregnationPlease extends App.Eve
 				if (eventSlave.bellyPreg >= 5000) {
 					r.push(`but the gravid swell of ${his} current pregnancy thwarts ${his} efforts as you take ${him}.`);
 				} else if (eventSlave.belly >= 5000 && eventSlave.boobs < 600) {
-					r.push(`${his} big ${eventSlave.inflationType} stuffed belly pushing against you as you take ${him}.`);
+					r.push(`${his} big ${eventSlave.inflationType}-stuffed belly pushing against you as you take ${him}.`);
 				} else if (V.PC.belly >= 5000) {
 					r.push(`but the best ${he} can do is press ${himself} against your bulging middle.`);
 				} else if (eventSlave.boobs < 600 && eventSlave.belly < 5000) {
@@ -277,7 +277,7 @@ App.Events.RESSImpregnationPlease = class RESSImpregnationPlease extends App.Eve
 				} else if (eventSlave.boobs < 10000) {
 					r.push(`and ${his} big tits`);
 					if (eventSlave.bellyFluid >= 2000) {
-						r.push(`and ${eventSlave.inflationType} stuffed belly`);
+						r.push(`and ${eventSlave.inflationType}-stuffed belly`);
 					}
 					r.push(`form a soft cushion between you as you take ${him}.`);
 				} else {
diff --git a/src/events/RESS/injectionsPlease.js b/src/events/RESS/injectionsPlease.js
index 609d0d3515351fe40b59f481082eba3cd2391a0e..a52dfde5bf6d073f2bec90efe4a12862e3d1f672 100644
--- a/src/events/RESS/injectionsPlease.js
+++ b/src/events/RESS/injectionsPlease.js
@@ -117,6 +117,7 @@ App.Events.RESSInjectionsPlease = class RESSInjectionsPlease extends App.Events.
 					break;
 			}
 			surgeryDamage(eventSlave, 10);
+			App.Events.refreshEventArt(eventSlave);
 			return r;
 		}
 
diff --git a/src/events/RESS/muscles.js b/src/events/RESS/muscles.js
index a8ad178781e1f8d4d23ac7c5caf1547c75f146b4..b8e7a4e2e98063b234baf2bc052fb00f1d6bfb17 100644
--- a/src/events/RESS/muscles.js
+++ b/src/events/RESS/muscles.js
@@ -151,7 +151,7 @@ App.Events.RESSMuscles = class RESSMuscles extends App.Events.BaseEvent {
 					}
 					t.push("pregnant");
 				} else if (eventSlave.bellyFluid >= 5000) {
-					t.push(`${eventSlave.inflationType} filled`);
+					t.push(`${eventSlave.inflationType}-filled`);
 				} else {
 					t.push(`${bellyAdjective(eventSlave)} bellied`);
 				}
diff --git a/src/events/RESS/review/ampDevoted.js b/src/events/RESS/review/ampDevoted.js
index 37905e039d9d0e48b4b975fc86aaea7c217fb0f0..1b7064ed6308805c9e74743d70a8de0bdba101ca 100644
--- a/src/events/RESS/review/ampDevoted.js
+++ b/src/events/RESS/review/ampDevoted.js
@@ -39,7 +39,7 @@ App.Events.RESSAmpDevoted = class RESSAmpDevoted extends App.Events.BaseEvent {
 			} else if (eventSlave.bellyImplant >= 3000) {
 				r.push(`blow-up`);
 			} else {
-				r.push(`${eventSlave.inflationType} filled`);
+				r.push(`${eventSlave.inflationType}-filled`);
 			}
 			r.push(`sex toy`);
 		} else {
diff --git a/src/events/RESS/review/araAra.js b/src/events/RESS/review/araAra.js
index 1c463cb7b0bd01fe2a28ddf407c98141a34489cc..d50d1db1ff5de10ebd7928d68626ac2394a42d7f 100644
--- a/src/events/RESS/review/araAra.js
+++ b/src/events/RESS/review/araAra.js
@@ -32,7 +32,7 @@ App.Events.RESSAraAra = class RESSAraAra extends App.Events.BaseEvent {
 
 		const r = new SpacedTextAccumulator(node);
 		r.push(`Passing by the kitchen in the morning, you take a moment to listen to the low hum of your slaves chatting as they`);
-		if (V.feeder !== 0) {
+		if (V.cockFeeder !== 0) {
 			r.push(`wait their turn at the phallic feeders.`);
 		} else {
 			r.push(`drink their breakfasts.`);
diff --git a/src/events/RESS/review/breastExpansionBlues.js b/src/events/RESS/review/breastExpansionBlues.js
index d255350c5edbb5aa019a615e4df89bc37d28096b..9733202980e0d005642ea56ed56f2ba9ffb2a5e2 100644
--- a/src/events/RESS/review/breastExpansionBlues.js
+++ b/src/events/RESS/review/breastExpansionBlues.js
@@ -161,7 +161,7 @@ App.Events.RESSBreastExpansionBlues = class RESSBreastExpansionBlues extends App
 				if (V.assistant.fsAppearance === "asset expansionist") {
 					r.push(`openly groping ${hisA} own immense breasts while dropping comments about how big you like 'em.`);
 				} else if (V.assistant.fsAppearance === "pastoralist") {
-					r.push(`openly groping ${hisA} milk filled quad-breasts while dropping comments about how you love 'em big and milky.`);
+					r.push(`openly groping ${hisA} milk-filled quad-breasts while dropping comments about how you love 'em big and milky.`);
 				} else if (V.assistant.fsAppearance === "transformation fetishist") {
 					r.push(`openly groping ${hisA} own immense chest balloons while dropping comments about filling ${eventSlave.slaveName} with the biggest implants possible.`);
 				} else {
diff --git a/src/events/RESS/review/firstPeriod.js b/src/events/RESS/review/firstPeriod.js
index 2ca407ad9a5eacfccf50a87a2ad8d5edc9ddd997..a3fa0064042c4463e7ce172dfcb8350dc382ee9d 100644
--- a/src/events/RESS/review/firstPeriod.js
+++ b/src/events/RESS/review/firstPeriod.js
@@ -95,13 +95,21 @@ App.Events.RESSFirstPeriod = class RESSFirstPeriod extends App.Events.BaseEvent
 		function demonstrate() {
 			const frag = new DocumentFragment();
 			let r = [];
+			let restoreChastity = false;
+			if (slave.chastityVagina === 1) {
+				r.push(`You unlock ${his} chastity belt and set it aside, ${his} ${canSee(slave) ? `eyes widening as ${he} watches` : `body stiffening as ${he} feels`} your movements.`);
+				slave.chastityVagina = 0;
+				restoreChastity = true;
+			}
 			r.push(`You tell ${him} that ${he} is just becoming a woman, and to celebrate, you are going to put a child in ${him}.`);
-			if (!canTalk(slave)) {
-				r.push(`${He} gasps and rubs a hand across ${his} stomach.`);
-			} else {
+			if (canTalk(slave)) {
 				r.push(Spoken(slave, `"But I'm still a child myself, ${Master}, I can't get pregnant yet!"`));
+				r.push(`You tell ${him} that prior to this week, that would have been true. However, now that ${he} has become fertile, it's time that ${he} learned what ${his} body was made for.`);
+			} else {
+				r.push(`${He} gasps and rubs a hand across ${his} stomach.`);
+				r.push(`You tell ${him} that ${he} has become fertile, and it's now time that ${he} learned what ${his} body was made for.`);
 			}
-			r.push(`You tell ${him} that prior to this week, that would have been true. However, now that ${he} has become fertile, it's time that ${he} learned what ${his} body was made for. You guide ${him} to the couch and tell ${him} to lie on ${his} back so that you may take ${him}. ${He} breaks down when ${he} feels your cock enter ${his}`);
+			r.push(`You guide ${him} to the couch and tell ${him} to lie on ${his} back so that you may take ${him}. ${He} breaks down when ${he} feels your cock enter ${his}`);
 			if (slave.vagina === 0) {
 				r.push(`delightfully tight, virgin`);
 			} else if (slave.vagina === 1) {
@@ -129,6 +137,11 @@ App.Events.RESSFirstPeriod = class RESSFirstPeriod extends App.Events.BaseEvent
 			WombImpregnate(slave, slave.pregType, -1, 1);
 			r.push(VCheck.Vaginal(slave, 1));
 
+			if (restoreChastity) {
+				r.push(`The deed done, you return ${his} chastity belt to its accustomed place before allowing ${him} to leave your office.`);
+				slave.chastityVagina = 1;
+			}
+
 			App.Events.addParagraph(frag, r);
 			return frag;
 		}
@@ -136,20 +149,29 @@ App.Events.RESSFirstPeriod = class RESSFirstPeriod extends App.Events.BaseEvent
 		function ass() {
 			const frag = new DocumentFragment();
 			let r = [];
-			r.push(`In one swift motion, you pull out a chastity belt and lock it onto ${him}. ${He} gasps as ${he} feels it hug close to ${his} pussy. You explain that ${he} has just become a woman, and thus, will be taking it up the ass until you decide it's time for ${him} to become pregnant.`);
-			if (!canTalk(slave)) {
-				r.push(`${He} rubs a hand across ${his} stomach.`);
-			} else {
+			if (slave.chastityAnus === 1 && slave.chastityVagina === 1) { // double chastity, remove anal
+				r.push(`In one swift motion, you unlock and detach ${his} anal chastity belt. ${He} gasps at the sudden feeling of freedom at ${his} back door.`);
+			} else if (slave.chastityAnus === 1) { // anal chastity, swap for vaginal
+				r.push(`In a few swift motions, you remove ${his} anal chastity belt and replace it with one encasing ${his} vagina. ${He} gasps as ${he} feels it hug close to ${his} pussy.`);
+			} else if (slave.chastityVagina === 1) { // vaginal chastity, don't remove
+				r.push(`You bring your hand to ${his} chastity belt, feigning dramatically that you might remove it, before 'reconsidering' and pulling your hand away.`);
+			} else { // no chastity, give vaginal
+				r.push(`In one swift motion, you pull out a chastity belt and lock it onto ${him}. ${He} gasps as ${he} feels it hug close to ${his} pussy.`);
+			}
+			r.push(`You explain that ${he} has just become a woman, and thus, will be taking it up the ass until you decide it's time for ${him} to become pregnant.`);
+			if (canTalk(slave)) {
 				r.push(Spoken(slave, `"You don't want me to get pregnant, ${Master}?"`));
+			} else {
+				r.push(`${He} rubs a hand across ${his} stomach.`);
 			}
 			r.push(`You bring ${him} over to the couch, set ${him} on your lap, and teasingly call ${him} a buttslut. Every so often you graze a finger around ${his} chastity belt, noting how much ${his} body wants you in ${him}, but you only make it the center of attention once the poor over-aroused slave`);
-			if (!canTalk(slave)) {
-				r.push(`begins to use piteous gestures to beg you abjectly to penetrate ${him}.`);
-			} else {
+			if (canTalk(slave)) {
 				r.push(
 					`${say}s,`,
 					Spoken(slave, `"I can't take it any more, ${Master}! Please fuck me pregnant!"`)
 				);
+			} else {
+				r.push(`begins to use piteous gestures to beg you abjectly to penetrate ${him}.`);
 			}
 			r.push(`You snicker, but remind ${him} that no matter how much ${he} wants to be knocked up, ${his} belt will direct all the dicks ${he} takes into ${his} rear. You line up and insert your`);
 			if (V.PC.dick === 0) {
@@ -171,6 +193,7 @@ App.Events.RESSFirstPeriod = class RESSFirstPeriod extends App.Events.BaseEvent
 			}
 			slave.devotion += 5;
 			slave.chastityVagina = 1;
+			slave.chastityAnus = 0;
 			r.push(VCheck.Anal(slave, 1));
 
 			App.Events.addParagraph(frag, r);
diff --git a/src/events/RESS/review/shiftMasturbation.js b/src/events/RESS/review/shiftMasturbation.js
index cbcdeb2bff270cfd2d873ec8ed39e8f57762add3..61a4e1e4f14c441fe7df7ffef09841b59987881e 100644
--- a/src/events/RESS/review/shiftMasturbation.js
+++ b/src/events/RESS/review/shiftMasturbation.js
@@ -196,7 +196,7 @@ App.Events.RESSShiftMasturbation = class RESSShiftMasturbation extends App.Event
 				r.push(`jerking off,`);
 			} else if (eventSlave.dick > 0) {
 				r.push(`teasing ${his} girly little dick,`);
-			} else if (eventSlave.clit > 0) {
+			} else if (eventSlave.clit > 2) {
 				r.push(`jerking off ${his} ridiculous clit,`);
 			} else if (eventSlave.labia > 0) {
 				r.push(`spreading and teasing ${his} petals,`);
diff --git a/src/events/RETS/reAnalCowgirl.js b/src/events/RETS/reAnalCowgirl.js
index cfaa9607acff50a80bda76abdbdf6c79fabfd0ac..f875de397c492f4496a58365f5f3cf9a21bd3468 100644
--- a/src/events/RETS/reAnalCowgirl.js
+++ b/src/events/RETS/reAnalCowgirl.js
@@ -250,7 +250,7 @@ App.Events.RETSAnalCowgirl = class RETSAnalCowgirl extends App.Events.BaseEvent
 				t.push(`jacking ${him2} off.`);
 			} else if (subSlave.dick > 0) {
 				t.push(`playing with ${his2} soft cock.`);
-			} else if (subSlave.clit > 1) {
+			} else if (subSlave.clit > 2) {
 				t.push(`rubbing ${his2} ridiculous clit.`);
 			} else if (subSlave.labia > 0) {
 				t.push(`fingering ${his2} glorious labia.`);
diff --git a/src/events/RETS/reCockmilkInterception.js b/src/events/RETS/reCockmilkInterception.js
index 1c4cd0f11b560fe0a723c1a7e016c87a9ca47545..5d41a4a8513f1ecc075d7eb208d3c13bb7a64647 100644
--- a/src/events/RETS/reCockmilkInterception.js
+++ b/src/events/RETS/reCockmilkInterception.js
@@ -47,11 +47,11 @@ App.Events.RETSCockmilkInterception = class RETSCockmilkInterception extends App
 			t.push(`${he2}'s not lactating, but ${he2}'s a good semen producer and when ${he2} wakes up, ${he2}'s usually very ready to have one of the machines drain ${his2} balls for ${him2}.`);
 		} else {
 			if (subSlave.preg > subSlave.pregData.normalBirth / 1.33) {
-				t.push(`it's late in ${his2} pregnancy and ${he2} wakes up every day with ${his2} ${subSlave.boobShape} breasts sore, painfully swollen with rich, nutritious ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk.`);
+				t.push(`it's late in ${his2} pregnancy and ${he2} wakes up every day with ${his2} ${subSlave.boobShape} breasts sore, painfully swollen with rich, nutritious ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk.`);
 			} else if (subSlave.preg > subSlave.pregData.normalBirth / 2) {
-				t.push(`${he2}'s pregnant and ${he2} wakes up every day with ${his2} ${subSlave.boobShape} breasts sore and swollen with rich, nutritious ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk.`);
+				t.push(`${he2}'s pregnant and ${he2} wakes up every day with ${his2} ${subSlave.boobShape} breasts sore and swollen with rich, nutritious ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk.`);
 			} else if (subSlave.lactation > 1) {
-				t.push(`the tiny little slow-release implant in each of ${his2} breasts is merciless. It keeps ${his2} mammary glands in a permanent state of barely-safe hyperproduction, and ${he2} wakes up every day with ${his2} terribly sore breasts spontaneously dribbling ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk.`);
+				t.push(`the tiny little slow-release implant in each of ${his2} breasts is merciless. It keeps ${his2} mammary glands in a permanent state of barely-safe hyperproduction, and ${he2} wakes up every day with ${his2} terribly sore breasts spontaneously dribbling ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk.`);
 			} else {
 				t.push(`${his2} lactation is natural, but it's still enough that ${he2} wakes up most days with full, sore breasts.`);
 			}
@@ -478,7 +478,7 @@ App.Events.RETSCockmilkInterception = class RETSCockmilkInterception extends App
 			} else {
 				t.push(`${he}'s no oral master, but ${his} mouth is wet and hot, and ${subSlave.slaveName} clearly likes it more than machine's dick receptacle. ${He2}`);
 			}
-			t.push(`can feel that ${his2} breasts aren't nearly empty of ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk yet, and of course the milkers are tugging at ${his2} teats as industriously as ever, so ${he2} relaxes luxuriantly as ${slave.slaveName} starts to climb out from under ${him2}.`);
+			t.push(`can feel that ${his2} breasts aren't nearly empty of ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk yet, and of course the milkers are tugging at ${his2} teats as industriously as ever, so ${he2} relaxes luxuriantly as ${slave.slaveName} starts to climb out from under ${him2}.`);
 			App.Events.addParagraph(frag, t);
 			t = [];
 
@@ -521,7 +521,7 @@ App.Events.RETSCockmilkInterception = class RETSCockmilkInterception extends App
 			if (subSlave.lactation > 1) {
 				t.push(`lactation is unnaturally copious,`);
 			} else {
-				t.push(`${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk is really flowing now,`);
+				t.push(`${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk is really flowing now,`);
 			}
 			t.push(`and a thin stream of cream squirts out of ${him2}. It lands on ${slave.slaveName}'s face below, surprising ${him}. ${He} splutters comically, but obeys eagerly when you squeeze ${subSlave.slaveName}'s freed boob and order ${slave.slaveName} to start drinking. After all, you point out, a balanced diet is important. ${slave.slaveName} <span class="trust inc">giggles complaisantly</span> and reaches for the proffered tit. ${subSlave.slaveName} is still basking in the afterglow of ${his2} orgasm and shudders silently with overstimulation as ${he2} feels ${slave.slaveName}'s lips`);
 			if (subSlave.nipples !== "fuckable") {
diff --git a/src/events/RETS/reDatePlease.js b/src/events/RETS/reDatePlease.js
index 0643f28a7d972ed0ef016bb45b719da38b043857..3ca0965beb5c00fd6695b40d0672f9212ba94531 100644
--- a/src/events/RETS/reDatePlease.js
+++ b/src/events/RETS/reDatePlease.js
@@ -99,7 +99,7 @@ App.Events.RETSDatePlease = class RETSDatePlease extends App.Events.BaseEvent {
 			t = [];
 			t.push(`It costs you a small sum in upkeep and other trifles to cover an unexpected unavailability of both slaves, but they deserve it, and your Attendant does not disappoint. After the slaves have soaked in the main pool for a while, ${he3} gives them a series of mud packs, hot rock massages, and skin treatments, always setting them up right next to each other. They chat a bit at first, but soon relax into companionable silence, ${hasAnyArms(eventSlave) && hasAnyArms(subSlave) ? "holding hands and enjoying" : "side by side to enjoy"} the pampering.`);
 			if (S.Attendant.lactation > 0) {
-				t.push(`${S.Attendant.slaveName} has their evening meal sent down, and supplements it with ${S.Attendant.milkFlavor === "none" ? `` : `${S.Attendant.milkFlavor} flavored `}milk drunk fresh from ${his3} own nipples.`);
+				t.push(`${S.Attendant.slaveName} has their evening meal sent down, and supplements it with ${S.Attendant.milkFlavor === "none" ? `` : `${S.Attendant.milkFlavor}-flavored `}milk drunk fresh from ${his3} own nipples.`);
 			}
 			t.push(`This being your penthouse, ${his3} services become quite sexual later in the night, as the Attendant applies all ${his3} talents in choosing positions that emphasize ${eventSlave.slaveName} and ${subSlave.slaveName} being close to each other, a difficult task given`);
 			if (S.Attendant.bellyPreg >= 10000 && eventSlave.bellyPreg >= 10000 && subSlave.bellyPreg >= 10000) {
diff --git a/src/events/RETS/reTasteTest.js b/src/events/RETS/reTasteTest.js
index ae950cabe61e9f961331a095b401bcb562d1e750..5703f1fafa366da527783900a4152afade3edf00 100644
--- a/src/events/RETS/reTasteTest.js
+++ b/src/events/RETS/reTasteTest.js
@@ -149,7 +149,7 @@ App.Events.RETSTasteTest = class RETSTasteTest extends App.Events.BaseEvent {
 					t.push(`of ${his2} ${subSlave.inflationType}-filled belly gurgling`);
 				}
 			} else if (subSlave.lactation > 1) {
-				t.push(`of the ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor} flavored `}milk dripping from ${his2} nipples`);
+				t.push(`of the ${subSlave.milkFlavor === "none" ? `` : `${subSlave.milkFlavor}-flavored `}milk dripping from ${his2} nipples`);
 			} else {
 				t.push(`of ${his2} bare skin against the cool air`);
 			}
diff --git a/src/events/RETS/reTopExhaustion.js b/src/events/RETS/reTopExhaustion.js
index 80da0807c36a2ffb80ae93235e82215a4d72188d..3f82d65a55ec1e3d5e48b042b79ed194b76dfc16 100644
--- a/src/events/RETS/reTopExhaustion.js
+++ b/src/events/RETS/reTopExhaustion.js
@@ -301,7 +301,7 @@ App.Events.RETSTopExhaustion = class RETSTopExhaustion extends App.Events.BaseEv
 			} else {
 				t.push(`Nevertheless, ${he2} clumsily wiggles ${his2} hips for you. As you begin to grind against ${him2},`);
 				if (canPenetrate(domSlave)) {
-					t.push(`the lewdity of the act manages to get ${his2} member hard again.`);
+					t.push(`the lewdness of the act manages to get ${his2} member hard again.`);
 				} else {
 					t.push(`${he2} starts to move along with you.`);
 				}
diff --git a/src/events/assistant/assistantSP.js b/src/events/assistant/assistantSP.js
index 5c5810746f9bc073220f8ed56727c4757e18f9fa..ba0e8facb0856929cc384930d109b87971c2a45a 100644
--- a/src/events/assistant/assistantSP.js
+++ b/src/events/assistant/assistantSP.js
@@ -37,7 +37,7 @@ App.Events.assistantSP = class assistantSP extends App.Events.BaseEvent {
 		r = [];
 		r.push(`"One more thing, ${properTitle()}!" ${HisA} symbol flashes brightly. "I could stay like I am now, a hot voice with this symbol representing me when I need to show up on screens. Or, I could slip into something a little sexier. How about this?" The symbol vanishes, and is replaced by a cute little school${girlA} character. ${HeA} bounces up and down experimentally. "This appearance would work best with an excited voice," ${heA} exclaims. ${HeA} blows you a kiss. The school${girlA}'s body shrinks down and all ${hisA} clothing falls off. A small pair of wings pops out from the pile of clothes and a fairy stands up. "Or I could be your tiny and adorable fairy companion!" ${HeA} shouts excitedly while waving ${hisA} arms.`);
 		if (V.seePreg !== 0) {
-			r.push(`The fairy's belly begins to swell out, ${hisA} breasts getting puffier and leaking a drop of milk. "Or maybe you want your little buddy to be filled with adorable little babies, you little minx" ${heA} playfully teases.`);
+			r.push(`The fairy's belly begins to swell out, ${hisA} breasts getting puffier and leaking a drop of milk. "Or maybe you want your little buddy to be filled with adorable little babies, you little minx," ${heA} playfully teases.`);
 		}
 		r.push(`The fairy rapidly grows to adult size, becomes curvier and more mature, ${hisA} hair pulls itself back into a bun, and ${hisA} clothes change into a business suit. A pair of glasses appears on ${hisA} nose, and ${heA} looks at you over their tops. "Or I could be businesslike. And mature." ${HeA} snaps ${hisA} fingers, and ${hisA} bun falls away into long flowing locks.`);
 		if (V.seePreg !== 0) {
diff --git a/src/events/eventUtils.js b/src/events/eventUtils.js
index 37f975a09b1c4df7560ca9430a4f0fe108215f4a..24ec34502205a3b20984e54410a8bba5fdee86f2 100644
--- a/src/events/eventUtils.js
+++ b/src/events/eventUtils.js
@@ -256,7 +256,7 @@ App.Events.Result = class {
 			node.append(" ");
 		}
 		if (this.note) {
-			node.appendChild(App.UI.DOM.makeElement("span", this.note, "detail"));
+			node.appendChild(App.UI.DOM.makeElement("span", this.note, ["detail"]));
 			wrote = true;
 		}
 		return wrote;
diff --git a/src/events/intro/acquisition.js b/src/events/intro/acquisition.js
index 663136ce1e188aa902a3c73799d283b83b4fbdaa..dcc4120c8e31f41109441e2bbd35fcd979a2bd4c 100644
--- a/src/events/intro/acquisition.js
+++ b/src/events/intro/acquisition.js
@@ -352,7 +352,6 @@ App.Intro.acquisition = function() {
 				}
 			}
 			if (V.PC.preg > 0) {
-				V.PC.pregWeek = V.PC.preg;
 				if (V.PC.pregType !== 8) {
 					V.PC.pregType = 1;
 				} else {
@@ -367,8 +366,8 @@ App.Intro.acquisition = function() {
 					V.PC.pregSource = -5;
 				}
 				V.PC.pregKnown = 1;
-				V.PC.belly = getPregBellySize(V.PC);
-				WombImpregnate(V.PC, V.PC.pregType, V.PC.pregSource, V.PC.preg);
+				WombForceFatherID(V.PC, V.PC.pregSource);
+				WombUpdatePregVars(V.PC);
 			}
 		} else {
 			V.PC.trueVirgin = 1;
diff --git a/src/events/intro/arcologySelection.js b/src/events/intro/arcologySelection.js
index 83dc574fb13e997d97d231d9f779755aa3dd9f43..245e3d1493019e5f63b5098ed962710b0e72b8e7 100644
--- a/src/events/intro/arcologySelection.js
+++ b/src/events/intro/arcologySelection.js
@@ -1,5 +1,5 @@
-/** @param {number} [price] */
-App.Intro.generateEstablishedArcologies = function(price) {
+/** @param {boolean} inIntro */
+App.Intro.generateEstablishedArcologies = function(inIntro = false) {
 	/* setup */
 	const fsAllowed = {
 		FSGenderRadicalist: () => V.seeDicks !== 0,
@@ -23,21 +23,10 @@ App.Intro.generateEstablishedArcologies = function(price) {
 	function arcologyCard() {
 		const div = document.createElement("div");
 		const arcology = generateArcology();
-		const sectionPrice = {
-			"penthouse": 10_000_000,
-			"shops": 1_000_000,
-			"apartments": 500_000,
-			"markets": 250_000,
-			"manufacturing": 100_000,
-		};
-		const rows = (/** @type {App.Arcology.Section} */ section) => section.rows
-			.reduce((acc, cur) => acc + cur.length * sectionPrice[section.id], 0);
-		const _price = price ?? arcology.building.sections
-			.reduce((acc, cur) => acc + rows(cur), 10_000_000); // base price of ¤10,000,000
 
 		div.classList.add("card");
 		div.append(
-			App.UI.DOM.makeElement("span", arcology.name, ['bold']),
+			App.UI.DOM.makeElement("span", inIntro ? App.UI.DOM.passageLink(arcology.name, "Intro Summary", () => acceptArcology()) : arcology.name, ['bold']),
 			` is an established arcology located in a Free City `,
 		);
 		if (arcology.terrain === "urban") {
@@ -185,48 +174,65 @@ App.Intro.generateEstablishedArcologies = function(price) {
 		div.append(
 			innerDiv,
 			App.UI.DOM.makeElement("div", arcology.building.render(), ["intro"]),
-			App.UI.DOM.makeElement("div", makePurchase(`Purchase ${arcology.name}`, _price, "capEx", {
-				handler: () => {
-					V.targetArcology = arcology;
-					V.terrain = arcology.terrain;
-					V.continent = arcology.continent;
-					V.language = arcology.language;
-					V.building = arcology.building;
-					V.weatherCladding = 0;
-					V.rep = 0;
-
-					if (V.secExpEnabled && V.SecExp.core) {
-						V.SecExp.core.authority = 0;
-					}
+		);
 
-					arcology.apply();
+		if (!inIntro) {
+			// for some reason we put the acquisition link at the bottom instead of the top when moving arcologies
+			const sectionPrice = {
+				"spire": 2_500_000,
+				"penthouse": 10_000_000,
+				"shops": 1_000_000,
+				"fountain": 5_000_000,
+				"apartments": 500_000,
+				"markets": 250_000,
+				"ravine-markets": 250_000,
+				"manufacturing": 100_000,
+			};
+			const rows = (/** @type {App.Arcology.Section} */ section) => section.rows
+				.reduce((acc, cur) => acc + cur.length * sectionPrice[section.id], 0);
+			const price = arcology.building.sections.reduce((acc, cur) => acc + rows(cur), 10_000_000) || 25_000_000; // base price of ¤10,000,000
 
-					if (passage() === "Takeover Target") {
-						Engine.play("Intro Summary");
-					} else {
-						updatePlayerArcology();
-						Engine.play("Main");
-					}
+			div.append(App.UI.DOM.makeElement("div", makePurchase(`Purchase ${arcology.name}`, price, "capEx", {
+				handler: () => {
+					acceptArcology();
+					updatePlayerArcology();
+					Engine.play("Main");
 				},
 				prereqs: [
 					[
 						V.rival.state === 0 || V.rival.state > 2,
-						`Your inter-arcology war is preventing you from leaving ${arcology.name}.`
+						`Your inter-arcology war is preventing you from leaving ${V.arcologies[0].name}.`
 					],
 					[
 						V.daughtersVictory !== 1,
-						`You cannot leave ${arcology.name} behind while the Daughters of Liberty are still a threat.`
+						`You cannot leave ${V.arcologies[0].name} behind while the Daughters of Liberty are still a threat.`
 					],
 				],
-			}), ['center']),
-		);
+			}), ['center']));
+		}
 
 		return div;
 
+		function acceptArcology() {
+			V.targetArcology = arcology;
+			V.terrain = arcology.terrain;
+			V.continent = arcology.continent;
+			V.language = arcology.language;
+			V.building = arcology.building;
+
+			arcology.apply();
+		}
+
 		function updatePlayerArcology() {
 			V.arcologies[0].name = arcology.name;
 			V.arcologies[0].weeks = 1;
 
+			V.weatherCladding = 0;
+			V.rep = 0;
+			if (V.secExpEnabled && V.SecExp.core) {
+				V.SecExp.core.authority = 0;
+			}
+
 			updateFS();
 		}
 
diff --git a/src/events/intro/initNationalities.js b/src/events/intro/initNationalities.js
index 213a1bdf0c6fa63dd90ca00c50b2ceb5a4b8c7ac..7aaeeec2563ad769bc131d65baa262d02b186e0c 100644
--- a/src/events/intro/initNationalities.js
+++ b/src/events/intro/initNationalities.js
@@ -334,6 +334,7 @@ App.Intro.initNationalities = function() {
 		V.arcologies[0].FSMaturityPreferentialistSMR = 0;
 		V.arcologies[0].FSSlimnessEnthusiastSMR = 0;
 		V.arcologies[0].FSSlimnessEnthusiastLaw = 0;
+		V.arcologies[0].FSSlimnessEnthusiastFoodLaw = 0;
 		V.arcologies[0].FSAssetExpansionistSMR = 0;
 		V.arcologies[0].FSPastoralistLaw = 0;
 		V.arcologies[0].FSPastoralistSMR = 0;
diff --git a/src/events/intro/introSummary.js b/src/events/intro/introSummary.js
index 34ec2533a090911e482d962760983fff3928151f..9528b40b147f3120d8c83f09b144721740a54090 100644
--- a/src/events/intro/introSummary.js
+++ b/src/events/intro/introSummary.js
@@ -17,11 +17,10 @@ App.Intro.summary = function() {
 	let minAge = V.minimumSlaveAge;
 	let maxAge = V.retirementAge - 1 > 60 ? 60 : V.retirementAge - 1;
 	let defaultAge = 18;
-	if(V.targetArcology.fs === "FSMaturityPreferentialist") {
+	if (V.targetArcology.fs === "FSMaturityPreferentialist") {
 		minAge = 30;
 		defaultAge = 30;
-	}
-	else if(V.targetArcology.fs === "FSYouthPreferentialist") {
+	} else if (V.targetArcology.fs === "FSYouthPreferentialist") {
 		maxAge = 29;
 	}
 	V.idealAge = variableAsNumber(V.idealAge, minAge, maxAge, defaultAge);
@@ -35,6 +34,7 @@ App.Intro.summary = function() {
 		V.PC.origRace = V.PC.race;
 		V.PC.origSkin = V.PC.skin;
 		V.PC.origHColor = V.PC.hColor;
+		V.PC.eyebrowHColor = V.PC.hColor;
 	}
 
 	const tabBar = new App.UI.Tabs.TabBar("IntroSummary");
@@ -306,6 +306,8 @@ App.Intro.summary = function() {
 								}
 								if (V.PC.vagina >= 0) {
 									V.PC.geneticQuirks.fertility = 2;
+								} else {
+									V.PC.geneticQuirks.fertility = 1;
 								}
 								V.PC.skill.trading = -100;
 								V.PC.skill.warfare = -100;
@@ -314,7 +316,6 @@ App.Intro.summary = function() {
 								V.PC.skill.medicine = -100;
 								V.PC.skill.hacking = -100;
 								V.PC.muscles = 0;
-								V.PC.geneticQuirks.fertility = 1;
 								V.PC.digestiveSystem = "atrophied";
 								break;
 							case "handmaiden":
@@ -325,6 +326,8 @@ App.Intro.summary = function() {
 								}
 								if (V.PC.vagina >= 0) {
 									V.PC.geneticQuirks.fertility = 2;
+								} else {
+									V.PC.geneticQuirks.fertility = 1;
 								}
 								V.PC.skill.trading = -100;
 								V.PC.skill.warfare = -100;
@@ -344,6 +347,8 @@ App.Intro.summary = function() {
 								}
 								if (V.PC.vagina >= 0) {
 									V.PC.geneticQuirks.fertility = 2;
+								} else {
+									V.PC.geneticQuirks.fertility = 1;
 								}
 								V.PC.skill.trading = -100;
 								V.PC.skill.warfare = -100;
@@ -384,6 +389,32 @@ App.Intro.summary = function() {
 								V.PC.skill.medicine = -100;
 								V.PC.skill.hacking = -100;
 								break;
+							case "test subject":
+								V.PC.intelligenceImplant = 0;
+								V.PC.skill.trading = -100;
+								V.PC.skill.warfare = -100;
+								V.PC.skill.slaving = -100;
+								V.PC.skill.engineering = -100;
+								V.PC.skill.medicine = -100;
+								V.PC.skill.hacking = -100;
+								V.PC.muscles = -100;
+								V.PC.boobs = 50000;
+								V.PC.lactation = 1;
+								V.PC.lactationAdaptation = 100;
+								if (V.PC.pubertyXX === 1) {
+									V.PC.pregType = 100;
+									V.PC.preg = 27;
+								} else {
+									V.PC.bellyImplant = 800000;
+								}
+								V.PC.pregAdaptation = 200;
+								V.PC.hips = 3;
+								V.PC.butt = 20;
+								V.PC.dick = 50;
+								V.PC.balls = 100;
+								V.PC.weight = 200;
+								V.PC.digestiveSystem = "atrophied";
+								break;
 						}
 						if (V.PC.rumor === "diligence") {
 							V.PC.weight = 0;
@@ -780,7 +811,7 @@ App.Intro.economy = function(isIntro) {
 		.addValue("Vanilla", 0, () => V.difficultySwitch = 0)
 		.addValue("Easy", 1, () => V.difficultySwitch = 1)
 		.addValue("Default", 2, () => V.difficultySwitch = 1)
-		.addValue("Hard", 3, () => V.difficultySwitch = 1);
+		.addValue("Hard", 4, () => V.difficultySwitch = 1);
 
 	/* Not functional yet
 	All the things you need to run your arcology are getting more expensive
diff --git a/src/events/intro/pcAppearance.js b/src/events/intro/pcAppearance.js
index a318ba069f96e9b46d8c13eb92699f8c6d021864..406545b0ee52099bdcb7f60f293ed94ca932e42c 100644
--- a/src/events/intro/pcAppearance.js
+++ b/src/events/intro/pcAppearance.js
@@ -101,6 +101,9 @@ App.UI.Player.appearance = function(options, summary = false) {
 		option.addValue("Very broad", 2);
 	}
 
+	options.addOption(`Your armpits`, "underArmHStyle", V.PC)
+		.addValueList([["Are naturally hairless", "hairless"], ["Can grow hair", "neat"]]);
+
 	if (V.PC.boobs >= 200 || summary) {
 		if (V.PC.title === 1 && V.PC.boobs <= 200) {
 			option = options.addOption("Your chest is", "boobs", V.PC).addValue("Manly", 200, () => { V.PC.boobsImplant = 0; V.PC.boobsImplantType = "none"; });
@@ -246,7 +249,7 @@ App.UI.Player.appearance = function(options, summary = false) {
 		if (V.PC.physicalAge < 14) {
 			options.addOption("You are", "pubertyXY", V.PC)
 				.addValueList([["Not producing potent sperm yet", 0], ["Producing potent sperm", 1]]);
-		} 
+		}
 		if (V.PC.pubertyXY === 1) {
 			options.addOption("You went through puberty when you were", "pubertyAgeXY", V.PC).showTextBox({unit: "years old."});
 		}
@@ -270,6 +273,9 @@ App.UI.Player.appearance = function(options, summary = false) {
 		}
 	}
 
+	options.addOption(`You`, "pubicHStyle", V.PC)
+		.addValueList([["Are naturally hairless", "hairless"], ["Can grow pubic hair", "neat"]]);
+
 	options.addOption("You are", "anus", V.PC)
 		.addValueList([["An anal virgin", 0], ["Not an anal virgin", 1]]);
 
@@ -417,7 +423,7 @@ App.UI.Player.assignCareerByAge = function(selection) {
 		career = selection;
 	} else {
 		for (const data of App.Data.player.career.values()) {
-			if (Object.values(data).includes(V.PC.career)) {
+			if (Object.values(data).includes(selection)) {
 				if (V.PC.actualAge <= 13) {
 					career = data.child;
 				} else if (V.PC.actualAge <= 21) {
@@ -638,6 +644,7 @@ App.UI.Player.design = function() {
 	// History
 	if (allowEdits) {
 		option = options.addOption("Before you came to the Free Cities, you were a", "career", V.PC);
+		// option.addValue("Test subject", "test subject");
 		if (V.PC.career === "arcology owner") {
 			option.addValue("Arcology owner", "arcology owner");
 		} else {
diff --git a/src/events/intro/takeoverTarget.js b/src/events/intro/takeoverTarget.js
index 7923d6a0fc0a2b6f9769a3920682115f6bfa313f..de0256579fc7da1cdbe0daa7aec6b7356b9a1a9d 100644
--- a/src/events/intro/takeoverTarget.js
+++ b/src/events/intro/takeoverTarget.js
@@ -50,6 +50,6 @@ App.Intro.takeoverTarget = function() {
 	App.UI.DOM.appendNewElement("div", card, `With many new arcologies being constructed, you will be able to select which area of the world and type of Free City you'd like your target arcology to be located in.`, ["indent", "note"]);
 	App.UI.DOM.appendNewElement("div", card, `Recommended for new players.`, ["indent", "note"]);
 
-	node.append(App.Intro.generateEstablishedArcologies(0));
+	node.append(App.Intro.generateEstablishedArcologies(true));
 	return node;
 };
diff --git a/src/events/nonRandom/daughters/pHackerSupport.js b/src/events/nonRandom/daughters/pHackerSupport.js
index 369e49e690b7135f9c704c647a0b7e77a0b78dcf..d4cbb25ca7ca48f5470ae6212cba05814e065e95 100644
--- a/src/events/nonRandom/daughters/pHackerSupport.js
+++ b/src/events/nonRandom/daughters/pHackerSupport.js
@@ -172,7 +172,7 @@ App.Events.PHackerSupport = class PHackerSupport extends App.Events.BaseEvent {
 					case "angel":
 						r.push(`She seems to have left a present for your poor personal assistant; ${hisA} little angel avatar is visible in the bottom corner of a screen on the wall opposite you. ${HisA} virginity is being forcibly taken by a representation of the hacker in the same style. ${HeA} pleads for them to stop before ${heA} falls, but it goes unheeded. ${HeA} cries out in orgasm as the hacker unloads their corrupting jism deep into ${hisA} womb before pulling out and letting ${himA} drop to the ground. ${HeA} rolls from side to side in anguish,`);
 						if (V.seePreg !== 0) {
-							r.push(`gripping ${hisA} cum filled belly as it rounds more and more, before settling on ${hisA} back and cradling ${hisA} now full-term pregnancy. As it continues to grow, ${hisA} body becomes increasingly withered, until ${heA} appears to be pregnant with a fully grown person.`);
+							r.push(`gripping ${hisA} cum-filled belly as it rounds more and more, before settling on ${hisA} back and cradling ${hisA} now full-term pregnancy. As it continues to grow, ${hisA} body becomes increasingly withered, until ${heA} appears to be pregnant with a fully grown person.`);
 							if (V.seeExtreme === 1) {
 								r.push(`As the light fades from ${himA}, ${hisA} gravid belly begins to shudder violently, its occupant trying to tear its way free. Before long, it splits open, revealing a gorgeous ${womanA} with all the features of the fallen angel. ${V.assistant.name} spreads ${hisA} bat-like wings as ${heA} rises from the disintegrating remains of ${hisA} once holy body, turns to you, and sensually traces ${hisA} new curves seductively.`);
 							} else {
diff --git a/src/events/nonRandom/mercs/pMercsHelpCorp.js b/src/events/nonRandom/mercs/pMercsHelpCorp.js
index f4fe0b6264e5312303f2f7d0f65b1426c09d02b9..26d8b1a88b07e5b62dd3a4a2a92745433e149e76 100644
--- a/src/events/nonRandom/mercs/pMercsHelpCorp.js
+++ b/src/events/nonRandom/mercs/pMercsHelpCorp.js
@@ -2,7 +2,7 @@ App.Events.PMercsHelpCorp = class PMercsHelpCorp extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
 			() => V.corp.Incorporated > 0,
-			() => V.rival.state === 5,
+			() => V.rival.state > 2,
 			() => V.mercenaries >= 3,
 			() => V.mercenariesHelpCorp === 0,
 			() => V.corp.DivExtra > 0,
diff --git a/src/events/nonRandom/pRaped.js b/src/events/nonRandom/pRaped.js
index 15306612139c985beeeb398ad69437f08f0e225c..4b9d7ff2f27ed779e75acd5082822968456e5fb5 100644
--- a/src/events/nonRandom/pRaped.js
+++ b/src/events/nonRandom/pRaped.js
@@ -523,7 +523,7 @@ App.Events.pRaped = class pRaped extends App.Events.BaseEvent {
 				r.push(`${He} teases as ${he} pushes you to the ground and climbs on top of you.`);
 				App.Events.addParagraph(node, r);
 				r = [];
-				r.push(`${He} lines ${himself} up with the tip of your dick before taking its entire length into ${himself}. ${He} lets out a lust filled moan as ${he} begins to bounce on your traitorous member. You can do nothing to stop ${him} from riding you to climax, so you just enjoy the sight of ${his} breasts bouncing to ${his} pace. As you feel your orgasm approaching, you try to time it so you can slip out of ${him} just before you blow your load, but you have no such luck.`);
+				r.push(`${He} lines ${himself} up with the tip of your dick before taking its entire length into ${himself}. ${He} lets out a lust-filled moan as ${he} begins to bounce on your traitorous member. You can do nothing to stop ${him} from riding you to climax, so you just enjoy the sight of ${his} breasts bouncing to ${his} pace. As you feel your orgasm approaching, you try to time it so you can slip out of ${him} just before you blow your load, but you have no such luck.`);
 				r.push(Spoken(rapist, `"You really think I'd let you spoil my plans?"`));
 				r.push(`${he} asks as ${he} grinds against you, making sure you cum deep in ${his} pussy. ${He} leans back and massages ${his}`);
 				if (V.PC.balls >= 20) {
diff --git a/src/events/nonRandom/rival/pRivalryActions.js b/src/events/nonRandom/rival/pRivalryActions.js
index 1b7df31f25e646552c50e116687a73a8da8f085e..dbf946aca091c675b4ac302cbf4f01f6e05e3b32 100644
--- a/src/events/nonRandom/rival/pRivalryActions.js
+++ b/src/events/nonRandom/rival/pRivalryActions.js
@@ -2162,7 +2162,7 @@ App.Events.pRivalryActions = function() {
 							V.hostage.counter.anal += 100;
 							V.hostage.counter.mammary += 100;
 							if (V.seeHyperPreg !== 1) {
-								hostageAction.push(`happily rubbing ${his} cum filled belly, eager for ${his} next pregnancy to take.`);
+								hostageAction.push(`happily rubbing ${his} cum-filled belly, eager for ${his} next pregnancy to take.`);
 								hostageAction.push(`eagerly checking a pregnancy test before dropping it sadly.`);
 								hostageAction.push(`injecting cum into ${his} vagina, hoping to get pregnant again sooner.`);
 							} else {
@@ -2678,7 +2678,7 @@ App.Events.pRivalryActions = function() {
 							V.hostage.counter.vaginal += 1;
 							hostageAction.push(`lifting weights, ${his} soft body barely hiding ${his} bulging muscles.`);
 							hostageAction.push(`pinching ${his} remaining flab and making a disgusted face.`);
-							hostageAction.push(`running laps around the track to burn off ${his} excess bodyfat.`);
+							hostageAction.push(`running laps around the track to burn off ${his} excess body fat.`);
 						} else if (V.rival.duration <= 20) {
 							V.hostage.trust -= 5;
 							V.hostage.devotion -= 5;
@@ -2785,7 +2785,7 @@ App.Events.pRivalryActions = function() {
 									SetBellySize(V.hostage);
 									break;
 							}
-							hostageAction.push(`relaxing in ${his} comfy bed carefully exploring ${his} food stuffed belly and its unique curvature. ${He}'s certainly getting soft.`);
+							hostageAction.push(`relaxing in ${his} comfy bed carefully exploring ${his} food-stuffed belly and its unique curvature. ${He}'s certainly getting soft.`);
 							hostageAction.push(`crying as ${he} rubs the uncomfortable bulge of ${his} overfilled stomach and soft belly as yet another guy fucks ${his} loosening cunt.`);
 							switch (V.hostage.fetish) {
 								case "submissive":
@@ -3029,7 +3029,7 @@ App.Events.pRivalryActions = function() {
 							V.hostage.counter.vaginal += 1;
 							hostageAction.push(`lifting weights, ${his} soft body barely hiding ${his} bulging muscles.`);
 							hostageAction.push(`pinching ${his} remaining flab and making a disgusted face.`);
-							hostageAction.push(`running laps around the track to burn off ${his} excess bodyfat.`);
+							hostageAction.push(`running laps around the track to burn off ${his} excess body fat.`);
 						} else if (V.rival.duration <= 20) {
 							V.hostage.trust -= 5;
 							V.hostage.devotion -= 5;
diff --git a/src/events/nonRandom/rival/pRivalryCapture.js b/src/events/nonRandom/rival/pRivalryCapture.js
index 1dff371f2e31c1e56d46dbaea715b89293d96b23..2b631f494a2376ec9376642ce23276df3e0ec4e2 100644
--- a/src/events/nonRandom/rival/pRivalryCapture.js
+++ b/src/events/nonRandom/rival/pRivalryCapture.js
@@ -400,7 +400,7 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.behavioralQuirk = "insecure";
 				slave.sexualFlaw = "shamefast";
 				slave.sexualQuirk = "tease";
-				slave.hStyle = "twin tails";
+				slave.hStyle = "tails";
 				slave.hLength = 40;
 				break;
 			case "cow":
diff --git a/src/events/nonRandom/rival/pRivalryVictory.js b/src/events/nonRandom/rival/pRivalryVictory.js
index e61627a5369772d28c0a572045747e0dc19df3fc..9c7db22975e2c69db3ac114f26fe865e9392e024 100644
--- a/src/events/nonRandom/rival/pRivalryVictory.js
+++ b/src/events/nonRandom/rival/pRivalryVictory.js
@@ -35,6 +35,7 @@ App.Events.pRivalryVictory = function() {
 					if (V.rival.hostageState === 1) {
 						V.rival.hostageState = 2;
 					}
+					V.rival.state = 4;
 				} else {
 					r.push(`${HisR} arcology will go to satisfy ${hisR} great debts, but you will still profit <span class="yellowgreen">immensely</span> from your victory${(V.rival.hostageState > 0 && V.hostage) ? `, and acquire ${V.hostage.slaveName} as a slave` : ``}.`);
 					cashX(random(100000, 250000), "war");
diff --git a/src/events/nonRandom/slaveFood.js b/src/events/nonRandom/slaveFood.js
index 6f4296860d349c1b157c99e5982f79ae80755fd4..08480c1ab33f047118de50337367f25b936b10c4 100644
--- a/src/events/nonRandom/slaveFood.js
+++ b/src/events/nonRandom/slaveFood.js
@@ -51,7 +51,7 @@ App.Events.PSlaveFood = class PSlaveFood extends App.Events.BaseEvent {
 					r.push(`The goddess beams. "It's wonderful," ${heA} says radiantly. "Their place is here, with us." ${HeA} pauses.`);
 					break;
 				case "hypergoddess":
-					r.push(`The child filled goddess beams. "It's wonderful," ${heA} says radiantly. "They are like our children, and this arcology our womb; even after they are born they are forever bound to us." ${HeA} pauses.`);
+					r.push(`The child-filled goddess beams. "It's wonderful," ${heA} says radiantly. "They are like our children, and this arcology our womb; even after they are born they are forever bound to us." ${HeA} pauses.`);
 					break;
 				case "loli":
 					r.push(`The little ${girlA} smiles happily while jumping up and down. "So we can be friends forever? That's great!" ${HeA} pauses.`);
diff --git a/src/events/reRecruit/handsomePC.js b/src/events/reRecruit/handsomePC.js
index 70ddc462cab1277f6b1ef7ed34716b1c31dc92cd..9992a6c8631a0b83ae2581a66cf76d02072d9f5c 100644
--- a/src/events/reRecruit/handsomePC.js
+++ b/src/events/reRecruit/handsomePC.js
@@ -87,6 +87,10 @@ App.Events.recHandsomePC = class recHandsomePC extends App.Events.BaseEvent {
 			slave.trust = random(-15, -10);
 			setHealth(slave, jsRandom(0, 20), undefined, undefined, 0, 0);
 			slave.anus = 1;
+			slave.attrXY = random(70, 100);
+			if (slave.behavioralFlaw === "hates men") {
+				slave.behavioralFlaw = "none";
+			}
 			slave.skill.anal = 15;
 			slave.skill.oral = 15;
 			if (slave.vagina > 0) {
diff --git a/src/events/reRecruit/maleRecruit.js b/src/events/reRecruit/maleRecruit.js
index 2a4691e207aba175c6c2db569436875da57640b4..f4763a57f047c042a07b0ff1ecc09eeb8ddc20c5 100644
--- a/src/events/reRecruit/maleRecruit.js
+++ b/src/events/reRecruit/maleRecruit.js
@@ -28,6 +28,7 @@ App.Events.recMaleRecruit = class recMaleRecruit extends App.Events.BaseEvent {
 		App.Events.addParagraph(node, r);
 		r = [];
 		r.push(Spoken(slave, `"${title}, my name is ${slave.slaveName}. I'm, um, bored, I guess. I go to clubs and get drunk and fuck guys and it's just kinda boring. I thought it would be different when I turned ${num(slave.actualAge)}, but that was a couple months ago and, well, nothing's different. I saw ${S.HeadGirl.slaveName} and ${he2} was just so beautiful and has a dick like me and ${he2} seemed so confident in what ${he2} was doing and who he was and I talked to ${him2} and ${he} said ${he2} was your Head Girl and... I want to be like ${him2}. Can I be your slave? I'd be good, I'm good at sucking dicks and stuff."`));
+		App.Events.addParagraph(node, r);
 
 		const contractCost = 1000;
 		const cost = slaveCost(slave) - contractCost;
diff --git a/src/events/reRecruit/shemalePC.js b/src/events/reRecruit/shemalePC.js
index 11142b4a1fad0047bcf38933e639e97c6cc0363a..fb196567cfe5c56d10c8126b136273e955a5abed 100644
--- a/src/events/reRecruit/shemalePC.js
+++ b/src/events/reRecruit/shemalePC.js
@@ -19,7 +19,7 @@ App.Events.recShemalePC = class recShemalePC extends App.Events.BaseEvent {
 
 	execute(node) {
 		const slave = makeSlave();
-		const {He, he, his, him, girl} = getPronouns(slave);
+		const {He, he, his, him, himself, girl} = getPronouns(slave);
 		const {himselfA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 		let r = [];
 		r.push(`${capFirstChar(V.assistant.name)} alerts you that a supplicant has arrived at the door to the penthouse. A constant stream of hopefuls appear at your door, and ${V.assistant.name} makes ${himselfA} invaluable by filtering them. One of the few categories of applicant that is always admitted is people willing to be enslaved for some reason; this is just such a ${girl}.`);
@@ -53,7 +53,7 @@ App.Events.recShemalePC = class recShemalePC extends App.Events.BaseEvent {
 			const el = new DocumentFragment();
 			let r = [];
 			cashX(forceNeg(contractCost), "slaveTransfer", slave);
-			r.push(`You put ${him} through the enslavement procedures. ${He} looks relieved, as though ${he} thinks ${he} no longer has anything to worry about. ${He}'s certainly more complacent than the average inductee.`);
+			r.push(`You put ${him} through the enslavement procedures. ${He}'s almost excited. Though ${he} knows ${he}'s signed ${himself} over to a life of sexual slavery, the anticipation of becoming more feminine is clearly more important to ${him} than any kind of fear.`);
 			r.push(App.UI.newSlaveIntro(slave));
 			App.Events.addNode(el, r);
 			return el;
@@ -84,6 +84,8 @@ App.Events.recShemalePC = class recShemalePC extends App.Events.BaseEvent {
 			slave.balls = random(1, 2);
 			slave.scrotum = slave.balls;
 			slave.anus = 1;
+			slave.attrXX = Math.max(slave.attrXX, 70);
+			slave.attrXY = Math.max(slave.attrXY, 70);
 			slave.skill.anal = 15;
 			slave.skill.oral = 15;
 			slave.boobs += 400;
diff --git a/src/events/reRecruit/whoreRecruit.js b/src/events/reRecruit/whoreRecruit.js
index 80f3d8f95de066c63c46d07e8fd9765c5c2a41ba..9f57776c34b0fb31b13bb4cb59e41298520f8868 100644
--- a/src/events/reRecruit/whoreRecruit.js
+++ b/src/events/reRecruit/whoreRecruit.js
@@ -30,6 +30,7 @@ App.Events.recWhoreRecruit = class recWhoreRecruit extends App.Events.BaseEvent
 		r = [];
 
 		r.push(Spoken(slave, `"${title}, my name is ${slave.slaveName}. I'm a street whore. Working ${girl}s get to know each other, so I know ${S.HeadGirl.slaveName} pretty well. I've been having a bad time on the streets, and last night a john beat on me pretty good. I'm broke and I'm sick of this. Being free isn't worth shit. ${S.HeadGirl.slaveName} likes you and ${he2} seems to do OK. So, can I be your slave? I'm a good bet, ${title.toLowerCase()}. I'd be happy enough working for you as a slave whore if you keep me healthy and safe, and I'm a good fuck."`));
+		App.Events.addParagraph(node, r);
 
 		const contractCost = 1000;
 		const cost = slaveCost(slave) - contractCost;
diff --git a/src/events/reRecruit/womanlyPC.js b/src/events/reRecruit/womanlyPC.js
index 3521828f60c46b8edb36deb7553cbe44b6f182f4..cb3239fcd9d9f1411932043d5460187272d8c04d 100644
--- a/src/events/reRecruit/womanlyPC.js
+++ b/src/events/reRecruit/womanlyPC.js
@@ -20,7 +20,7 @@ App.Events.recWomanlyPC = class recWomanlyPC extends App.Events.BaseEvent {
 
 	execute(node) {
 		const slave = makeSlave();
-		const {He, he, his, him, himself, woman} = getPronouns(slave);
+		const {He, he, his, him, woman} = getPronouns(slave);
 		const {himselfA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 		let r = [];
 
@@ -57,7 +57,7 @@ App.Events.recWomanlyPC = class recWomanlyPC extends App.Events.BaseEvent {
 			const el = new DocumentFragment();
 			let r = [];
 			cashX(forceNeg(contractCost), "slaveTransfer", slave);
-			r.push(`You put ${him} through the enslavement procedures. ${He}'s almost excited. Though ${he} knows ${he}'s signed ${himself} over to a life of sexual slavery, the anticipation of becoming more feminine is clearly more important to ${him} than any kind of fear.`);
+			r.push(`You put ${him} through the enslavement procedures. ${He} looks relieved, as though ${he} thinks ${he} no longer has anything to worry about. ${He}'s certainly more complacent than the average inductee.`);
 			r.push(App.UI.newSlaveIntro(slave));
 			App.Events.addNode(el, r);
 			return el;
@@ -86,6 +86,7 @@ App.Events.recWomanlyPC = class recWomanlyPC extends App.Events.BaseEvent {
 			slave.skill.anal = 0;
 			slave.skill.oral = 15;
 			slave.vagina = 1;
+			slave.behavioralFlaw = "hates men";
 			slave.skill.vaginal = 15;
 			slave.piercing.ear.weight = either(0, 1);
 			slave.piercing.navel.weight = either(0, 1);
diff --git a/src/events/recETS/recetsIdenticalHermPair.js b/src/events/recETS/recetsIdenticalHermPair.js
index 2128d10917c6a8068df18a68a01719b792d54858..cf6663d961bf3b45d0d881a924305ec59dc5f54e 100644
--- a/src/events/recETS/recetsIdenticalHermPair.js
+++ b/src/events/recETS/recetsIdenticalHermPair.js
@@ -60,9 +60,7 @@ App.Events.recetsIdenticalHermPair = class recetsIdenticalHermPair extends App.E
 		setMissingParents(thing1);
 		thing1.canRecruit = 0;
 		thing1.relationship = 4;
-
-		let cost = slaveCost(thing1);
-		let contractCost = cost;
+		const contractCost = slaveCost(thing1) * 2;
 
 		const thing2 = generateRelatedSlave(thing1, "twin");
 		thing2.energy = Math.max(thing2.energy, 40);
@@ -123,15 +121,15 @@ App.Events.recetsIdenticalHermPair = class recetsIdenticalHermPair extends App.E
 		}
 
 		App.Events.addParagraph(node, [Spoken(thing2, `"We cost ${cashFormat(contractCost)}, ${(V.PC.title !== 0) ? "sir" : "ma'am"}."`)]);
-		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical.`, ["detail"]);
 
 		const newSlaves = [thing1, thing2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -139,9 +137,9 @@ App.Events.recetsIdenticalHermPair = class recetsIdenticalHermPair extends App.E
 
 		function both() {
 			newSlave(thing1);
-			cashX(forceNeg(contractCost), "slaveTransfer", thing1);
 			newSlave(thing2);
-			cashX(forceNeg(contractCost), "slaveTransfer", thing2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", thing1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", thing2);
 			return [
 				`They giggle and kiss each other rather passionately, their miniskirts ${V.seePreg ? `becoming pinned against their pregnancies` : `being lifted toward their navels`} by their stiffening pricks. They're very well trained but not very disciplined, though their pervertedness will be fun.`,
 				Spoken(thing2, `"You know we ${V.seePreg ? `each are carrying the other's twins` : `took each other's virginities`}, right?"`),
diff --git a/src/events/recETS/recetsIdenticalPair.js b/src/events/recETS/recetsIdenticalPair.js
index d47deb0310eeea3bdccb4417211d012f6bcf0372..551ad443bdb640dd50a64fda94e1458e8cbe5113 100644
--- a/src/events/recETS/recetsIdenticalPair.js
+++ b/src/events/recETS/recetsIdenticalPair.js
@@ -53,8 +53,7 @@ App.Events.recetsIdenticalPair = class recetsIdenticalPair extends App.Events.Ba
 		setMissingParents(thing1);
 		thing1.canRecruit = 0;
 		thing1.relationship = 2;
-		let cost = slaveCost(thing1);
-		const contractCost = cost;
+		const contractCost = slaveCost(thing1) * 2 ;
 
 		const thing2 = generateRelatedSlave(thing1, "twin");
 		thing2.energy = Math.max(thing2.energy, 40);
@@ -77,15 +76,15 @@ App.Events.recetsIdenticalPair = class recetsIdenticalPair extends App.Events.Ba
 		]);
 
 		App.Events.addParagraph(node, [Spoken(thing2, `"We cost ${cashFormat(contractCost)}, ${(V.PC.title !== 0) ? "sir" : "ma'am"}."`)]);
-		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical.`, ["detail"]);
 
 		const newSlaves = [thing1, thing2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -93,9 +92,9 @@ App.Events.recetsIdenticalPair = class recetsIdenticalPair extends App.Events.Ba
 
 		function both() {
 			newSlave(thing1);
-			cashX(forceNeg(contractCost), "slaveTransfer", thing1);
 			newSlave(thing2);
-			cashX(forceNeg(contractCost), "slaveTransfer", thing2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", thing1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", thing2);
 			return App.UI.DOM.combineNodes(
 				`They giggle and kiss each other rather sexually, pressing their nearly identical bodies closely together. They're clearly very well trained.`,
 				newSlaveIncestSex(thing1, thing2)
diff --git a/src/events/recETS/recetsIncestBrotherBrother.js b/src/events/recETS/recetsIncestBrotherBrother.js
index 6268372492c0142c2ff3b94233d7e9d66db9d7f5..f32c9036ae9b21ea231589f0d2062833c2d5e8a7 100644
--- a/src/events/recETS/recetsIncestBrotherBrother.js
+++ b/src/events/recETS/recetsIncestBrotherBrother.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const brother1 = GenerateNewSlave("XY", {
 			minAge: Math.max(V.potencyAge + 2, V.minimumSlaveAge + 2), maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -35,7 +35,6 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 		setMissingParents(brother1);
 		brother1.canRecruit = 0;
 		brother1.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const brother2 = generateRelatedSlave(brother1, "younger brother");
 		brother2.height += random(-5, 5);
@@ -55,9 +54,7 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 		brother2.relationshipTarget = brother1.ID;
 		brother1.relationshipTarget = brother2.ID;
 
-		const {
-			sister
-		} = getPronouns(brother1);
+		const {sister} = getPronouns(brother1);
 		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
@@ -66,15 +63,15 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [brother1, brother2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -83,8 +80,8 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 		function both() {
 			newSlave(brother2);
 			newSlave(brother1);
-			cashX(forceNeg(contractCost), "slaveTransfer", brother1);
-			cashX(forceNeg(contractCost), "slaveTransfer", brother2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", brother1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", brother2);
 			return [
 				`They hug each other tightly as the older ${sister} slips a hand down the younger's pants. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(brother1, brother2)
diff --git a/src/events/recETS/recetsIncestBrotherSister.js b/src/events/recETS/recetsIncestBrotherSister.js
index 6f07cec0db1ec9b645ef082b995020e8cff786c2..33d02a20b8d8b5ca1af275345268644bcd6d5e8e 100644
--- a/src/events/recETS/recetsIncestBrotherSister.js
+++ b/src/events/recETS/recetsIncestBrotherSister.js
@@ -14,7 +14,7 @@ App.Events.recetsIncestBrotherSister = class recetsIncestBrotherSister extends A
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const sis = GenerateNewSlave("XX", {
 			minAge: Math.max(V.fertilityAge, V.potencyAge + 2, V.minimumSlaveAge + 2), maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -39,7 +39,6 @@ App.Events.recetsIncestBrotherSister = class recetsIncestBrotherSister extends A
 		setMissingParents(sis);
 		sis.canRecruit = 0;
 		sis.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const bro = generateRelatedSlave(sis, "younger brother");
 		bro.pubicHStyle = "shaved";
@@ -83,15 +82,15 @@ App.Events.recetsIncestBrotherSister = class recetsIncestBrotherSister extends A
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [sis, bro];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -100,8 +99,8 @@ App.Events.recetsIncestBrotherSister = class recetsIncestBrotherSister extends A
 		function both() {
 			newSlave(bro);
 			newSlave(sis);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis);
-			cashX(forceNeg(contractCost), "slaveTransfer", bro);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", bro);
 			return [
 				`They cheer happily and hug each other tightly. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(sis, bro)
diff --git a/src/events/recETS/recetsIncestFatherDaughter.js b/src/events/recETS/recetsIncestFatherDaughter.js
index 1feb9d539cbff392c4b18b889039eb97b4ae3616..b45a91f700f868aad58e1988ec70cdc1b6f5b7a6 100644
--- a/src/events/recETS/recetsIncestFatherDaughter.js
+++ b/src/events/recETS/recetsIncestFatherDaughter.js
@@ -15,7 +15,7 @@ App.Events.recetsIncestFatherDaughter = class recetsIncestFatherDaughter extends
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const father = GenerateNewSlave("XY", {
 			minAge: Math.max(V.potencyAge + 20, V.fertilityAge + 20, V.minimumSlaveAge + 20), maxAge: 40, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -38,7 +38,6 @@ App.Events.recetsIncestFatherDaughter = class recetsIncestFatherDaughter extends
 		father.behavioralQuirk = "sinful";
 		father.canRecruit = 0;
 		father.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const daughter = generateRelatedSlave(father, "daughter");
 		daughter.vagina = 3;
@@ -92,15 +91,15 @@ App.Events.recetsIncestFatherDaughter = class recetsIncestFatherDaughter extends
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost*2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [father, daughter];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -109,8 +108,8 @@ App.Events.recetsIncestFatherDaughter = class recetsIncestFatherDaughter extends
 		function both() {
 			newSlave(daughter);
 			newSlave(father);
-			cashX(forceNeg(contractCost), "slaveTransfer", father);
-			cashX(forceNeg(contractCost), "slaveTransfer", daughter);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", father);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", daughter);
 			return [
 				`The ${daughter2} cheers happily and hugs ${his2} relieved father. ${He} leans in and kisses ${him2} deeply. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(father, daughter)
diff --git a/src/events/recETS/recetsIncestFatherSon.js b/src/events/recETS/recetsIncestFatherSon.js
index 44a969d7d21a960001f4d8422158357cbe9de019..50458bd83118316f521bfd5f5e1b318ab8075375 100644
--- a/src/events/recETS/recetsIncestFatherSon.js
+++ b/src/events/recETS/recetsIncestFatherSon.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestFatherSon = class recetsIncestFatherSon extends App.Event
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const father = GenerateNewSlave("XY", {
 			minAge: Math.max(V.potencyAge + 20, V.minimumSlaveAge + 20), maxAge: 40, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -36,7 +36,6 @@ App.Events.recetsIncestFatherSon = class recetsIncestFatherSon extends App.Event
 		father.behavioralQuirk = "sinful";
 		father.canRecruit = 0;
 		father.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const son = generateRelatedSlave(father, "son");
 		son.career = "a student";
@@ -66,15 +65,15 @@ App.Events.recetsIncestFatherSon = class recetsIncestFatherSon extends App.Event
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [father, son];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -83,8 +82,8 @@ App.Events.recetsIncestFatherSon = class recetsIncestFatherSon extends App.Event
 		function both() {
 			newSlave(son);
 			newSlave(father);
-			cashX(forceNeg(contractCost), "slaveTransfer", father);
-			cashX(forceNeg(contractCost), "slaveTransfer", son);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", father);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", son);
 			return [
 				`The father hugs ${his} ${daughter2} tight and slips a hand down ${his2} pants. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(father, son)
diff --git a/src/events/recETS/recetsIncestMotherDaughter.js b/src/events/recETS/recetsIncestMotherDaughter.js
index 9d24ea18678e4d4f738c17d998680d3a3cc85f13..bc220e238aff8684bf8388882a0cc9a68f36c569 100644
--- a/src/events/recETS/recetsIncestMotherDaughter.js
+++ b/src/events/recETS/recetsIncestMotherDaughter.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestMotherDaughter = class recetsIncestMotherDaughter extends
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const mother = GenerateNewSlave("XX", {
 			minAge: Math.max(V.fertilityAge + 20, V.minimumSlaveAge + 20), maxAge: 40, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -47,7 +47,6 @@ App.Events.recetsIncestMotherDaughter = class recetsIncestMotherDaughter extends
 		mother.behavioralQuirk = "sinful";
 		mother.canRecruit = 0;
 		mother.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const daughter = generateRelatedSlave(mother, "daughter");
 		daughter.career = "a student";
@@ -87,15 +86,15 @@ App.Events.recetsIncestMotherDaughter = class recetsIncestMotherDaughter extends
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [mother, daughter];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -104,8 +103,8 @@ App.Events.recetsIncestMotherDaughter = class recetsIncestMotherDaughter extends
 		function both() {
 			newSlave(daughter);
 			newSlave(mother);
-			cashX(forceNeg(contractCost), "slaveTransfer", mother);
-			cashX(forceNeg(contractCost), "slaveTransfer", daughter);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", mother);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", daughter);
 			return [
 				`The ${daughter2} cheers happily and hugs ${his2} relieved mother. ${He} leans in and kisses ${him2} deeply. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(mother, daughter)
diff --git a/src/events/recETS/recetsIncestMotherSon.js b/src/events/recETS/recetsIncestMotherSon.js
index c4c921ccda5e5bb565bc6513fadcba4d047b445a..4cc7983b64c523863af89e51790b46e96be6357f 100644
--- a/src/events/recETS/recetsIncestMotherSon.js
+++ b/src/events/recETS/recetsIncestMotherSon.js
@@ -14,7 +14,7 @@ App.Events.recetsIncestMotherSon = class recetsIncestMotherSon extends App.Event
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const mother = GenerateNewSlave("XX", {
 			minAge: Math.max(V.fertilityAge + 20, V.potencyAge + 20, V.minimumSlaveAge + 20), maxAge: 40, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -47,7 +47,6 @@ App.Events.recetsIncestMotherSon = class recetsIncestMotherSon extends App.Event
 		mother.behavioralQuirk = "sinful";
 		mother.canRecruit = 0;
 		mother.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const son = generateRelatedSlave(mother, "son");
 		son.career = "a student";
@@ -82,16 +81,11 @@ App.Events.recetsIncestMotherSon = class recetsIncestMotherSon extends App.Event
 			WombChangeGene(mother, "motherName", mother.slaveName);
 		}
 
-		const {
-			He,
-			his
-		} = getPronouns(mother);
+		const {He, his} = getPronouns(mother);
 		const {
 			daughter2, his2, him2
 		} = getPronouns(son).appendSuffix("2");
-		const {
-			HeA
-		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
+		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 		const children = mother.pregType > 1 ? "children" : "child";
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
@@ -100,15 +94,15 @@ App.Events.recetsIncestMotherSon = class recetsIncestMotherSon extends App.Event
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [mother, son];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -117,8 +111,8 @@ App.Events.recetsIncestMotherSon = class recetsIncestMotherSon extends App.Event
 		function both() {
 			newSlave(son);
 			newSlave(mother);
-			cashX(forceNeg(contractCost), "slaveTransfer", mother);
-			cashX(forceNeg(contractCost), "slaveTransfer", son);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", mother);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", son);
 			return [
 				`The ${daughter2} cheers happily and hugs ${his2} relieved mother. ${He} leans in and kisses ${him2} deeply. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(mother, son)
diff --git a/src/events/recETS/recetsIncestSisterSister.js b/src/events/recETS/recetsIncestSisterSister.js
index ff684f5355d1c16f100e5af37f1e844107e777b6..9c81d5d7d17a61854fc7f588b5db618b2d379f8e 100644
--- a/src/events/recETS/recetsIncestSisterSister.js
+++ b/src/events/recETS/recetsIncestSisterSister.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestSisterSister = class recetsIncestSisterSister extends App
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const sis1 = GenerateNewSlave("XX", {
 			minAge: V.minimumSlaveAge + 2, maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -37,7 +37,6 @@ App.Events.recetsIncestSisterSister = class recetsIncestSisterSister extends App
 		setMissingParents(sis1);
 		sis1.canRecruit = 0;
 		sis1.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const sis2 = generateRelatedSlave(sis1, "younger sister");
 		sis2.pubicHStyle = "bushy";
@@ -54,12 +53,8 @@ App.Events.recetsIncestSisterSister = class recetsIncestSisterSister extends App
 
 		sis1.relationshipTarget = sis2.ID;
 
-		const {
-			sister
-		} = getPronouns(sis1);
-		const {
-			HeA
-		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
+		const {sister} = getPronouns(sis1);
+		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
 
@@ -67,15 +62,15 @@ App.Events.recetsIncestSisterSister = class recetsIncestSisterSister extends App
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [sis1, sis2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -84,8 +79,8 @@ App.Events.recetsIncestSisterSister = class recetsIncestSisterSister extends App
 		function both() {
 			newSlave(sis2);
 			newSlave(sis1);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis1);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis2);
 			return [
 				`They cheer happily and hug each other tightly. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(sis1, sis2)
diff --git a/src/events/recETS/recetsIncestTwinBrother.js b/src/events/recETS/recetsIncestTwinBrother.js
index 1606396cb110305e872d6d7bbb0c7d64d97f012a..8ab785f01258588c744138c8b8ef81215b3bfdfa 100644
--- a/src/events/recETS/recetsIncestTwinBrother.js
+++ b/src/events/recETS/recetsIncestTwinBrother.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const brother1 = GenerateNewSlave("XY", {
 			minAge: Math.max(V.potencyAge, V.minimumSlaveAge), maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -47,10 +47,7 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E
 		brother2.relationshipTarget = brother1.ID;
 		brother1.relationshipTarget = brother2.ID;
 
-		const {
-			sister
-		} = getPronouns(brother1);
-
+		const {sister} = getPronouns(brother1);
 		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
@@ -59,15 +56,15 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [brother1, brother2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -76,8 +73,8 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E
 		function both() {
 			newSlave(brother2);
 			newSlave(brother1);
-			cashX(forceNeg(contractCost), "slaveTransfer", brother1);
-			cashX(forceNeg(contractCost), "slaveTransfer", brother2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", brother1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", brother2);
 			return [
 				`They hug each other tightly as they slip a hand down the other's pants. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(brother1, brother2)
diff --git a/src/events/recETS/recetsIncestTwinSister.js b/src/events/recETS/recetsIncestTwinSister.js
index 86359872b6232ac9d254533d7227f666c5a69722..091551daba1c0aa53aff34f6db38158740bd63df 100644
--- a/src/events/recETS/recetsIncestTwinSister.js
+++ b/src/events/recETS/recetsIncestTwinSister.js
@@ -13,7 +13,7 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const sis1 = GenerateNewSlave("XX", {
 			minAge: Math.max(V.fertilityAge, V.minimumSlaveAge), maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -36,7 +36,6 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 		setMissingParents(sis1);
 		sis1.canRecruit = 0;
 		sis1.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const sis2 = generateRelatedSlave(sis1, "twin");
 		sis2.slaveName = sis2.birthName;
@@ -51,10 +50,7 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 		sis1.relationshipTarget = sis2.ID;
 
 		const {sister} = getPronouns(sis1);
-
-		const {
-			HeA
-		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
+		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
 
@@ -62,15 +58,15 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [sis1, sis2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -79,8 +75,8 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 		function both() {
 			newSlave(sis2);
 			newSlave(sis1);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis1);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis2);
 			return [
 				`They cheer happily and hug each other tightly. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(sis1, sis2)
diff --git a/src/events/recETS/recetsIncestTwinsMixed.js b/src/events/recETS/recetsIncestTwinsMixed.js
index 7ce1c60997e0e337fdf09cb3d11c856c26d51c9a..da82a05d02f9cc6568edb6973acbe3d802197aca 100644
--- a/src/events/recETS/recetsIncestTwinsMixed.js
+++ b/src/events/recETS/recetsIncestTwinsMixed.js
@@ -14,7 +14,7 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		const contractCost = 10000;
+		const contractCost = 10000 * 2;
 		const sis = GenerateNewSlave("XX", {
 			minAge: Math.max(V.fertilityAge, V.potencyAge, V.minimumSlaveAge), maxAge: 20, ageOverridesPedoMode: 1, disableDisability: 1
 		});
@@ -38,7 +38,6 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 		setMissingParents(sis);
 		sis.canRecruit = 0;
 		sis.relationship = 3;
-		/* cost not needed, no option to sell */
 
 		const bro = generateRelatedSlave(sis, "twin", true);
 		bro.height += random(-5, 5);
@@ -78,10 +77,8 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 			WombChangeGene(sis, "motherName", sis.slaveName);
 		}
 
+		const {he, his} = getPronouns(sis);
 		const {HeA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
-		const {
-			he, his
-		} = getPronouns(sis);
 		const children = sis.pregType > 1 ? "children" : "child";
 
 		App.Events.addParagraph(node, [`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`]);
@@ -90,15 +87,15 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 
 		App.Events.addParagraph(node, [`${capFirstChar(V.assistant.name)} assembles a dossier of information and photos from information they've sent describing their bodies and skills, to be used as a substitute for an in-person inspection.`]);
 
-		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost * 2)} to enslave the two of them.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `It would cost ${cashFormat(contractCost)} to enslave the two of them.`, ["detail"]);
 
 		const newSlaves = [sis, bro];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -107,8 +104,8 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 		function both() {
 			newSlave(bro);
 			newSlave(sis);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis);
-			cashX(forceNeg(contractCost), "slaveTransfer", bro);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", bro);
 			return [
 				`They cheer happily and hug each other tightly. They ought to be an interesting addition to your penthouse.`,
 				newSlaveIncestSex(sis, bro)
diff --git a/src/events/recETS/recetsMatchedPair.js b/src/events/recETS/recetsMatchedPair.js
index 84dd394ec1bd703545464342ff51e48947520d6d..27ffa9b7645aa30a94a4647d429436711873e265 100644
--- a/src/events/recETS/recetsMatchedPair.js
+++ b/src/events/recETS/recetsMatchedPair.js
@@ -13,7 +13,6 @@ App.Events.recetsMatchedPair = class recetsMatchedPair extends App.Events.BaseEv
 
 	execute(node) {
 		V.encyclopedia = "Enslaving People";
-		/* contractCost not needed, no option to sell */
 		const sis1 = GenerateNewSlave("XY", {minAge: 12, maxAge: 21, disableDisability: 1});
 		sis1.origin = "$He was brought up in a radical slave school to match $his twin.";
 		sis1.career = "a slave";
@@ -55,8 +54,7 @@ App.Events.recetsMatchedPair = class recetsMatchedPair extends App.Events.BaseEv
 		setMissingParents(sis1);
 		sis1.canRecruit = 0;
 		sis1.relationship = 2;
-		let cost = slaveCost(sis1);
-		let contractCost = cost;
+		const contractCost = slaveCost(sis1) * 2;
 
 		const sis2 = generateRelatedSlave(sis1, "twin", true);
 		sis2.vagina = 1;
@@ -82,9 +80,7 @@ App.Events.recetsMatchedPair = class recetsMatchedPair extends App.Events.BaseEv
 		sis1.relationshipTarget = sis2.ID;
 
 		const {His, his} = getPronouns(sis1);
-		const {
-			he2, sister2,
-		} = getPronouns(sis2).appendSuffix("2");
+		const {he2, sister2} = getPronouns(sis2).appendSuffix("2");
 
 		let r = [];
 
@@ -104,15 +100,15 @@ App.Events.recetsMatchedPair = class recetsMatchedPair extends App.Events.BaseEv
 		r = [];
 		r.push(Spoken(sis2, `"We cost ${cashFormat(contractCost)}, ${(V.PC.title !== 0) ? "sir" : "ma'am"}."`));
 		App.Events.addParagraph(node, r);
-		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical except that ${he2} is naturally female and lacks implants, having reached that size the normal way.`, "detail");
+		App.UI.DOM.appendNewElement("p", node, `${His} ${sister2} is identical except that ${he2} is naturally female and lacks implants, having reached that size the normal way.`, ["detail"]);
 
 		const newSlaves = [sis1, sis2];
 
 		node.append(App.UI.MultipleInspect(newSlaves, true, "generic"));
 		const choices = [];
 
-		if (V.cash >= (contractCost * 2)) {
-			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost * 2)}`));
+		if (V.cash >= contractCost) {
+			choices.push(new App.Events.Result(`Buy them both`, both, `This will cost ${cashFormat(contractCost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave them.`));
 		}
@@ -120,9 +116,9 @@ App.Events.recetsMatchedPair = class recetsMatchedPair extends App.Events.BaseEv
 
 		function both() {
 			newSlave(sis1);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis1);
 			newSlave(sis2);
-			cashX(forceNeg(contractCost), "slaveTransfer", sis2);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis1);
+			cashX(forceNeg(contractCost / 2), "slaveTransfer", sis2);
 			return [
 				`They giggle and kiss each other rather sexually, pressing their nearly identical bodies closely together so their hips and shapely buttocks hide any sign of their difference. They're clearly very well trained.`,
 				newSlaveIncestSex(sis1, sis2)];
diff --git a/src/events/recETS/recetsMismatchedPair.js b/src/events/recETS/recetsMismatchedPair.js
index a29631effe56604bfe04022b766f361968227133..eb07df36e443b4edc4acae61e8829f6939a66ab7 100644
--- a/src/events/recETS/recetsMismatchedPair.js
+++ b/src/events/recETS/recetsMismatchedPair.js
@@ -141,8 +141,8 @@ App.Events.recetsMismatchedPair = class recetsMismatchedPair extends App.Events.
 
 		function both() {
 			newSlave(bro);
-			cashX(forceNeg(contractCost), "slaveTransfer", bro);
 			newSlave(sis);
+			cashX(forceNeg(contractCost), "slaveTransfer", bro);
 			cashX(forceNeg(contractCost), "slaveTransfer", sis);
 			const frag = new DocumentFragment();
 			App.Events.addParagraph(frag, [`The poor sissy isn't happy to become a slave, but ${he}'s clearly relieved to be away from ${his} ${sister2}. The bitch isn't likely to have an easy time; the sale didn't clear ${him2} from debt. ${bro.slaveName} describes ${his} basic sexual experience, which includes a lot of sucking and anal whoring. Without further ado ${he} moves from practical sexual slavery at the hands of ${his} ${sister2} to actual sexual slavery.`]);
diff --git a/src/events/recFS/recfsPastoralistTwo.js b/src/events/recFS/recfsPastoralistTwo.js
index 70f314e17507f939ba99f67b47ba9a3da57ecfb8..128971114480ff836df1d5ebe610dbc96918ea6c 100644
--- a/src/events/recFS/recfsPastoralistTwo.js
+++ b/src/events/recFS/recfsPastoralistTwo.js
@@ -64,7 +64,7 @@ App.Events.recFSPastoralistTwo = class recFSPastoralistTwo extends App.Events.Ba
 		function enslave() {
 			const frag = new DocumentFragment();
 			r = [];
-			r.push(`${He} speaks to you as a free ${woman} while working through the enslavement process, perhaps ${he} hasn't quite grasped ${his} new role. Nonetheless, it seems as if a vast weight has been lifted from ${his} shoulders. You've seen this before, the perverse internal freedom that comes with the knowledge that ${his} life is in the hands of another now, and that all ${he} has to do or can do is obey. ${His} last words to you as a free ${woman} are an ironic statement that, people always praised ${his} milk filled udders as givers of life, yet ${he} never thought they'd save ${hers} one day.`);
+			r.push(`${He} speaks to you as a free ${woman} while working through the enslavement process, perhaps ${he} hasn't quite grasped ${his} new role. Nonetheless, it seems as if a vast weight has been lifted from ${his} shoulders. You've seen this before, the perverse internal freedom that comes with the knowledge that ${his} life is in the hands of another now, and that all ${he} has to do or can do is obey. ${His} last words to you as a free ${woman} are an ironic statement that, people always praised ${his} milk-filled udders as givers of life, yet ${he} never thought they'd save ${hers} one day.`);
 
 			r.push(App.UI.newSlaveIntro(slave));
 			App.Events.addParagraph(frag, r);
diff --git a/src/events/scheduled/pitFightLethal.js b/src/events/scheduled/pitFightLethal.js
index d09c164e8666f819a9e0bb8fbcf2bc0776547475..a219ff8588ea5e2278ea5e6cd0e0455a12befd33 100644
--- a/src/events/scheduled/pitFightLethal.js
+++ b/src/events/scheduled/pitFightLethal.js
@@ -403,7 +403,7 @@ App.Facilities.Pit.lethalFight = function(fighters) {
 
 						repX(-20, "pit", loser);
 					}
-				} else if (deadliness(winner) < deadliness(loser) + 3) {
+				} else if (animal.deadliness < deadliness(loser) + 3) {
 					if (loser.skill.combat > 0) {
 						r.push(`${loser.slaveName} is fairly confident in ${his} fighting abilities, and ${he} knows that this fight is fairly evenly matched.`);
 					} else {
diff --git a/src/events/scheduled/seNicaeaCouncil.js b/src/events/scheduled/seNicaeaCouncil.js
index a84db3a84a94f58bed996f0fb317460d7bfd7fdc..5b8af802a69930e7563daf6c7d691a0edb4e60a1 100644
--- a/src/events/scheduled/seNicaeaCouncil.js
+++ b/src/events/scheduled/seNicaeaCouncil.js
@@ -66,6 +66,7 @@ App.Events.SENicaeaCouncil = class SENicaeaCouncil extends App.Events.BaseEvent
 				r.push(`but the weak Council may lead to a weak creed.`);
 			}
 			App.Events.addParagraph(node, r);
+			r = [];
 		}
 
 		const container	= App.UI.DOM.appendNewElement("div", node);
diff --git a/src/events/scheduled/seTheSirenStrikesBack.js b/src/events/scheduled/seTheSirenStrikesBack.js
index 32d404f5f17f77a32d2fd6f8c0a10ca32321fb84..e6d023e191c41ac3549ace0dd4b1d1ff4f15265a 100644
--- a/src/events/scheduled/seTheSirenStrikesBack.js
+++ b/src/events/scheduled/seTheSirenStrikesBack.js
@@ -58,7 +58,7 @@ App.Events.SETheSirenStrikesBack = class SETheSirenStrikesBack extends App.Event
 
 		App.Events.addParagraph(node, [`Several weeks have passed since you gained the musical prodigy and you couldn't help but notice ${his} constant scowl and muttering about "getting revenge one day" or "wishing ${his} producer would pay for what happened" whenever ${he} was not working. You decide to look into the incident and direct ${V.assistant.name} to look into the financial situation of ${his} record label. It turns out that not only should this slave not be eligible for enslavement due to ${his} performance profits, but a certain someone has been taking that money for themselves. You issue a bounty for ${his} producer and await a response. With surprising speed, an answer comes from a bounty hunter. The underhanded producer never left the arcology, instead opting to make use of the guest living arrangements you had set up for the concert. Only when an announcement of the bounty went out did ${he2} realize ${his2} peril and attempt to flee. The bounty hunter literally drags the escapee by the collar into your penthouse and throws ${him2} at your feet. The coward shivers as your eyes meet ${hers2}.`]);
 
-		App.Events.addParagraph(node, [`"Please, don't hurt me! I'll pay for that slave I sent you to be released, even set ${him} up with the life ${he2} would have had if I hadn't embezzled the profits!"`]);
+		App.Events.addParagraph(node, [`"Please, don't hurt me! I'll pay for that slave I sent you to be released, even set ${him} up with the life ${he} would have had if I hadn't embezzled the profits!"`]);
 
 		if (swan && swan.fuckdoll === 0 && swan.fetish !== Fetish.MINDBROKEN) {
 			const {title: Master} = getEnunciation(swan);
@@ -70,7 +70,7 @@ App.Events.SETheSirenStrikesBack = class SETheSirenStrikesBack extends App.Event
 			}
 			r.push(`${his} face quickly donning a scowl of pure anger and hatred.`);
 			if (canTalk(swan)) {
-				r.push(`"${Master}, please let me have my revenge on this despicable lowlife," ${he} hisses. "I promise not to kill ${him2}, just hurt ${him2} enough to let ${him2} know the suffering they caused me."`);
+				r.push(`"${Master}, please let me have my revenge on this despicable lowlife," ${he} hisses. "I promise not to kill ${him2}, just hurt ${him2} enough to let ${him2} know the suffering ${he2} caused me."`);
 			} else {
 				r.push(`${He} may not be able to talk anymore, but ${his} request of you is very clear across ${his} face.`);
 			}
@@ -106,7 +106,7 @@ App.Events.SETheSirenStrikesBack = class SETheSirenStrikesBack extends App.Event
 			healthDamage(producer, 20);
 			swan.devotion += 2;
 			swan.trust += 2;
-			App.Events.drawEventArt(node, producer); // TODO: update event art instead, maybe
+			App.Events.refreshEventArt(producer);
 
 			r.push(`You decide to give the victimized prodigy a chance for payback. ${He} moves over to ${his} former boss and begins to caress the despicable thief as ${he2} shakes with dread of what is to come. As ${he} moves lower, ${he} applies more pressure, peaking right on the genitals. The cowardly former executive yelps in pain, instinctively trying to get away from the`);
 			if (hasAnyArms(swan)) {
@@ -146,7 +146,7 @@ App.Events.SETheSirenStrikesBack = class SETheSirenStrikesBack extends App.Event
 			const frag = new DocumentFragment();
 			let r = [];
 			producer.clothes = "no clothing";
-			App.Events.drawEventArt(node, producer); // TODO: update event art instead, maybe
+			App.Events.refreshEventArt(producer);
 			r.push(`You spare the coward the pain and humiliation ${he2} deserves and simply enslave ${him2}.`);
 			r.push(App.UI.newSlaveIntro(producer));
 			App.Events.addParagraph(frag, r);
@@ -157,7 +157,7 @@ App.Events.SETheSirenStrikesBack = class SETheSirenStrikesBack extends App.Event
 			const frag = new DocumentFragment();
 			let r = [];
 			producer.clothes = "no clothing";
-			App.Events.drawEventArt(node, producer); // TODO: update event art instead, maybe
+			App.Events.refreshEventArt(producer);
 			r.push(`You decide the coward needs more punishment. You order a whip brought to you and give ${him2} several lashes directly across ${his2} exposed genitalia. ${He2} cries out with each lash as ${his2} nethers accumulate angry red welts, some even bleeding slightly. After the yelps stop, you feel enough punishment has been given for now and have the producer turned slave hauled to ${his2} feet for a proper inspection.`);
 			r.push(App.UI.newSlaveIntro(producer));
 			App.Events.addParagraph(frag, r);
diff --git a/src/events/scheduled/seWedding.js b/src/events/scheduled/seWedding.js
index b589e972c6b32e56ee293ca4a86ec01e2cfe34bd..3b0399cb8f538597f73c53ee1cadd893d4ccd904 100644
--- a/src/events/scheduled/seWedding.js
+++ b/src/events/scheduled/seWedding.js
@@ -1322,7 +1322,7 @@ App.Events.SEWedding = class SEWedding extends App.Events.BaseEvent {
 					App.Events.addParagraph(node, r);
 					r = [];
 					// TODO: marked for rewrite
-					r.push(`Once the ceremony is complete, you scoop up your new, protesting, slave ${wives} to carry them back into the master bedroom. They rest their heads against your ${PCChest}, simply too tired to care anymore. By the time they're home, they're fast asleep. You set them gently down on the bed and curl up behind them, feeling the animal warmth of their bodies as the exhausted slaves' chest rise and fall with their breathing. They squirms slightly in their sleep to the unwelcome feeling of your arm around them.`);
+					r.push(`Once the ceremony is complete, you scoop up your new, protesting, slave ${wives} to carry them back into the master bedroom. They rest their heads against your ${PCChest}, simply too tired to care anymore. By the time they're home, they're fast asleep. You set them gently down on the bed and curl up behind them, feeling the animal warmth of their bodies as the exhausted slaves' chests rise and fall with their breathing. They squirm slightly in their sleep to the unwelcome feeling of your arm around them.`);
 				} else if (slave1.devotion < -20) {
 					// TODO: rewrite for slaves that can't walk
 					r.push(`They spent the day before resting and crying to themselves, and this was a necessary precaution. They spend most of the day-long party at the center of a nonstop gangbang, screaming mixed cries of pleasure and horror. The theory is that they'll be bound to you as your slave ${wives} from this day onward, so they must get the promiscuity that is a sex slave's responsibility out of the way now. Whatever their opinions on the idea, your guests take part with enthusiasm, completely unhampered by your slave's utter unwillingness. Many brought their own slaves to participate, too. ${namesString} spend hours with numerous cocks inside them, with attending slaves using their mouths on any erogenous zones they can reach. When the moment of the ceremony nears, they're extracted and taken off to be bathed.`);
diff --git a/src/facilities/bodyModification/bodyModification.js b/src/facilities/bodyModification/bodyModification.js
index 2b149eaeef670eaa147ab95627cfd13561574055..914d37a5023a2ba718485aeec5a89b83b1d617c4 100644
--- a/src/facilities/bodyModification/bodyModification.js
+++ b/src/facilities/bodyModification/bodyModification.js
@@ -433,7 +433,6 @@ App.UI.bodyModification = function(slave, cheat = false) {
 			if (!hasAnyNaturalArms(slave)) {
 				removeTattooLocation("upper arm");
 			}
-
 			if (!hasAnyNaturalArms(slave)) {
 				removeTattooLocation("thigh");
 			}
@@ -441,7 +440,10 @@ App.UI.bodyModification = function(slave, cheat = false) {
 			if (slave.dick === 0 || tattooChoice === "scenes") {
 				removeTattooLocation("dick");
 			}
-			if ((tattooChoice === "Asian art" || tattooChoice === "scenes") && slave.anusTat === "bleached") { // leave existing bleached anus alone
+			if (tattooChoice === "scenes") {
+				removeTattooLocation("lips");
+			}
+			if ((tattooChoice === "Asian art" || tattooChoice === "scenes") || slave.anusTat === "bleached") { // leave existing bleached anus alone
 				removeTattooLocation("anus");
 			}
 		}
@@ -469,7 +471,7 @@ App.UI.bodyModification = function(slave, cheat = false) {
 					() => {
 						for (const location of validTattooLocations) {
 							if (slave[`${location}tattoo`] !== tattooChoice) {
-								applyTat(location);
+								applyTat(location, tattooChoice);
 							}
 						}
 						refresh();
@@ -484,7 +486,7 @@ App.UI.bodyModification = function(slave, cheat = false) {
 					App.UI.DOM.link(
 						capFirstChar(location),
 						() => {
-							applyTat(location);
+							applyTat(location, tattooChoice);
 							refresh();
 						}
 					)
@@ -515,10 +517,9 @@ App.UI.bodyModification = function(slave, cheat = false) {
 
 		return el;
 
-		function applyTat(location) {
-			tattooChoice = (location === "lips" && tattooChoice === "scenes") ? "permanent makeup" : tattooChoice;
-			modReaction += App.Medicine.Modification.setTattoo(slave, tattooLocations.get(location), tattooChoice, cheat);
-			if (!["flowers", "paternalist", "tribal patterns", 0].includes(tattooChoice)) {
+		function applyTat(location, style) {
+			modReaction += App.Medicine.Modification.setTattoo(slave, tattooLocations.get(location), style, cheat);
+			if (!["flowers", "paternalist", "tribal patterns", 0].includes(style)) {
 				degradation += 1;
 			}
 		}
diff --git a/src/facilities/incubator/incubatorInteract.js b/src/facilities/incubator/incubatorInteract.js
index 35c944eec283e712bf07240f7df69a546ae3e7d1..1194ce6383300821461e2bcfa2cfc72af57761ae 100644
--- a/src/facilities/incubator/incubatorInteract.js
+++ b/src/facilities/incubator/incubatorInteract.js
@@ -772,7 +772,7 @@ App.UI.incubator = function() {
 					} else if (safeCC > 150000) {
 						r.push(`${His} body looks almost spherical, having been grotesquely inflated with the stimulator sacs inserted into ${his} internals. The incubator constantly maintains high pressure inside ${him}, forcing the displacement of ${his} organs and stretching skin, tissues, and muscles. Even ${his} chest has been forced to become a part of the top of ${his} belly, having been pushed forward from the overwhelming volume inside.`);
 					} else if (safeCC > 75000) {
-						r.push(`${His} belly has become so huge that it can be easily compared with belly of a woman ready to birth quintuplets. It pulses from the pressure applied within by the incubator probes.`);
+						r.push(`${His} belly has become so huge that it can be easily be compared with that of a woman ready to birth quintuplets. It pulses from the pressure applied within by the incubator probes.`);
 					} else if (safeCC > 45000) {
 						r.push(`${His} belly, in its current state, would look normal on a woman who was ready to birth triplets. On ${his} still growing form, it's something completely out of the ordinary.`);
 					} else if (safeCC > 30000) {
@@ -931,7 +931,7 @@ App.UI.incubator = function() {
 								)
 							);
 						} else {
-							linkArray.push(App.UI.DOM.makeElement("span", `Ovaries are already prepared.`, "detail"));
+							linkArray.push(App.UI.DOM.makeElement("span", `Ovaries are already prepared.`, ["detail"]));
 						}
 					}
 					if (V.incubator.tanks[i].dick === 0 && (V.seeDicks > 0 || V.makeDicks > 0)) {
@@ -940,14 +940,14 @@ App.UI.incubator = function() {
 								makeLink("Prepare penis", () => { App.Medicine.OrganFarm.growIncubatorOrgan(V.incubator.tanks[i], "penis"); }, refresh)
 							);
 						} else {
-							linkArray.push(App.UI.DOM.makeElement("span", `A penis is already prepared`, "detail"));
+							linkArray.push(App.UI.DOM.makeElement("span", `A penis is already prepared`, ["detail"]));
 						}
 					}
 					if (V.incubator.tanks[i].balls === 0) {
 						if (tankOrgans.testicles !== 1) {
 							linkArray.push(makeLink("Prepare testicles", () => { App.Medicine.OrganFarm.growIncubatorOrgan(V.incubator.tanks[i], "testicles"); }, refresh));
 						} else {
-							linkArray.push(App.UI.DOM.makeElement("span", `Testicles are already prepared.`, "detail"));
+							linkArray.push(App.UI.DOM.makeElement("span", `Testicles are already prepared.`, ["detail"]));
 						}
 					}
 					const vision = {
@@ -1194,7 +1194,7 @@ App.UI.incubator = function() {
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.weight = 0; }, refresh));
 			}
-			section.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(" ", App.UI.DOM.generateLinksStrip(linkArray));
 		} else {
 			const cost = Math.trunc(20000 * V.upgradeMultiplierArcology);
 			section.append(`There are no systems in place to control a growing child's weight; they will likely come out emaciated from the rapid growth.`);
@@ -1238,7 +1238,7 @@ App.UI.incubator = function() {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.muscles = 0; }, refresh));
 			}
 
-			section.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(" ", App.UI.DOM.generateLinksStrip(linkArray));
 		} else {
 			const cost = Math.trunc(20000 * V.upgradeMultiplierArcology);
 			section.append(`There are no systems in place to control a growing child's musculature; they will likely come out frail and weak from the rapid growth.`);
@@ -1281,7 +1281,7 @@ App.UI.incubator = function() {
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.reproduction = 0; }, refresh));
 			}
-			section.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(" ", App.UI.DOM.generateLinksStrip(linkArray));
 			div.append(section);
 			el.append(div);
 
@@ -1313,7 +1313,7 @@ App.UI.incubator = function() {
 				} else {
 					linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.pregAdaptation = 0; }, refresh));
 				}
-				section.append(App.UI.DOM.generateLinksStrip(linkArray));
+				section.append(" ", App.UI.DOM.generateLinksStrip(linkArray));
 
 				if (V.incubator.upgrade.pregAdaptation === 1 && V.incubator.setting.pregAdaptation > 0) {
 					// Should be visible only after incubator.upgrade.reproduction is installed and turned on
@@ -1343,7 +1343,7 @@ App.UI.incubator = function() {
 					} else {
 						linkArray.push(makeLink(`Standard`, () => { V.incubator.setting.pregAdaptationPower = 0; }, refresh));
 					}
-					section.append(App.UI.DOM.generateLinksStrip(linkArray));
+					section.append(" ", App.UI.DOM.generateLinksStrip(linkArray));
 					div.append(section);
 
 					section = document.createElement("div");
diff --git a/src/facilities/penthouse/managePenthouse.js b/src/facilities/penthouse/managePenthouse.js
index 15ff5968be7c5136db8d090faf2e2b1c37fa7f13..90561620fd7536a212559395ec461f64b237a7e3 100644
--- a/src/facilities/penthouse/managePenthouse.js
+++ b/src/facilities/penthouse/managePenthouse.js
@@ -471,12 +471,7 @@ App.UI.managePenthouse = function() {
 		if (V.studio === 0) {
 			r.push(makeLink("Install a media hub to convert slave video feeds into pornography", () => { V.studio = 1; }, 10000));
 		} else {
-			r.push(`The arcology's video systems are connected to a media hub that can convert slave video feeds into pornography.`);
-			if (V.studioFeed === 0) {
-				r.push(makeLink("Upgrade the media hub to allow better control of pornographic content", () => { V.studioFeed = 1; }, 15000));
-			} else {
-				r.push(`It has been upgraded to allow superior control of a slave's pornographic content.`);
-			}
+			r.push(`The arcology's video systems are connected to a`, App.UI.DOM.passageLink("media hub", "Media Studio"), `that can convert slave video feeds into pornography.`);
 		}
 		App.Events.addNode(el, r, "div");
 
diff --git a/src/facilities/pit/pitFramework.js b/src/facilities/pit/pitFramework.js
index a12fec5369e9f943ef387a3473d7e06a9d9264a4..ed2ca4086d586fd6e6cd7af89efccfe478c3f571 100644
--- a/src/facilities/pit/pitFramework.js
+++ b/src/facilities/pit/pitFramework.js
@@ -32,6 +32,12 @@ App.Entity.Facilities.PitFighterJob = class extends App.Entity.Facilities.Facili
 		if ((slave.indentureRestrictions > 0) && (this.facility.option("lethal"))) {
 			r.push(`${slave.slaveName}'s indenture forbids lethal fights.`);
 		}
+		if (!canWalk(slave)) {
+			r.push(`${slave.slaveName} cannot walk independently.`);
+		}
+		if (!canHold(slave)) {
+			r.push(`${slave.slaveName} is unable to strike their opponent.`);
+		}
 		return r;
 	}
 
diff --git a/src/facilities/studio/studio.js b/src/facilities/studio/studio.js
new file mode 100644
index 0000000000000000000000000000000000000000..b767057814f8cf5db19fa8ef6f16765de4a2ab4a
--- /dev/null
+++ b/src/facilities/studio/studio.js
@@ -0,0 +1,130 @@
+App.UI.mediaStudio = function() {
+	const t = new DocumentFragment();
+	const r = new SpacedTextAccumulator(t);
+
+	r.push(`The media hub is a small room wired in to almost every camera in ${V.arcologies[0].name}. From here, you and your personal assistant can edit, produce, and distribute pornography featuring your slaves going about their daily lives.`);
+	r.toNode("p", ["note"]);
+
+	if (V.studioFeed === 0) {
+		r.push(makePurchase("Upgrade the media hub to allow better control of pornographic content", 15000, "capEx", {
+			handler: () => { V.studioFeed = 1; },
+			refresh: () => App.UI.reload()
+		}));
+	} else {
+		r.push(`It has been upgraded to allow superior control of a slave's pornographic content.`);
+	}
+	r.toParagraph();
+
+	if (V.PC.career === "escort" || V.PC.career === "prostitute" || V.PC.career === "child prostitute") {
+		if (V.PC.career === "escort") {
+			r.push(`You retain some contacts from your past life in the industry that may be willing to cut you some discounts on promotion costs, should you return to it.`);
+		} else {
+			r.push(`You were approached in the past to star in some adult films and they may be willing to cut you some discounts on promotion costs, should you accept their offer.`);
+		}
+		if (V.PCSlutContacts !== 2) {
+			r.push(`You are not baring your body for all to see.`);
+			r.push(
+				App.UI.DOM.link(
+					`Star in porn for a discount`,
+					() => {
+						V.PCSlutContacts = 2;
+						App.UI.reload();
+					}
+				)
+			);
+		} else {
+			if (V.PC.career === "escort") {
+				r.push(`You are starring in hardcore porn once more.`);
+			} else if (V.PC.actualAge < V.minimumSlaveAge) {
+				r.push(`You are taking part in porn that may disturb people.`);
+			} else {
+				r.push(`You are starring in some hardcore porn.`);
+			}
+			r.push(
+				App.UI.DOM.link(
+					`Stop doing porn for a discount`,
+					() => {
+						V.PCSlutContacts = 1;
+						App.UI.reload();
+					}
+				)
+			);
+		}
+		r.toParagraph();
+	}
+
+	/** @param {App.Entity.SlaveState} slave */
+	function slavePornSummary(slave) {
+		const res = new DocumentFragment();
+
+		if (V.slavePanelStyle === 0) {
+			res.appendChild(document.createElement("br"));
+		} else if (V.slavePanelStyle === 1) {
+			const hr = document.createElement("hr");
+			hr.style.margin = "0";
+			res.appendChild(hr);
+		}
+
+		if (batchRenderer && (!V.seeCustomImagesOnly || (V.seeCustomImagesOnly && slave.custom.image))) {
+			let imgDiv = document.createElement("div");
+			imgDiv.classList.add("imageRef", "smlImg", "margin-right");
+			imgDiv.appendChild(batchRenderer.render(slave));
+			res.appendChild(imgDiv);
+		}
+
+		const r = new SpacedTextAccumulator(res);
+		r.push(App.UI.DOM.link(SlaveFullName(slave), () => { V.AS = slave.ID; }, [], "Slave Interact"));
+		if (slave.porn.feed) {
+			r.push("is making porn.");
+		} else {
+			r.push("is");
+			r.push(App.UI.DOM.makeElement("span", "not making porn.", ["red"]));
+		}
+		const f2 = new DocumentFragment();
+		App.UI.SlaveSummaryImpl.bits.long.porn_prestige(slave, f2); // why do these bits not just return the element?
+		App.UI.SlaveSummaryImpl.bits.long.face(slave, f2);
+		r.push(f2);
+		if (V.studioFeed && slave.porn.feed) {
+			if (slave.porn.focus === "none") {
+				r.push("Guided by viewers.");
+			} else {
+				const genre = App.Porn.getGenreByFocusName(slave.porn.focus);
+				r.push("Focused on");
+				r.push(App.UI.DOM.makeElement("span", `${genre.focusName}`, ["genre", genre.type.name]));
+				r.push("porn.");
+			}
+		}
+		if (slave.porn.spending > 0) {
+			r.push("Spending", App.UI.DOM.cashFormat(slave.porn.spending), "on promotion.");
+		}
+		r.toNode("div");
+
+		res.append(App.Porn.makeFameProgressChart(slave));
+		res.append(App.Porn.makeViewershipChart(slave));
+
+		return res;
+	}
+
+	// just dump them all into one giant list for now.  TODO: sorting and filtering might come later?
+	const slaves = V.slaves;
+	let batchRenderer = null;
+	if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) {
+		batchRenderer = new App.Art.SlaveArtBatch(slaves.map(s => s.ID), 1);
+		t.appendChild(batchRenderer.writePreamble());
+	} else {
+		batchRenderer = null;
+	}
+
+	for (const slave of slaves) {
+		let slaveDiv = document.createElement("div");
+		slaveDiv.id = `slave-${slave.ID}`;
+		slaveDiv.classList.add("slaveSummary");
+		if (V.slavePanelStyle === 2) {
+			slaveDiv.classList.add("card");
+		}
+		slaveDiv.appendChild(slavePornSummary(slave));
+		t.append(slaveDiv);
+	}
+
+	return t;
+};
diff --git a/src/facilities/studio/studioCharts.js b/src/facilities/studio/studioCharts.js
new file mode 100644
index 0000000000000000000000000000000000000000..84511ceb98ed803570c7f9a31e85cbdf8d7e37c2
--- /dev/null
+++ b/src/facilities/studio/studioCharts.js
@@ -0,0 +1,158 @@
+/** Make a bar chart showing the slave's progress towards the next/previous level of porn fame in her chosen genre.
+ * @param {App.Entity.SlaveState} slave
+ */
+App.Porn.makeFameProgressChart = function(slave) {
+	const container = document.createElement("div");
+	const genre = App.Porn.getGenreByFameName(slave.porn.fameType);
+	const fameVal = slave.porn.prestige > 0 ? slave.porn.fame[genre.fameVar] : slave.porn.viewerCount;
+
+	if (slave.porn.prestige === 3) {
+		container.append("Worldwide fame reached.");
+	} else {
+		if (slave.porn.prestige === 0) {
+			container.append(App.UI.DOM.makeElement("div", `Fame progress (total viewership):`));
+		} else {
+			container.append(App.UI.DOM.makeElement("div", `Fame progress (in ${genre.fameName} porn): `));
+		}
+		// ranges
+		let bottomThreshold = 0;
+		let nextThreshold = 100000;
+		if (slave.porn.prestige === 2) {
+			bottomThreshold = 40000;
+			nextThreshold = V.pornStars[genre.fameVar].p3ID === 0 ? 150000 : 0;
+		} else if (slave.porn.prestige === 1) {
+			bottomThreshold = 5000;
+			nextThreshold = 50000;
+		}
+		const maxVal = (nextThreshold ? nextThreshold : 150000) * 1.1;
+		const curVal = Math.min(fameVal, nextThreshold * 1.1);
+
+		// container
+		const margin = {top: 10, right: 30, bottom: 30, left: 90},
+			width = 600 - margin.left - margin.right,
+			height = 60 - margin.top - margin.bottom;
+		const svg = d3.select(container)
+			.append("svg")
+			.attr("width", width + margin.left + margin.right)
+			.attr("height", height + margin.top + margin.bottom);
+
+		// X axis
+		const x = d3.scaleLinear()
+			.domain([0, maxVal])
+			.range([0, width]);
+		svg.append("g")
+			.attr("transform", `translate(0, ${height})`)
+			.call(d3.axisBottom(x))
+			.selectAll("text")
+				.attr("transform", "translate(-10,0)rotate(-45)")
+				.style("text-anchor", "end");
+
+		// Y axis (invisible)
+		const y = d3.scaleBand()
+			.range([ 0, height ])
+			.domain([""])
+
+		// Bar
+		svg.selectAll("myRect")
+			.data([curVal])
+			.join("rect")
+			.attr("x", x(0))
+			.attr("y", y(""))
+			.attr("width", d => x(d))
+			.attr("height", y.bandwidth())
+			.attr("fill", "var(--link-color)")
+
+		// downgrade threshold
+		if (bottomThreshold > 0) {
+			svg.append("line")
+				.attr("x1", x(bottomThreshold))
+				.attr("x2", x(bottomThreshold))
+				.attr("y1", 0)
+				.attr("y2", height)
+				.attr("stroke-width", 2)
+				.attr("stroke", "red")
+		}
+
+		// upgrade threshold
+		if (nextThreshold > 0) {
+			svg.append("line")
+				.attr("x1", x(nextThreshold))
+				.attr("x2", x(nextThreshold))
+				.attr("y1", 0)
+				.attr("y2", height)
+				.attr("stroke-width", 2)
+				.attr("stroke", "green")
+		}
+	}
+
+	if (slave.porn.prestige === 2 && V.pornStars[genre.fameVar].p3ID !== 0) {
+		container.append(App.UI.DOM.makeElement("div", "You already have another slave with worldwide fame in this genre.", ["note"]));
+	}	
+	return container;
+};
+
+/** Make a treemap chart showing the slave's current viewership distribution among the porn genres.
+ * @param {App.Entity.SlaveState} slave
+ */
+App.Porn.makeViewershipChart = function(slave) {
+	const container = document.createElement("div");
+
+	const data = {name: "Total viewership", children: []};
+	for (const type of Object.values(App.Porn.GenreType)) {
+		const child = {name: type, children: []};
+		for (const genre of App.Porn.getGenresByType(type)) {
+			if (slave.porn.fame[genre.fameVar] > 0) {
+				child.children.push({name: genre.fameName, value: Math.trunc(slave.porn.fame[genre.fameVar]), type: type.name});
+			}
+		}
+		if (child.children.length > 0) {
+			data.children.push(child);
+		}
+	}
+	const root = d3.hierarchy(data)
+		.sum(d => +d.value)
+		.sort((a,b) => d3.descending(a.value, b.value));
+	
+	// container size
+	const margin = {top: 10, right: 10, bottom: 10, left: 10},
+		width = 600 - margin.left - margin.right,
+		height = 200 - margin.top - margin.bottom;
+
+	// treemap construction
+	const layout = d3.treemap()
+		.size([width - margin.left - margin.right, height - margin.top - margin.bottom])
+		.padding(1)
+		(root);
+
+	const svg = d3.select(container)
+		.append("svg")
+		.attr("width", width + margin.left + margin.right)
+		.attr("height", height + margin.top + margin.bottom)
+		.append("g")
+		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+	// rectangles
+	svg.selectAll("rect")
+		.data(layout.leaves())
+		.join("rect")
+			.attr('x', d => d.x0)
+			.attr('y', d => d.y0)
+			.attr('width', d => d.x1 - d.x0)
+			.attr('height', d => d.y1 - d.y0)
+			.style("fill", d => `var(--genre-color-${d.data.type})`)
+			.attr("data-tippy-content", d => `${d.data.name} (${d.data.value})`)
+			// @ts-ignore - can't specify generic arguments from JS, but the right one will be picked
+			.call(x => tippy(x.nodes()));
+
+	// text labels
+	svg.selectAll("text")
+		.data(layout.leaves())
+    	.join("text")
+			.attr("x", d => d.x0 + 5)
+			.attr("y", d => d.y0 + 15)
+			.text(d => d.data.name)
+			.attr("font-size", "15px")
+			.attr("fill", "black")
+
+	return container;	
+};
diff --git a/src/facilities/surgery/analyzePregnancy.js b/src/facilities/surgery/analyzePregnancy.js
index dae95df153d4c2d28c63ec751e23c331b963084a..7ed19d59c5e90f27c505f4de9a465aa26f53a063 100644
--- a/src/facilities/surgery/analyzePregnancy.js
+++ b/src/facilities/surgery/analyzePregnancy.js
@@ -108,6 +108,13 @@ globalThis.analyzePregnancies = function(mother, cheat) {
 				} else {
 					el.append(fetusAbnormalities());
 				}
+				if(V.inbreeding && genes.inbreedingCoeff!==undefined)
+				{							
+					option = options.addOption(`Inbreeding coefficient: ${genes.inbreedingCoeff}`, "inbreedingCoeff", genes);
+					if (cheat) {
+						option.showTextBox();
+					}
+				}			
 			} else {
 				if (fetus.age > 13) {
 					App.UI.DOM.appendNewElement("div", el, `Gender: ${genes.gender}`);
diff --git a/src/facilities/surgery/surgeryPassageExotic.js b/src/facilities/surgery/surgeryPassageExotic.js
index a2f853ad513d1ee847d05fc7f5f68477edcc51f7..1019cc5f480cc44e769349a99d4ca533ad877b74 100644
--- a/src/facilities/surgery/surgeryPassageExotic.js
+++ b/src/facilities/surgery/surgeryPassageExotic.js
@@ -189,7 +189,7 @@ App.UI.surgeryPassageExotic = function(slave, refresh, cheat = false) {
 			if (slave.milkFlavor === "natural") {
 				title = `${His} milk is natural.`;
 			} else {
-				title = `${His} milk is ${slave.milkFlavor} flavored.`;
+				title = `${His} milk is ${slave.milkFlavor}-flavored.`;
 			}
 			App.UI.DOM.appendNewElement("div", el, title);
 
diff --git a/src/facilities/surgery/surgeryPassageUpper.js b/src/facilities/surgery/surgeryPassageUpper.js
index 811c0249da2e76a40fab53a3ada312314ba23a07..7edd8e9fcace77b4b824638fa8c16d6e894c70cb 100644
--- a/src/facilities/surgery/surgeryPassageUpper.js
+++ b/src/facilities/surgery/surgeryPassageUpper.js
@@ -407,7 +407,7 @@ App.UI.surgeryPassageUpper = function(slave, refresh, cheat = false) {
 				r.push(`showing unusual discomfort as ${his} stomach is inspected. A quick test reveals that <span class="lime">${he} is pregnant.</span>`);
 				slave.pregKnown = 1;
 			} else if (slave.bellyImplant > 0) {
-				r.push(`got a ${slave.bellyImplant}cc implant filled implant located in ${his} abdomen.`);
+				r.push(`got a ${slave.bellyImplant}cc fluid-filled implant located in ${his} abdomen.`);
 				if (slave.cervixImplant === 1) {
 					r.push(`${He} also has a micropump filter installed in ${his} cervix feeding into the implant.`);
 				} else if (slave.cervixImplant === 2) {
diff --git a/src/facilities/wardrobe/wardrobeShopping.js b/src/facilities/wardrobe/wardrobeShopping.js
index d6bd9c1caeb1473ba0a37de14341de06a3bd6fec..54bc1a170c8067f0d45588f0174ef9d045c2d373 100644
--- a/src/facilities/wardrobe/wardrobeShopping.js
+++ b/src/facilities/wardrobe/wardrobeShopping.js
@@ -133,7 +133,7 @@ App.UI.WardrobeShopping = function() {
 							}
 						)
 					);
-					App.UI.DOM.appendNewElement("div", el, ` Costs ${cashFormat(cost)}`, "detail");
+					App.UI.DOM.appendNewElement("div", el, ` Costs ${cashFormat(cost)}`, ["detail"]);
 				} else {
 					div = App.UI.DOM.disabledLink(
 						`Order ${clothingObj.title}`,
@@ -189,7 +189,7 @@ App.UI.WardrobeShopping = function() {
 						)
 					);
 					if (cost > 0) {
-						App.UI.DOM.appendNewElement("span", div, ` Costs ${cashFormat(cost)}`, "detail");
+						App.UI.DOM.appendNewElement("span", div, ` Costs ${cashFormat(cost)}`, ["detail"]);
 					}
 				} else {
 					div.append(
diff --git a/src/futureSocieties/aztec/slaveSacrificePenance.js b/src/futureSocieties/aztec/slaveSacrificePenance.js
index 6827ed922e8c1d137cbffc6bb194373d2e866a80..3db3c2c282d271adf03f41f1b23dfe6d322dd7ab 100644
--- a/src/futureSocieties/aztec/slaveSacrificePenance.js
+++ b/src/futureSocieties/aztec/slaveSacrificePenance.js
@@ -406,7 +406,7 @@ App.UI.SlaveInteract.aztecSlaveSacrificePenance = function(sacrifice) {
 				} else {
 					r.push(`lower body`);
 				}
-				r.push(`constantly cleaned when it becomes apparent they are wet to avoid any evidence of pleasure. ${He} tries to make it more difficult as now it is the only thing ${he} has to fantasize on cumming. At the end of the week is often common to see ${him} beg to be touched by anyone who is close enough to hear ${him} and bursts into tears when ${he} is blatantly ignored. As a result of all this crying, the lack of food and sleep ${he} needs to be hydrated more often also the dose of aphrodisiacs is changed to be less potent but be injected more often to avoid the danger that ${he} might cum from it. ${His} body refuses to lose anymore more liquids, a fact that doesn't stop ${him} from sobbing and begging to be touched as soon as ${he} finds the strength to it while ${he} remains almost immobile on the bottom of the cage, interrupted by the spasms of ${his} body as a result of being constantly aroused for a week.`);
+				r.push(`constantly cleaned when it becomes apparent they are wet to avoid any evidence of pleasure. ${He} tries to make it more difficult as now it is the only thing ${he} has to fantasize on cumming. At the end of the week is often common to see ${him} beg to be touched by anyone who is close enough to hear ${him} and bursts into tears when ${he} is blatantly ignored. As a result of all this crying, the lack of food and sleep ${he} needs to be hydrated more often also the dose of aphrodisiacs is changed to be less potent but be injected more often to avoid the danger that ${he} might cum from it. ${His} body refuses to lose any more liquids, a fact that doesn't stop ${him} from sobbing and begging to be touched as soon as ${he} finds the strength to it while ${he} remains almost immobile on the bottom of the cage, interrupted by the spasms of ${his} body as a result of being constantly aroused for a week.`);
 			} else if (sacrifice.fetish === "humiliation") {
 				r.push(`${He} seems to enjoy all the attention ${he} receives every time ${he} tries to fight the impulse to touch ${himself} as ${his} body shows clear signs of arousal and takes special care in showing just how degrading the whole process can be. It's common to see ${him} enjoying every time the dose of aphrodisiacs needs to be injected again or when ${he} needs to be awaken. Often, ${he} refuses to drink the tea provided, hoping that when the moment comes ${he} will be forced to drink it — preferably in a very humiliating way. As the week progresses and ${his} need to cum increases ${he} focuses on the humiliation ${he} gets every time the aphrodisiacs get the best of ${him} and tries to find release and fails as the citizens passing by throw insults and disgusted looks on ${his} direction for failing in trying to please the goddess. As a result, ${he} is immobilized and blindfolded in an attempt to reduce external stimulation. By the end of the week ${he} cannot stand up and remains on the bottom of the cage, saving ${his} strength to procure making the procedures as humiliating as possible with the little strength ${he} has saved.`);
 			} else if (sacrifice.fetish === "buttslut") {
diff --git a/src/futureSocieties/fsDecoration.js b/src/futureSocieties/fsDecoration.js
index 88681cef66b82e451ad85acf79c59b1ab410c810..323cb9744ebbb137af4ccefb6b911a211c5eeb68 100644
--- a/src/futureSocieties/fsDecoration.js
+++ b/src/futureSocieties/fsDecoration.js
@@ -148,7 +148,6 @@ App.UI.FSChangeDecoration = function(FS, items = []) {
 						makePurchase(`Customize the exterior of the arcology to support this goal`, costs, "capEx", {
 							handler: () => {
 								V.arcologies[0][FSDecoration] = 100;
-								cashX(forceNeg(costs), "capEx");
 								for (const item of items) {
 									_.set(V, item, 1);
 								}
diff --git a/src/futureSocieties/fsPassage.js b/src/futureSocieties/fsPassage.js
index a9c23ed21eb8fb66c293ea386883dfdb6f9d3070..a80ecb9a5ce46be04ba04cc1bdb042aa230a7ae6 100644
--- a/src/futureSocieties/fsPassage.js
+++ b/src/futureSocieties/fsPassage.js
@@ -342,6 +342,72 @@ App.UI.fsPassage = function() {
 		}
 	}
 
+	/** Test what new social effects you'd get if a new FS were added
+	 *  This is a good proxy for evaluating whether you'll be able to make it stick or not
+	 * @param {FC.FutureSociety} proposedFS
+	 */
+	function evaluation(proposedFS) {
+		const effectCounts = new Map();
+		for (const slave of App.SlaveAssignment.reportSlaves(V.slaves)) {
+			const slaveEffects = App.SlaveAssignment.saSocialEffects(slave).newForFS(proposedFS);
+			for (const effect of slaveEffects) {
+				const curVal = effectCounts.get(effect.shortDesc);
+				if (curVal) {
+					effectCounts.set(effect.shortDesc, curVal + effect.magnitude);
+				} else {
+					effectCounts.set(effect.shortDesc, effect.magnitude);
+				}
+			}
+		}
+
+		const grid = document.createElement("div");
+		grid.classList.add("grid-2columns-auto");
+		let avg = 0;
+		for (const [key, count] of effectCounts) {
+			const className = count < 0 ? "red" : "green";
+			App.UI.DOM.appendNewElement("div", grid, count.toString(), [className]);
+			App.UI.DOM.appendNewElement("div", grid, key);
+			avg += count;
+		}
+		avg /= V.slaves.length;
+
+		const tip = document.createElement('div');
+		tip.classList.add("tip-details");
+		if (avg > 1.5) {
+			tip.appendChild(document.createTextNode(`Adopting ${FutureSocieties.displayName(proposedFS)} is likely to be straightforward, even against social pressure from your neighbors. Your arcology is already primed to move this direction thanks to your actions, and your slaves are well-aligned with it.`));
+		} else if (avg > 0.5) {
+			tip.appendChild(document.createTextNode(`Adopting ${FutureSocieties.displayName(proposedFS)} should be relatively painless. Your arcology is already receptive to moving this direction thanks to your actions, and your slaves are aligned with it.`));
+		} else if (avg > -0.1) {
+			tip.appendChild(document.createTextNode(`Adopting ${FutureSocieties.displayName(proposedFS)} will require investment and effort. Your arcology is not opposed to moving this direction, but it's also not expecting it based on your past actions. To improve your chances, consider first aligning your slaves with ${FutureSocieties.displayAdj(proposedFS)} goals.`));
+		} else {
+			tip.appendChild(document.createTextNode(`Attempting to adopt ${FutureSocieties.displayName(proposedFS)} with your arcology in its current state will likely result in failure. You should strongly consider aligning your slaves with ${FutureSocieties.displayAdj(proposedFS)} goals before endorsing it.`));
+		}
+		tip.append(grid);
+
+		const span = document.createElement("span");
+		span.classList.add("fs-recommend");
+		if (avg > 1.5) {
+			span.textContent = "Primed";
+			span.classList.add("fs-recommend-great");
+		} else if (avg > 0.5) {
+			span.textContent = "Receptive";
+			span.classList.add("fs-recommend-good");
+		} else if (avg > -0.1) {
+			span.textContent = "Neutral";
+			span.classList.add("fs-recommend-neutral");
+		} else {
+			span.textContent = "Resistant";
+			span.classList.add("fs-recommend-bad");
+		}
+		span.tabIndex = 0;
+		span.classList.add("has-tooltip");
+		tippy(span, {
+			content: tip,
+			placement: "right",
+		});
+		return span;
+	}
+
 	function selectFS() {
 		const el = new DocumentFragment();
 		let r;
@@ -380,6 +446,7 @@ App.UI.fsPassage = function() {
 					arc.FSSupremacistRace = /** @type {FC.Race} */ (race);
 					App.UI.reload();
 				}));
+				r.push(evaluation("FSSupremacist"));
 			} else {
 				/* <span class="note"><span style="font-weight:Bold">Racial Supremacism:</span> a belief in the superiority of a chosen race.</span>*/
 			}
@@ -408,15 +475,15 @@ App.UI.fsPassage = function() {
 					r.push(`${arc.FSSubjugationistRace} inferiority.`);
 				}
 				r.push(`Select race:`);
-
 				const options = [];
 				for (const race of App.Utils.getRaceArrayWithoutParamRace(arc.FSSupremacistRace)) { // Superior race cannot be subj, so remove
 					options.push({key: race, name: capFirstChar(race)});
 				}
 				r.push(App.UI.DOM.makeSelect(options, arc.FSSubjugationistRace, race => {
-					arc.FSSubjugationistRace = race;
+					arc.FSSubjugationistRace = /** @type {FC.Race} */ (race);
 					App.UI.reload();
 				}));
+				r.push(evaluation("FSSubjugationist"));
 			} else {
 				/* <span class="note"><span style="font-weight:Bold">Racial Subjugationism:</span> a belief in the inferiority of a subject race.</span>*/
 			}
@@ -447,6 +514,7 @@ App.UI.fsPassage = function() {
 							)
 						);
 						r.push(`is a focus on mass breeding in order to repopulate the future world.`);
+						r.push(evaluation("FSRepopulationFocus"));
 					} else {
 						/* <span class="note"><span style="font-weight:Bold">Repopulation Efforts:</span> societal fetishization of pregnancy.</span>*/
 					}
@@ -480,6 +548,7 @@ App.UI.fsPassage = function() {
 							)
 						);
 						r.push(`is rebuilding society using restrictive breeding programs reserved solely for society's finest.`);
+						r.push(evaluation("FSRestart"));
 					} else {
 						/* <span class="note"><span style="font-weight:Bold">Complete Societal Reconstruction:</span> rebuilding society based off the elite.</span>*/
 					}
@@ -509,6 +578,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a belief that slaves should be airheaded, horny and fully dependent on their owners.`);
+					r.push(evaluation("FSIntellectualDependency"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Intellectual Dependency:</span> a belief that slaves should be airheaded, horny and fully dependent on their owners.</span>*/
 				}
@@ -533,6 +603,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is increased interest in smart, refined, altogether perfect slaves.`);
+					r.push(evaluation("FSSlaveProfessionalism"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Slave Professionalism:</span> increased interest in smart, refined, altogether perfect slaves.</span>*/
 				}
@@ -562,6 +633,7 @@ App.UI.fsPassage = function() {
 							)
 						);
 						r.push(`is a radical redefinition of gender that identifies powerful people as male, and everyone else as female.`);
+						r.push(evaluation("FSGenderRadicalist"));
 					} else {
 						/* <span class="note"><span style="font-weight:Bold">Gender radicalism:</span> a radical redefinition of gender that identifies powerful people as male, and everyone else as female.</span>*/
 					}
@@ -587,6 +659,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`gender traditionalism, including a societal preference for feminine slaves ${(V.seePreg !== 0) ? ` and support for slave pregnancy` : ``}.`);
+					r.push(evaluation("FSGenderFundamentalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Gender traditionalism:</span> a societal preference for feminine slaves
 						if (V.seePreg !== 0) {
@@ -619,6 +692,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of slave improvement, including slaves' health, mental well-being, and education.`);
+					r.push(evaluation("FSPaternalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Paternalism:</span> a vision of slave improvement, including slaves' health, mental well-being, and education.</span>*/
 				}
@@ -643,6 +717,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a belief that slaves are not human and should not be treated decently.`);
+					r.push(evaluation("FSDegradationist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Degradation:</span> a belief that slaves are not human and should not be treated decently.</span>*/
 				}
@@ -671,6 +746,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal disapproval of implant surgery.`);
+					r.push(evaluation("FSBodyPurist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Body Purism:</span> societal disapproval of implant surgery.</span>*/
 				}
@@ -695,6 +771,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal fetishization of implant surgery.`);
+					r.push(evaluation("FSTransformationFetishist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Transformation Fetishism:</span> societal fetishization of implant surgery.</span>*/
 				}
@@ -732,6 +809,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is increased interest in girls just past their majority.`);
+					r.push(evaluation("FSYouthPreferentialist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Youth Preferentialism:</span> increased interest in girls just past their majority.</span>*/
 				}
@@ -763,6 +841,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is increased interest in mature slaves.`);
+					r.push(evaluation("FSMaturityPreferentialist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Maturity Preferentialism:</span> increased interest in mature slaves.</span>*/
 				}
@@ -791,6 +870,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is increased interest in short slaves.`);
+					r.push(evaluation("FSPetiteAdmiration"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Petite Admiration:</span> increased interest in short slaves.</span>*/
 				}
@@ -815,6 +895,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal fixation on tallness.`);
+					r.push(evaluation("FSStatuesqueGlorification"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Statuesque Glorification:</span> societal fixation on tallness.</span>*/
 				}
@@ -843,6 +924,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a fashion for slaves with girlish figures.`);
+					r.push(evaluation("FSSlimnessEnthusiast"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Slimness Enthusiasm:</span> a fashion for slaves with girlish figures.</span>*/
 				}
@@ -867,6 +949,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal hunger for huge assets of whatever origin.`);
+					r.push(evaluation("FSAssetExpansionist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Asset Expansionism:</span> societal hunger for huge assets of whatever origin.</span>*/
 				}
@@ -893,6 +976,7 @@ App.UI.fsPassage = function() {
 					)
 				);
 				r.push(`is societal acceptance of slave products like milk.`);
+				r.push(evaluation("FSPastoralist"));
 			} else {
 				/* <span class="note"><span style="font-weight:Bold">Slave Pastoralism:</span> societal acceptance of slave products like milk.</span>*/
 			}
@@ -919,6 +1003,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal reverence for the idealized human form, including height, health and muscle.`);
+					r.push(evaluation("FSPhysicalIdealist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Physical Idealism:</span> societal reverence for the idealized human form, including height, health and muscle.</span>*/
 				}
@@ -943,6 +1028,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is societal acceptance of overindulgence and immediate gratification. Be it food, drink, sex, drugs or whatever one's desire may be.`);
+					r.push(evaluation("FSHedonisticDecadence"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">HedonisticDecadence:</span> societal acceptance of over indulgence, particularly of food, drink, sex and drugs.</span>*/
 				}
@@ -971,6 +1057,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a new strain of religion that emphasizes the slaveholding portions of religious history.`);
+					r.push(evaluation("FSChattelReligionist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Chattel Religionism:</span> a new strain of religion that emphasizes the slaveholding portions of religious history.</span>*/
 				}
@@ -1142,6 +1229,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of a new Rome.`);
+					r.push(evaluation("FSRomanRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Roman Revivalism:</span> a vision of a new Rome.</span>*/
 				}
@@ -1166,6 +1254,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of a new Imperial society, integrating high technology and old-world culture under the iron fist of your absolute rule.`);
+					r.push(evaluation("FSNeoImperialist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Neo-Imperialism:</span> a vision of a new Imperial Society, integrating high technology and old-world culture under the iron fist of your absolute rule.</span>*/
 				}
@@ -1190,6 +1279,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of a new Aztec Empire.`);
+					r.push(evaluation("FSAztecRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Aztec Revivalism:</span> a vision of a new Aztec Empire.</span>*/
 				}
@@ -1215,6 +1305,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of a Pharaoh's Egypt.`);
+					r.push(evaluation("FSEgyptianRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Egyptian Revivalism:</span> a vision of Pharaoh's Egypt.</span>*/
 				}
@@ -1239,6 +1330,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of Edo Japan.`);
+					r.push(evaluation("FSEdoRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Edo Revivalism:</span> a vision of Edo Japan.</span>*/
 				}
@@ -1263,6 +1355,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of the Sultanate of old.`);
+					r.push(evaluation("FSArabianRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Arabian Revivalism:</span> a vision of the Sultanate of old.</span>*/
 				}
@@ -1287,6 +1380,7 @@ App.UI.fsPassage = function() {
 						)
 					);
 					r.push(`is a vision of ancient China.`);
+					r.push(evaluation("FSChineseRevivalist"));
 				} else {
 					/* <span class="note"><span style="font-weight:Bold">Chinese Revivalism:</span> a vision of ancient China.</span>*/
 				}
diff --git a/src/futureSocieties/futureSociety.js b/src/futureSocieties/futureSociety.js
index ac1d705d18aaa75f5a8329f844ec1c08593183d4..e9f299f9ac5afcda44ba2e1fb856cdcc1b2e7132 100644
--- a/src/futureSocieties/futureSociety.js
+++ b/src/futureSocieties/futureSociety.js
@@ -297,6 +297,11 @@ globalThis.FutureSocieties = (function() {
 			case "FSAssetExpansionist":
 				arcology[FSSMR] = 0;
 				break;
+			case "FSSlimnessEnthusiast":
+				arcology.FSSlimnessEnthusiastLaw = 0;
+				arcology.FSSlimnessEnthusiastFoodLaw = 0;
+				arcology.FSSlimnessEnthusiastSMR = 0;
+				break;
 			case "FSPhysicalIdealist":
 				arcology.FSPhysicalIdealistLaw = 0;
 				arcology.FSPhysicalIdealistSMR = 0;
diff --git a/src/gui/Encyclopedia/encyclopedia.tw b/src/gui/Encyclopedia/encyclopedia.tw
index c640cdd55ac6460a3df0d4e2c7c32608d8c52e90..a2eaaff662e05a48208302a3d10e7c9257a157c7 100644
--- a/src/gui/Encyclopedia/encyclopedia.tw
+++ b/src/gui/Encyclopedia/encyclopedia.tw
@@ -47,7 +47,7 @@ $encyclopedia
 	<br><br>
 	<h3>Extras</h3>
 		<<= App.Encyclopedia.Dialog.linkSC("Game Mods", "Game Mods")>>
-		<br><<= App.Encyclopedia.Dialog.linkSC("Lore")>>
+		<br><<= App.Encyclopedia.Dialog.linkSC("Lore", "Lore")>>
 		<br><<= App.Encyclopedia.Dialog.linkSC("Credits", "Credits")>>
 	</div>
 
@@ -199,88 +199,6 @@ SLAVE FETISHES:
 
 	<br><br>Submissives serving on public sexual assignment may become <<= App.Encyclopedia.Dialog.linkSC("sexually self neglectful", "Self Neglect")>>.
 
-/**********
-SLAVE BEHAVIORAL FLAWS
-**********/
-<<case "Flaws">>
-	''Flaws '' are negative slave qualities. They decrease slaves' value and performance at sexual assignments, and each flaw also has other, differing effects. Each flaw is associated with a corresponding <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>, and slave can have two flaws (a sexual flaw and a behavioral flaw), just like quirks. New slaves will often have flaws, and tough experiences can also cause them to appear.
-
-	<br><br>The <<= App.Encyclopedia.Dialog.linkSC("Head Girl", "Head Girl")>> can be ordered to soften or remove flaws, and the player character can soften or remove flaws with personal attention. Flaws can also be naturally softened or removed by fetishes, and can resolve on their own if a slave is happy.
-
-
-<<case "Anorexic">>
-	''Anorexic '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("insecure", "Insecure")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. In addition to the standard penalties to value and performance on sexual assignments, anorexia can cause unexpected weight loss. Anorexics will enjoy dieting but dislike gaining weight, and may bilk attempts to make them fatten up.
-
-
-<<case "Arrogant">>
-	''Arrogant '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("confident", "Confident")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. The <<= App.Encyclopedia.Dialog.linkSC("submissive", "Submissives")>> fetish can do this naturally. In addition to the standard penalties to value and performance on sexual assignments, arrogance limits weekly @@.hotpink;<<= App.Encyclopedia.Dialog.linkSC("devotion", "From Rebellious to Devoted")>>@@ gains.
-
-
-<<case "Bitchy">>
-	''Bitchy '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("cutting", "Cutting")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. The <<= App.Encyclopedia.Dialog.linkSC("humiliation", "Humiliation Fetishists")>> fetish can do this naturally. In addition to the standard penalties to value and performance on sexual assignments, bitchiness limits weekly @@.hotpink;<<= App.Encyclopedia.Dialog.linkSC("devotion", "From Rebellious to Devoted")>>@@ gains.
-
-
-<<case "Devout">>
-	''Devout '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("sinful", "Sinful")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. A very powerful sex drive can do this naturally. In addition to the standard penalties to value and performance on sexual assignments, being devout limits weekly @@.hotpink;<<= App.Encyclopedia.Dialog.linkSC("devotion", "From Rebellious to Devoted")>>@@ gains.
-
-
-<<case "Gluttonous">>
-	''Gluttonous '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("fitness", "Fitness")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. In addition to the standard penalties to value and performance on sexual assignments, gluttons will enjoy gaining weight but dislike dieting, and may bilk attempts to make them lose weight.
-
-
-<<case "Hates Men">>
-	''Hates men '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("adores women", "Adores women")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("boob fetish", "Boob Fetishists")>>. Strong attraction to men or the <<= App.Encyclopedia.Dialog.linkSC("pregnancy fetish", "Pregnancy Fetishists")>> will soften it so she <<= App.Encyclopedia.Dialog.linkSC("adores men", "Adores men")>> instead. This flaw can also be removed by serving a player character or another slave with a dick.
-
-
-<<case "Hates Women">>
-	''Hates women '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("adores men", "Adores men")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("cumslut", "Cumsluts")>> fetish. Strong attraction to women or the <<= App.Encyclopedia.Dialog.linkSC("pregnancy fetish", "Pregnancy Fetishists")>> will soften it so she <<= App.Encyclopedia.Dialog.linkSC("adores women", "Adores women")>> instead. This flaw can also be removed by serving a player character or another slave with a vagina.
-
-
-<<case "Liberated">>
-	''Liberated '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("advocate", "Advocate")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. The <<= App.Encyclopedia.Dialog.linkSC("submissive", "Submissives")>> fetish can do this naturally. In addition to the standard penalties to value and performance on sexual assignments, being liberated limits weekly @@.hotpink;<<= App.Encyclopedia.Dialog.linkSC("devotion", "From Rebellious to Devoted")>>@@ gains.
-
-
-<<case "Odd">>
-	''Odd '' is a behavioral <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("funny", "Funny")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>>. The <<= App.Encyclopedia.Dialog.linkSC("humiliation", "Humiliation Fetishists")>> fetish can do this naturally. In addition to the standard penalties to value and performance on sexual assignments, being odd limits weekly @@.hotpink;<<= App.Encyclopedia.Dialog.linkSC("devotion", "From Rebellious to Devoted")>>@@ gains.
-
-/**********
-SLAVE SEXUAL FLAWS
-**********/
-<<case "Apathetic">>
-	''Apathetic '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("caring", "Caring")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("submissive", "Humiliation Submissive")>> fetish. It can also be removed by the <<= App.Encyclopedia.Dialog.linkSC("dom", "Doms")>> fetish.
-
-
-<<case "Crude">>
-	''Crude '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("unflinching", "Unflinching")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("buttslut", "Buttsluts")>> fetish.
-
-
-<<case "Hates Anal">>
-	''Hates anal '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("painal queen", "Painal Queen")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("buttslut", "Buttsluts")>> fetish. This flaw can also be removed by serving the player character.
-
-
-<<case "Hates Oral">>
-	''Hates oral '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("gagfuck queen", "Gagfuck Queen")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("cumslut", "Cumsluts")>> fetish. This flaw can also be removed by serving the player character.
-
-
-<<case "Hates Penetration">>
-	''Hates penetration '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("strugglefuck queen", "Strugglefuck Queen")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("buttslut", "Buttsluts")>> fetish. This flaw can also be removed by serving the player character.
-
-
-<<case "Idealistic">>
-	''Idealistic '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("romantic", "Romantic")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("submissive", "Submissives")>> fetish.
-
-
-<<case "Judgemental">>
-	''Judgemental '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the ''<<= App.Encyclopedia.Dialog.linkSC("size queen", "Size Queen")>> '' <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("submissive", "Humiliation Submissive")>> fetish.
-
-
-<<case "Repressed">>
-	''Repressed '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("perverted", "Perverted")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, the <<= App.Encyclopedia.Dialog.linkSC("cumslut", "Cumsluts")>> fetish, or the <<= App.Encyclopedia.Dialog.linkSC("buttslut", "Buttsluts")>> fetish.
-
-
-<<case "Shamefast">>
-	''Shamefast '' is a sexual <<= App.Encyclopedia.Dialog.linkSC("flaw", "Flaws")>> that can be softened into the <<= App.Encyclopedia.Dialog.linkSC("tease", "Tease")>> <<= App.Encyclopedia.Dialog.linkSC("quirk", "Quirks")>> by training, a good <<= App.Encyclopedia.Dialog.linkSC("Attendant", "Attendant")>>, a powerful sex drive, or the <<= App.Encyclopedia.Dialog.linkSC("humiliation", "Humiliation Fetishists")>> fetish.
-
 /**********
 SLAVE PARAPHILIAS
 **********/
diff --git a/src/gui/Encyclopedia/encyclopediaBody.js b/src/gui/Encyclopedia/encyclopediaBody.js
index ac7c2f42412d2c6cf888aa96a1ce73ddaca522c1..6e0b759dece6143a92245849e7c79cfff8febc68 100644
--- a/src/gui/Encyclopedia/encyclopediaBody.js
+++ b/src/gui/Encyclopedia/encyclopediaBody.js
@@ -1,6 +1,6 @@
 App.Encyclopedia.addArticle("Body", function() {
 	const fragment = new DocumentFragment();
-	App.UI.DOM.appendNewElement("p", fragment, "Future room for lore text", "note");
+	App.UI.DOM.appendNewElement("p", fragment, "Future room for lore text", ["note"]);
 	App.UI.DOM.appendNewElement("div", fragment, "Choose a more particular entry below:");
 	return fragment;
 }, "body");
@@ -67,6 +67,20 @@ App.Encyclopedia.addArticle("Breasts", function() {
 	return fragment;
 }, "body");
 
+App.Encyclopedia.addArticle("Butts", function() {
+	return App.UI.DOM.combineNodes(
+		`Slaves' `,
+		App.UI.DOM.makeElement("span", "butts", ["strong"]),
+		` contribute to beauty. They can be enlarged with `,
+		App.Encyclopedia.Dialog.linkDOM("XX hormones", "Hormones (XX)"),
+		`, `,
+		App.Encyclopedia.Dialog.linkDOM("weight gain", "Weight"),
+		`, or surgery (which `,
+		App.Encyclopedia.Dialog.linkDOM("buttsluts", "Buttsluts"),
+		` will be grateful for).`
+	);
+}, "body");
+
 App.Encyclopedia.addArticle("Clits", function() {
 	const fragment = new DocumentFragment();
 	const r = [];
@@ -319,21 +333,12 @@ App.Encyclopedia.addArticle("Skin Distinctions", function() {
 
 App.Encyclopedia.addArticle("Teeth", function() {
 	const fragment = new DocumentFragment();
-	let r = [];
-	r.push(`Slaves'`);
-	r.push(App.Encyclopedia.topic("teeth"));
-	r.push(`have a variety of impacts and can be customized in several ways.`);
-	App.Events.addParagraph(fragment, r);
-	r = [];
+	App.Events.addParagraph(fragment, [`Slaves'`, App.Encyclopedia.topic("teeth"), `have a variety of impacts and can be customized in several ways.`]);
 	for (const [key, teeth] of App.Medicine.Modification.teeth) {
-		if (!teeth.hasOwnProperty("requirements") || teeth.requirements) {
-			r.push(App.UI.DOM.makeElement("span", capFirstChar(key), ["note"]));
-			r.push(teeth.desc);
-			App.Events.addNode(fragment, r, "div");
-			r = [];
+		if (teeth.desc) {
+			App.Events.addNode(fragment, [App.UI.DOM.makeElement("span", capFirstChar(key), ["note"]), teeth.desc], "div");
 		}
 	}
-	App.Events.addParagraph(fragment, r);
 	return fragment;
 }, "body");
 
@@ -354,7 +359,7 @@ App.Encyclopedia.addArticle("Vaginas", function() {
 	r.push(App.Encyclopedia.topic("vaginas"));
 	r.push(`are a valuable commodity. Like `);
 	r.push(App.UI.DOM.combineNodes(
-		App.Encyclopedia.Dialog.linkDOM("anuses", "Anuses"),
+		App.Encyclopedia.Dialog.linkDOM("anuses"),
 		`, they appear in four degrees of tightness: virgin and three increasing levels of looseness. Tighter vaginas improve performance at sexual assignments, but most methods of learning `
 	));
 
diff --git a/src/gui/Encyclopedia/encyclopediaCommonAssignments.js b/src/gui/Encyclopedia/encyclopediaCommonAssignments.js
index e3b538b516650fbce05f45dd6c8721386b4fd453..bcb2b007e9749a6991a648301eb3f4cd083e9dea 100644
--- a/src/gui/Encyclopedia/encyclopediaCommonAssignments.js
+++ b/src/gui/Encyclopedia/encyclopediaCommonAssignments.js
@@ -149,7 +149,7 @@ App.Encyclopedia.addArticle("Slave Assignments", function() {
 	const frag = new DocumentFragment();
 	const r = [];
 	r.push("Slave assignments are stratified into ordinary assignments and");
-	r.push(App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("leadership positions"), "."));
+	r.push(App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("leadership positions", "Leadership Positions"), "."));
 	App.Events.addParagraph(frag, r);
 
 	App.UI.DOM.appendNewElement("p", frag, "Choose a more particular entry below:");
@@ -251,7 +251,7 @@ App.Encyclopedia.addArticle("Rest", function() {
 	return frag;
 }, "assignmentCommon");
 
-App.Encyclopedia.addArticle("Sexual Servitude", App.Encyclopedia.Assignments.servitude, "assignmentCommon");
+App.Encyclopedia.addArticle("Sexual Servitude", App.Encyclopedia.Assignments.sexualServitude, "assignmentCommon");
 
 App.Encyclopedia.addArticle("Servitude", function() {
 	const frag = new DocumentFragment();
diff --git a/src/gui/Encyclopedia/encyclopediaGuide.js b/src/gui/Encyclopedia/encyclopediaGuide.js
index bb79bec90055e80511e6013a2267a9818bdfd783..738a8f113465d4acf5fa6ffa8a38b50285c864d1 100644
--- a/src/gui/Encyclopedia/encyclopediaGuide.js
+++ b/src/gui/Encyclopedia/encyclopediaGuide.js
@@ -421,9 +421,9 @@ App.Encyclopedia.addArticle("Design Your Master", function() {
 			r.push(App.Encyclopedia.Dialog.linkDOM("authority", "Security Expansion", "darkviolet"));
 		}
 		r.push("losses each week. You can spend your free time selling your body for");
-		r.push(App.UI.DOM.makeElement("span", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("money", "Money"), ","), "cash"));
+		r.push(App.Encyclopedia.Dialog.linkDOM("money,", "Money", "cash"));
 		r.push("at the cost of a large amount of");
-		r.push(App.UI.DOM.makeElement("span", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("reputation", "Arcologies and Reputation"), "."), ["reputation", "inc"]));
+		r.push(App.Encyclopedia.Dialog.linkDOM("reputation", "Arcologies and Reputation", "reputation inc"));
 		App.Events.addNode(ul, r, "li");
 
 		r = [];
diff --git a/src/gui/Encyclopedia/encyclopediaLore.js b/src/gui/Encyclopedia/encyclopediaLore.js
index 44b4dbdbd2458c1c92134744136444e5e3ed9904..d5a96847ab7dcc24a814103e1057f3504132d06b 100644
--- a/src/gui/Encyclopedia/encyclopediaLore.js
+++ b/src/gui/Encyclopedia/encyclopediaLore.js
@@ -102,13 +102,13 @@ App.Encyclopedia.addArticle("Slave Couture", function() {
  r.push("Let's break it right down into categories, shall we?");
  r.toNode("p", ["note"]);
 
- r.push(App.UI.DOM.makeElement("span","First, clothes for your disobedient bitches.", ["bold"]), "We must keep them uncomfortable, yes? The old reliable is", App.UI.DOM.makeElement("span","slave clothes", ["note"]) + ",", "sometimes referred to as straps. These give her that sex slave allure while keeping her nice and uncomfortable. You can also go for full coverage with", App.UI.DOM.makeElement("span","latex", ["note"]), ". A suit of that will keep her totally reliant on your little whims.", App.UI.DOM.makeElement("span","Plugs", ["note"]), "are nice sturdy leather affairs with inward-facing dildos for all the holes — and I do mean all. They're good stuff for breaking a bitch, and she might even learn to take dick a bit better! Word to the wise: not a good idea if you want those holes tight, though. Finally,", App.UI.DOM.makeElement("span","corsets", ["note"]), ". These will make life tough, but that's good for a", App.Encyclopedia.Dialog.linkDOM("rebellious", "From Rebellious to Devoted", "orangered"), "little cunt, no? And corseting might just narrow that waist. But never mind, on to my favorites.");
+ r.push(App.UI.DOM.makeElement("span","First, clothes for your disobedient bitches.", ["bold"]), "We must keep them uncomfortable, yes? The old reliable is slave clothes, sometimes referred to as straps. These give her that sex slave allure while keeping her nice and uncomfortable. You can also go for full coverage with latex. A suit of that will keep her totally reliant on your little whims. Plugs are nice sturdy leather affairs with inward-facing dildos for all the holes — and I do mean all. They're good stuff for breaking a bitch, and she might even learn to take dick a bit better! Word to the wise: not a good idea if you want those holes tight, though. Finally, corsets. These will make life tough, but that's good for a", App.Encyclopedia.Dialog.linkDOM("rebellious", "From Rebellious to Devoted", "orangered"), "little cunt, no? And corseting might just narrow that waist. But never mind, on to my favorites.");
  r.toNode("p", ["note"]);
 
- r.push(App.UI.DOM.makeElement("span","Second, nice attire for your prize stock.", ["bold"]), "These clothes will keep your good slaves happy. You know, women out in the old world still wear", App.UI.DOM.makeElement("span","attractive lingerie", ["note"]), "UNDER clothing? Absurd. It's lovely on its own. If you're looking to be a bit more fun and a bit less classy, go for", App.UI.DOM.makeElement("span","string lingerie", ["note"]), "instead. You could even let her choose her own", App.UI.DOM.makeElement("span","slutty outfits", ["note"]) + ";", "watching livestock dress itself is always good fun. When you can afford proper", App.UI.DOM.makeElement("span","slutty jewelry", ["note"]) + ",", "who needs clothes? I suggest accenting heavy piercings with this. For your hookah fanatics and decadent harem masters, there's", App.UI.DOM.makeElement("span","sheer gauze", ["note"]) + ".", "Makes even a clumsy girl look like she's dancing to a zither.");
+ r.push(App.UI.DOM.makeElement("span","Second, nice attire for your prize stock.", ["bold"]), "These clothes will keep your good slaves happy. You know, women out in the old world still wear attractive lingerie UNDER clothing? Absurd. It's lovely on its own. If you're looking to be a bit more fun and a bit less classy, go for string lingerie instead. You could even let her choose her own slutty outfits; watching livestock dress itself is always good fun. When you can afford proper slutty jewelry, who needs clothes? I suggest accenting heavy piercings with this. For your hookah fanatics and decadent harem masters, there's sheer gauze. Makes even a clumsy girl look like she's dancing to a zither.");
  r.toNode("p", ["note"]);
 
- r.push("Finally,", App.UI.DOM.makeElement("span","chastity belts", ["note"]) + ".", "Hard to categorize. Different bitches react in different ways to having the front door locked. Depends on how much traffic goes in the back, I find.");
+ r.push("Finally, chastity belts. Hard to categorize. Different bitches react in different ways to having the front door locked. Depends on how much traffic goes in the back, I find.");
  r.toNode("p", ["note"]);
 
  r.push("— Van Diemen, D. C. G.,", App.UI.DOM.makeElement("span","Free Cities Fashion (FCF), March 2032", ["note"]));
@@ -270,10 +270,10 @@ App.Encyclopedia.addArticle("The Sons of Sekhmet", function() {
  r.push(`Described as the "logical continuation of terrorism within the new world" by a prominent arcology owner, The Sons of Sekhmet are a global terrorist organization notorious for its viciousness and worldwide strike capacity. Formed in 2018 by Quati ibn Malek, the leader of a relatively minor sect of cat worshippers within Egypt, the Sons gained notoriety for seizing one of the first arcology clusters in the Sahara Desert and defending it from multiple incursions by old world peacekeeping forces. Ibn Malek was successfully assassinated by the Egyptian government in 2024, but the Sons have been resilient to being dislodged from their desert stronghold, and have used the resources of an arcology cluster to expand their presence and doctrine onto the global stage.`);
  r.toNode("p", ["note"]);
 
- r.push(`Their use of cell tactics and frequent insurgent action against arcology owners has led to comparisons with the Daughters of Liberty, but this is a misguided comparison. Where the Daughters are an ideologically-motivated anti-slavery organization, the Sons long ago cast off their ideological roots to adopt a brutal, pragmatic approach to terrorism with few considerations other than the expansion of their own power; Sekhmet cells frequently use slaves as footsoldiers and suicide bombers, but their primary approach to recruitment is with the poor and downtrodden of arcologies and old world nations. Basic Sons doctrine holds that the Old World was destroyed by wealthy, hedonistic plutocrats who have fled their failed nations to the arcologies to live out lives of decadence as the world they shattered collapses, leaving the "common people" to starve in their wake. This simple mantra attracts disgruntled individuals from around the world, and the Sons maintain an extremely online presence, with underground cells active in nearly every old world nation.`);
+ r.push(`Their use of cell tactics and frequent insurgent action against arcology owners has led to comparisons with the Daughters of Liberty, but this is a misguided comparison. Where the Daughters are an ideologically-motivated anti-slavery organization, the Sons long ago cast off their ideological roots to adopt a brutal, pragmatic approach to terrorism with few considerations other than the expansion of their own power; Sekhmet cells frequently use slaves as foot soldiers and suicide bombers, but their primary approach to recruitment is with the poor and downtrodden of arcologies and old world nations. Basic Sons doctrine holds that the Old World was destroyed by wealthy, hedonistic plutocrats who have fled their failed nations to the arcologies to live out lives of decadence as the world they shattered collapses, leaving the "common people" to starve in their wake. This simple mantra attracts disgruntled individuals from around the world, and the Sons maintain an extremely online presence, with underground cells active in nearly every old world nation.`);
  r.toNode("p", ["note"]);
 
- r.push("The capability of the Sons to provide manufactured weaponry and training, and their willingness to do so to anyone willing to pledge their life to the Orange Sun, makes them exceptionally dangerous. The Sons seize any possible oppurtunity to expand their wealth and power, and frequently launch assassination attempts on prominent public figures, sabotauge essential facilities, and attempt to stir chaos and unrest in vulnerable regions, often with the intent of stepping in and seizing power for themselves once the area has been sufficiently destabilized. Unlike many smaller-scale terrorist groups, the Sons produce some of the best-trained killers and thugs in the New World, and lie almost completely out of the reach of old world nations and arcology owners alike in their scorching desert arcology. Any responsible arcology owner should be aware of the orange sun used as the logo of the Sons of Sekhmet and take care to not expose themselves to any weakness.");
+ r.push("The capability of the Sons to provide manufactured weaponry and training, and their willingness to do so to anyone willing to pledge their life to the Orange Sun, makes them exceptionally dangerous. The Sons seize any possible opportunity to expand their wealth and power, and frequently launch assassination attempts on prominent public figures, sabotage essential facilities, and attempt to stir chaos and unrest in vulnerable regions, often with the intent of stepping in and seizing power for themselves once the area has been sufficiently destabilized. Unlike many smaller-scale terrorist groups, the Sons produce some of the best-trained killers and thugs in the New World, and are almost completely out of the reach of old world nations and arcology owners alike in their scorching desert arcology. Any responsible arcology owner should be aware of the orange sun used as the logo of the Sons of Sekhmet and take care to not expose themselves to any weakness.");
  r.toNode("p", ["note"]);
  App.Events.addNode(t, ["— Lawrence, J. K., and Bolingbroke, D. S.,", App.UI.DOM.makeElement("span","Trends in Free Cities Culture, 2031", ["underline"]), App.UI.DOM.makeElement("span","Journal of Modern Social Sciences, International Edition, February 2032", ["note"])], "p", ["indent", "note"]);
 
diff --git a/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw b/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw
index 5c7f7c4140c364ab45cb7d2e4ebf69359d4d522e..23a948a4f50e6000fc49612f4c0c72ce47d08b21 100644
--- a/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw
+++ b/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw
@@ -53,32 +53,6 @@ SLAVE PARAPHILIAS
 	| <<= App.Encyclopedia.Dialog.linkSC("Self Neglect", "Self Neglect")>>
 	| <<= App.Encyclopedia.Dialog.linkSC("Fetishes", "Fetishes")>>
 
-/**********
-SLAVE FLAWS
-**********/
-<<case "Anorexic" "Arrogant" "Bitchy" "Devout" "Flaws" "Gluttonous" "Hates Men" "Hates Women" "Liberated" "Odd" "Apathetic" "Crude" "Hates Anal" "Hates Oral" "Hates Penetration" "Idealistic" "Judgemental" "Repressed" "Shamefast">>
-	//Behavioral <<= App.Encyclopedia.Dialog.linkSC("Flaws", "Flaws")>>://
-	<<= App.Encyclopedia.Dialog.linkSC("Anorexic", "Anorexic")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Arrogant", "Arrogant")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Bitchy", "Bitchy")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Devout", "Devout")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Gluttonous", "Gluttonous")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Hates men", "Hates Men")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Hates women", "Hates Women")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Liberated", "Liberated")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Odd", "Odd")>>
-
-	<br>//Sexual <<= App.Encyclopedia.Dialog.linkSC("Flaws", "Flaws")>>://
-	<<= App.Encyclopedia.Dialog.linkSC("Apathetic", "Apathetic")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Crude", "Crude")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Hates anal", "Hates Anal")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Hates oral", "Hates Oral")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Hates penetration", "Hates Penetration")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Idealistic", "Idealistic")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Judgemental", "Judgemental")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Repressed", "Repressed")>>
-	| <<= App.Encyclopedia.Dialog.linkSC("Shamefast", "Shamefast")>>
-
 /**********
 SLAVE RELATIONSHIPS
 **********/
diff --git a/src/gui/Encyclopedia/encyclopediaSlaveFlaws.js b/src/gui/Encyclopedia/encyclopediaSlaveFlaws.js
new file mode 100644
index 0000000000000000000000000000000000000000..00616393bb0e86b20f8970f7340d73f3624ad04f
--- /dev/null
+++ b/src/gui/Encyclopedia/encyclopediaSlaveFlaws.js
@@ -0,0 +1,256 @@
+App.Encyclopedia.addArticle("Flaws", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Unflinching", ["bold"]), "are negative slave qualities.");
+	r.push("They decrease slaves' value and performance at sexual assignments, and each flaw also has other, differing effects. Each flaw is associated with a corresponding");
+	r.push(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), ", and slave can have two flaws (a sexual flaw and a behavioral flaw), just like quirks. New slaves will often have flaws, and tough experiences can also cause them to appear.");
+	r.toParagraph();
+
+	r.push("Flaws can softened or removed either by orders given to the", App.Encyclopedia.Dialog.linkDOM("Head Girl"), "or via personal attention provided by the player character.");
+	r.push("Flaws can also be naturally softened or removed by fetishes, and can resolve on their own if a slave is happy.");
+	r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Anorexic", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Anorexic", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("insecure"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, anorexia can cause unexpected weight loss. Anorexics will enjoy dieting but dislike gaining weight, and may bilk attempts to make them fatten up.");
+	r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Arrogant", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Arrogant", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("confident"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("The", App.Encyclopedia.Dialog.linkDOM("submissive", "Submissives"), "fetish fetish can do this naturally.");
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "gains are limited.");
+	r.toNode("div");
+
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Bitchy", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Bitchy", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+		r.push(App.Encyclopedia.Dialog.linkDOM("cutting"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+		r.push("The", App.Encyclopedia.Dialog.linkDOM("humiliation", "Humiliation Fetishists"), "fetish fetish can do this naturally.");
+		r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "gains are limited.");
+		r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Devout", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Devout", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("sinful"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("A very powerful sex drive can do this naturally.");
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "gains are limited.");
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Gluttonous", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Gluttonous", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("fitness"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, gluttons will enjoy gaining weight but dislike dieting, and may bilk attempts to make them lose weight.");
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Hates men", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Hates men", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("adores women"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("boob fetish.", "Boob Fetishists"));
+	r.push("Strong attraction to men or the", App.Encyclopedia.Dialog.linkDOM("pregnancy fetish", "Pregnancy Fetishists"), "will soften it so she", App.Encyclopedia.Dialog.linkDOM("adores men"), "instead.");
+	r.push("This flaw can also be removed by serving a player character or another slave with a dick.");
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Hates women", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Hates women", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("adores men"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("cumslut", "Cumsluts"), "fetish.");
+	r.push("Strong attraction to women or the", App.Encyclopedia.Dialog.linkDOM("pregnancy fetish", "Pregnancy Fetishists"), "will soften it so she", App.Encyclopedia.Dialog.linkDOM("Adores women"), "instead.");
+	r.push("This flaw can also be removed by serving a player character or another slave with a vagina.");
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Liberated", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Liberated", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("advocate"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("The", App.Encyclopedia.Dialog.linkDOM("submissive", "Submissives"), "fetish can do this naturally.");
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "gains are limited.");
+ r.toNode("div");
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Odd", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Odd", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("funny"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "."));
+	r.push("The", App.Encyclopedia.Dialog.linkDOM("humiliation", "Humiliation Fetishists"), "fetish can do this naturally.");
+	r.push("In addition to the standard penalties to value and performance on sexual assignments, weekly", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "gains are limited.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Apathetic", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Apathetic", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("caring"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("submissive", "Humiliation Submissive"), "fetish.");
+	r.push("It can also be removed by the", App.Encyclopedia.Dialog.linkDOM("dom", "Doms"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Crude", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Crude", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("unflinching"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("cumslut", "Cumsluts"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Hates anal", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Hates anal", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("painal queen"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("buttslut", "Buttsluts"), "fetish.");
+	r.push("This flaw can also be removed by serving the player character.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Hates oral", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Hates oral", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("gagfuck queen"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("cumslut", "Cumsluts"), "fetish.");
+	r.push("This flaw can also be removed by serving the player character.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Hates penetration", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Hates penetration", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("strugglefuck queen"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("buttslut", "Buttsluts"), "fetish.");
+	r.push("This flaw can also be removed by serving the player character.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Idealistic", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Idealistic", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("romantic"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("submissive", "Humiliation Submissive"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Judgemental", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Judgemental", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("size queen", "Size Queen"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("submissive", "Humiliation Submissive"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Repressed", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Repressed", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("perverted"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("cumslut", "Cumsluts"), "fetish, or the", App.Encyclopedia.Dialog.linkDOM("buttslut", "Buttsluts"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addArticle("Shamefast", function() {
+	const f = new DocumentFragment();
+	const r = new SpacedTextAccumulator(f);
+	r.push(App.UI.DOM.makeElement("span", "Shamefast", ["bold"]), "is a sexual", App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "that can be softened into the");
+	r.push(App.Encyclopedia.Dialog.linkDOM("tease"), App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "by training,");
+	r.push("a good", App.Encyclopedia.Dialog.linkDOM("Attendant"), ", a powerful sex drive, or the", App.Encyclopedia.Dialog.linkDOM("submissive", "Humiliation Submissive"), "fetish.");
+	r.toParagraph();
+
+	return f;
+}, "slaveFlaws");
+
+App.Encyclopedia.addCategory("slaveFlaws", function() {
+	const f = new DocumentFragment();
+	let r = [];
+	r.push(App.Encyclopedia.Dialog.linkDOM("Anorexic"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Arrogant"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Bitchy"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Devout"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Gluttonous"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Hates men"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Hates women"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Liberated"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Odd"));
+	App.Events.addNode(f, ["Behavioral ", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Flaws"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
+ 
+	r = [];
+	r.push(App.Encyclopedia.Dialog.linkDOM("Apathetic"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Crude"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Hates anal"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Hates oral"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Hates penetration"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Idealistic"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Judgemental"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Repressed"));
+	r.push(App.Encyclopedia.Dialog.linkDOM("Shamefast"));
+	App.Events.addNode(f, ["Sexual ", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Flaws"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
+
+	return f;
+});
diff --git a/src/gui/Encyclopedia/encyclopediaSlaveLeaders.js b/src/gui/Encyclopedia/encyclopediaSlaveLeaders.js
index 91db03c7994c6ed90e32922e120e3aed8c599c64..7d61715f93f00ab4d2e120188ffd24f827c0fa8a 100644
--- a/src/gui/Encyclopedia/encyclopediaSlaveLeaders.js
+++ b/src/gui/Encyclopedia/encyclopediaSlaveLeaders.js
@@ -53,17 +53,17 @@ App.Encyclopedia.addArticle("Career Experience", function() {
   * @param {string} [note]
   */
   function CareerBonus(career, bonus, list, note) {
-	const r = new SpacedTextAccumulator();
-	const notLeader = ["Grateful", "Menial", "Servant", "Entertainment", "Sex work"].includes(career);
-	const applicable = notLeader ? App.Data.Careers.General[list] : App.Data.Careers.Leader[list];
-
-	r.push(App.UI.DOM.makeElement("span", career, ["underline"]), `which offers a ${career === "Grateful" || career === "Menial" ? 'potential' : ''} bonus to`, bonus, `includes slaves who were: ${toSentence(applicable)}.`);
-	r.toNode("div");
-	if (note) {
-	  r.push(note);
-	  r.toNode("div");
-	}
-	return r.container();
+    const r = new SpacedTextAccumulator();
+    const notLeader = ["Grateful", "Menial", "Servant", "Entertainment", "Sex work"].includes(career);
+    const applicable = notLeader ? App.Data.Careers.General[list] : App.Data.Careers.Leader[list];
+
+    r.push(App.UI.DOM.makeElement("span", career, ["underline"]), `which offers a ${career === "Grateful" || career === "Menial" ? 'potential' : ''} bonus to`, bonus, `includes slaves who were: ${toSentence(applicable)}.`);
+    r.toNode("div");
+    if (note) {
+      r.push(note);
+      r.toNode("div");
+    }
+    return r.container();
   }
 }, "slaveLeaders");
 
@@ -96,14 +96,13 @@ App.Encyclopedia.addArticle("Matron", function() { // TODO: will still need more
 
 App.Encyclopedia.addArticle("Bodyguard", function() {
   const t = new DocumentFragment();
-  let r;
+  let r = [];
   const link = (text, article, className) => App.Encyclopedia.Dialog.linkDOM(text, article, className);
   const reduceDeadliness = [link("Big breasts", "Breasts"), link("butts"), link("poor health", "Health"), link("excess weight", "Weight"), link("pregnancy")];
   const bodyguardTrainees = ["her lover or wife if she has one",	link("the Head Girl", "Head Girl"), link("the Wardeness", "Wardeness"), link("your Concubine.", "Concubine")];
 
   App.UI.DOM.appendNewElement("div", t, "Slave bodyguards are best understood not as protection for a slaveowner's person, but rather as a projection of their skill at slave breaking.", ["note"]);
 
-  r = [];
   r.push("By giving a slave the means and position to easily kill her master, that master displays their total trust in them. The simple fact that an armed slave is near a slaveowner at all times is proof that that slaveowner has produced at least one slave that never wavers in her");
   r.push(link("devotion.", "From Rebellious to Devoted", "hotpink"));
   r.push("After all, if she ever wavered, the slaveowner would likely be dead.");
@@ -152,9 +151,8 @@ App.Encyclopedia.addArticle("Concubine", function() {
 App.Encyclopedia.addArticle("DJ", function() {
   const link = (text, article, className) => App.Encyclopedia.Dialog.linkDOM(text, article, className);
   const t = new DocumentFragment();
-  let r;
+  let r = [];
 
-  r = [];
   r.push(`My name is Danni Diemen, and I'm here today to talk about the prettiest girls in the Free Cities. That's right, DJs! When a slave bitch says, "Sweetie, I'm not that kind of girl," she's lying. She's a slave, and she is that kind of girl! So, have your way with her.`);
   App.Events.addNode(t, r, "p", "note");
 
@@ -210,20 +208,22 @@ App.Encyclopedia.addArticle("Head Girl", function() {
   r.push("In addition, such a slave can be an example to lesser livestock.");
   App.Events.addNode(t, r, "div", "note");
 
+  r = [];
   r.push("A good Head Girl will be", devotion("devoted"), "to her master and sexually skilled.");
   r.push("Experienced slaveowners have also found that an older slave girl is often more effective than a young one.");
   r.push("Since slavery is new, older slave girls will have spent part of their adult lives as free women, and have a deeper body of life experience to draw on.");
   App.Events.addNode(t, r, "p", "note");
 
+  r = [];
   r.push("Naturally, some slaveowners form a strong emotional bond with their Head Girl.");
   r.push(trust("Trusting"), "and relying on a close companion can begin to resemble old world relationships.");
   r.push("It is a paradox of modern Free Cities life that such closeness is strongly frowned upon.");
   r.push("Rumors that a prominent person is emotionally involved with his or her Head Girl can be as socially devastating as rumors of infidelity were a hundred years ago.");
   App.Events.addNode(t, r, "p", "note");
 
-  r.push("— Lawrence, W. G., Guide to Modern Slavery, 2037 Edition");
-  App.Events.addNode(t, r, "p", "note");
+  App.Events.addNode(t, ["— Lawrence, W. G., Guide to Modern Slavery, 2037 Edition"], "p", "note");
 
+  r = [];
   r.push("A", App.UI.DOM.makeElement("span", "Head Girl", ["bold"]));
   r.push("can be selected from among your", devotion("devoted"), "slaves immediately.");
   r.push("Duties are numerous, but mostly involve training slaves.");
@@ -231,6 +231,7 @@ App.Encyclopedia.addArticle("Head Girl", function() {
   r.push("Giving your", link("Head Girl a suite", "Head Girl Suite"), "and a personal slave will allow her to train an extra slave each week, an extremely powerful ability.");
   App.Events.addParagraph(t, r);
 
+  r = [];
   r.push(devotion(), App.UI.DOM.makeElement("span", "intelligence", ["cyan"]), "and age over 30 all help Head Girls do well.");
   r.push("Head Girls will do better if they are comfortable with the arcology's", link("lingua franca"), ".");
   r.push("Skills are required when teaching that skill, meaning that slaves without vaginas cannot teach vaginal skills.");
@@ -244,9 +245,8 @@ App.Encyclopedia.addArticle("Head Girl", function() {
 App.Encyclopedia.addArticle("Madam", function() {
   const link = (text, article, className) => App.Encyclopedia.Dialog.linkDOM(text, article, className);
   const t = new DocumentFragment();
-  let r;
+  let r = [];
 
-  r = [];
   r.push("Prostitution is indeed the oldest profession. It follows that the madam is probably the oldest managerial position.");
   App.Events.addNode(t, r, "div", "note");
 
@@ -287,9 +287,8 @@ App.Encyclopedia.addArticle("Milkmaid", function() {
   const devotion = (text="devotion", colour="hotpink") => link(text, "From Rebellious to Devoted", colour);
   const trust = (text="trust") => link(text, "Trust", "mediumaquamarine");
   const t = new DocumentFragment();
-  let r;
+  let r = [];
 
-  r = [];
   r.push("Most slaveowners get into dairy as a hobby. Why not? It's fun, tasty, and sexy. But sooner or later, almost everyone who starts out with a few low-volume milkers hears the call of mass production. After all, if it's hot to have one slave to use as the milking machine holds her down, it's hotter to have a whole row of moaning milkers at your mercy.");
   App.Events.addNode(t, r, "div");
 
@@ -310,7 +309,7 @@ App.Encyclopedia.addArticle("Milkmaid", function() {
   r.push("Having applicable", link("career experience", "Career Experience"), "and strong", link("muscles", "Musculature"), "allow a Milkmaid to help cows maintain their health.");
   r.push("If a Milkmaid is Funny or Caring, she can improve cow's", trust("trusting"), "resting point; if she has oral skills, she can improve their", devotion(), "resting point.");
   if (V.seeDicks !== 0) {
-	r.push("If she has a very large dick capable of erection, a Milkmaid can assist cows with ejaculation if the Dairy is not already stimulating prostates.");
+	  r.push("If she has a very large dick capable of erection, a Milkmaid can assist cows with ejaculation if the Dairy is not already stimulating prostates.");
   }
   App.Events.addNode(t, r, "div");
 
@@ -335,9 +334,8 @@ App.Encyclopedia.addArticle("Recruiter", function() {
   const devotion = (text="devotion", colour="hotpink") => link(text, "From Rebellious to Devoted", colour);
   const rep = (text="reputation") => link(text, "Arcologies and Reputation", "green");
   const t = new DocumentFragment();
-  let r;
+  let r = [];
 
-  r = [];
   r.push("A", App.UI.DOM.makeElement("span", "Recruiter", ["bold"]), "can be selected from among your", devotion("devoted"), "slaves immediately.");
   r.push(App.UI.DOM.makeElement("span", "Intelligence", ["cyan"]), "entertainment skills, and luxurious living standards help a recruiter convince vulnerable people to submit to voluntary enslavement.");
   r.push("Each targetable group is also more sympathetic to an appropriate recruiter.");
@@ -378,9 +376,8 @@ App.Encyclopedia.addArticle("Stewardess", function() {
   const devotion = (text="devotion", colour="hotpink") => link(text, "From Rebellious to Devoted", colour);
   const trust = (text="trust") => link(text, "Trust", "mediumaquamarine");
   const t = new DocumentFragment();
-  let r;
+  let r = [];
 
-  r = [];
   r.push("Throughout recorded history, wherever there have been mature slave societies, there have been slave overseers set over their peers by their masters. Naturally, these individuals have simultaneously been among the most");
   r.push(trust("trusted"));
   r.push("to their masters, and among the most hated to their compatriots in slavery. They have perhaps the greatest interest in preservation of a slave society, since the masters have only the loss of property to fear by abolition; slave overseers would likely be less lucky.");
diff --git a/src/gui/Encyclopedia/encyclopediaSlaveQuirks.js b/src/gui/Encyclopedia/encyclopediaSlaveQuirks.js
index b009357c60c2c667e668d08748acd6555c6e6634..c840b8185d13b33500458c44e54899263cd18a8c 100644
--- a/src/gui/Encyclopedia/encyclopediaSlaveQuirks.js
+++ b/src/gui/Encyclopedia/encyclopediaSlaveQuirks.js
@@ -13,7 +13,7 @@ App.Encyclopedia.addArticle("Quirks", function() {
 	return f;
 }, "slaveQuirks");
 
-App.Encyclopedia.addArticle("Adores Men", function() {
+App.Encyclopedia.addArticle("Adores men", function() {
 	const f = new DocumentFragment();
 	const r = new SpacedTextAccumulator(f);
  r.push(App.UI.DOM.makeElement("span", "Adores men", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "developed from the");
@@ -26,7 +26,7 @@ App.Encyclopedia.addArticle("Adores Men", function() {
 	return f;
 }, "slaveQuirks");
 
-App.Encyclopedia.addArticle("Adores Women", function() {
+App.Encyclopedia.addArticle("Adores women", function() {
 	const f = new DocumentFragment();
 	const r = new SpacedTextAccumulator(f);
  r.push(App.UI.DOM.makeElement("span", "Adores women", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "developed from the");
@@ -122,7 +122,7 @@ App.Encyclopedia.addArticle("Sinful", function() {
 	r.push(App.UI.DOM.makeElement("span", "Sinful", ["bold"]), "is a behavioral", App.Encyclopedia.Dialog.linkDOM("quirk", "Quirks"), "developed from the");
 	r.push(App.Encyclopedia.Dialog.linkDOM("devout"), App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("flaw", "Flaws"), "."));
 	r.push("Slaves may naturally become", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("humiliation fetishists", "Humiliation Fetishists"), "."));
-	r.push("In addition to the standard value and sexual assignment advantages, they get bonus", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "while performing", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("whoring."), "."));
+	r.push("In addition to the standard value and sexual assignment advantages, they get bonus", App.Encyclopedia.Dialog.linkDOM("devotion", "From Rebellious to Devoted", "hotpink"), "while performing", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("whoring"), "."));
 	r.toNode("div");
 
 	return f;
@@ -258,7 +258,7 @@ App.Encyclopedia.addCategory("slaveQuirks", function() {
 	r.push(App.Encyclopedia.Dialog.linkDOM("Funny"));
 	r.push(App.Encyclopedia.Dialog.linkDOM("Insecure"));
 	r.push(App.Encyclopedia.Dialog.linkDOM("Sinful"));
-	App.Events.addNode(f, ["Behavioral", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Quirks"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
+	App.Events.addNode(f, ["Behavioral ", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Quirks"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
  
 	r = [];
 	r.push(App.Encyclopedia.Dialog.linkDOM("Caring"));
@@ -270,7 +270,7 @@ App.Encyclopedia.addCategory("slaveQuirks", function() {
 	r.push(App.Encyclopedia.Dialog.linkDOM("Strugglefuck Queen"));
 	r.push(App.Encyclopedia.Dialog.linkDOM("Tease"));
 	r.push(App.Encyclopedia.Dialog.linkDOM("Unflinching"));
-	App.Events.addNode(f, ["Sexual", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Quirks"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
+	App.Events.addNode(f, ["Sexual ", App.UI.DOM.combineNodes(App.Encyclopedia.Dialog.linkDOM("Quirks"), ":"), App.UI.DOM.generateLinksStrip(r)], "div");
 
 	return f;
 });
diff --git a/src/gui/Encyclopedia/encyclopediaX-SeriesArcology.js b/src/gui/Encyclopedia/encyclopediaX-SeriesArcology.js
index 83cda2acbe9549d203ea17e28175757a1e4e51bf..05ed03f29e8badbf12bf0dbfa65b1060e4fb1586 100644
--- a/src/gui/Encyclopedia/encyclopediaX-SeriesArcology.js
+++ b/src/gui/Encyclopedia/encyclopediaX-SeriesArcology.js
@@ -2,20 +2,17 @@ App.Encyclopedia.addArticle("The X-Series Arcology", function() {
 	const t = new DocumentFragment();
 	const r = new SpacedTextAccumulator(t);
 
-	r.push("The X-Series Arcology is the latest model of 'arcology', designed in 2037 based off the model of keeping Free Cities as independent from the old world as fiscally viable. The first arcology was designed in early 2016 by the Berlin-based architecture firm Franz-Crekcht as a");
-	r.push('"Skyscraper for the next generation"');
-	r.push("- the A-Series. The original A-Series was made to exist as an arcology integrated within old world nations, but capable of producing its own energy, food, and housing for the population contained within, marketed as buildings you could");
-	r.push('"Live, work, eat and shop at without ever having to leave"');
-	r.push(". These first arcology units were rolled out by the end of the year based on a standard design prototype, and cheap housing prices combined with the promise of stable white-collar work immediately attracted a sizeable population to the A-series arcologies. Based off of these designs, F-C continued to produce arcology schematics, including the K-series and B-series, and formulated plans for arcologies that could operate in rural, maritime, and even oceanic environments. When the popularity of the Arcology model became evident, other design firms replicated their own takes, producing designs like the V-series, D-series, F-series, and finally the ultra-modern X-series that you presently inhabit, designed more as a quasi-independent city-state than the original");
-	r.push('"next-generation skyscrapers"');
-	r.push(". It wasn't long before arcologies began to form 'clusters' together, relying more on each other for trade and cultural exchange than the old world that surrounded them; increasingly complex infrastructure and surrounding networks began to connect the clusters, tying them together and making them stand apart from the rest of society, largely free from the purview of bureaucrats and old cultural mores. As the world outside the increasingly self-sufficient arcologies began to deteriorate, it wasn't long after that before the first arcologies declared independence from their parent nations, creating the original Free Cities we know today.");
+	r.push(`The X-Series Arcology is the latest model of 'arcology', designed in 2037 based off the model of keeping Free Cities as independent from the old world as fiscally viable. The first arcology was designed in early 2016 by the Berlin-based architecture firm Franz-Crekcht as a "Skyscraper for the next generation" - the A-Series. The original A-Series was made to exist as an arcology integrated within old world nations, but capable of producing its own energy, food, and housing for the population contained within, marketed as buildings you could "Live, work, eat and shop at without ever having to leave".`);
+	r.push(`These first arcology units were rolled out by the end of the year based on a standard design prototype, and cheap housing prices combined with the promise of stable white-collar work immediately attracted a sizeable population to the A-series arcologies. Based off of these designs, F-C continued to produce arcology schematics, including the K-series and B-series, and formulated plans for arcologies that could operate in rural, maritime, and even oceanic environments. When the popularity of the Arcology model became evident, other design firms replicated their own takes, producing designs like the V-series, D-series, F-series, and finally the ultra-modern X-series that you presently inhabit, designed more as a quasi-independent city-state than the original "next-generation skyscrapers".`);
+	r.toParagraph();
+	r.push("It wasn't long before arcologies began to form 'clusters' together, relying more on each other for trade and cultural exchange than the old world that surrounded them; increasingly complex infrastructure and surrounding networks began to connect the clusters, tying them together and making them stand apart from the rest of society, largely free from the purview of bureaucrats and old cultural mores. As the world outside the increasingly self-sufficient arcologies began to deteriorate, it wasn't long after that before the first arcologies declared independence from their parent nations, creating the original Free Cities we know today.");
 	r.toParagraph();
 
 	r.push("Choose a more particular entry below:");
 	r.toNode("div");
 
 	return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("What the Upgrades Do", function() {
  const t = new DocumentFragment();
@@ -32,37 +29,38 @@ App.Encyclopedia.addArticle("What the Upgrades Do", function() {
 	 */
   const highlight = (text, tag=["bold"]) => App.UI.DOM.makeElement("span", text, tag);
 
- App.Events.addNode(t, [`There are a lot of upgrades available for your arcology, ${properTitle()}. Please relax; some panic upon reviewing the options is normal. This list should familiarize you with your choices.`], "div", "note");
-
- r.push(highlight("Construction", ["div"]));
- r.push("The first upgrade section on the arcology management menu offers an escalating series of generic upgrades for the arcology. A few of these have minor beneficial side effects, but all share the same main effect: they raise the arcology's maximum prosperity level. You will be informed on the end of week report if your arcology is nearing, at, or over this level. Upgrading early is", highlight("not", ["note"]), "useless, since prosperity will increase more rapidly if the cap is much higher than the current prosperity level.");
- r.toParagraph();
-
- r.push(highlight("Facilities", ["div"]));
- r.push("These upgrades unlock the various facilities, which are detailed", link("here.", "Facilities"));
- r.toParagraph();
-
- r.push(highlight("Penthouse Improvements", ["div"]));
- r.push("The master suite and Head Girl suite options function like facilities. The master suite is the facility for the fucktoy assignment, and the Head Girl suite can house a single slave for her use.");
- r.toNode("div");
- App.Events.addNode(t, [highlight(highlight("Kitchen upgrade:"), ["bold", "note"]), "this increases the chances of success for dieting and opens up additional dietary options."], "div", ["indent"]);
- App.Events.addNode(t, [highlight(highlight("Feeding phalli:"), ["bold", "note"]), "unbroken slaves will find this disgusting, but it can cause beneficial oral fetishes to appear."], "div", ["indent"]);
- App.Events.addNode(t, [highlight(highlight("Drug fuckmachines:"), ["bold", "note"]), "unbroken slaves will resent this, but it may cause beneficial anal fetishes to appear."], "div", ["indent"]);
- App.Events.addNode(t, [highlight(highlight("Personal armory:"), ["bold", "note"]), "unlocks bodyguard options on the main menu."], "div", ["indent"]);
- App.Events.addNode(t, [highlight(highlight("Pharmaceutical Fabricator:"), ["bold", "note"]), "requires a lot of", link("reputation", "Arcologies and Reputation"), "green", "to buy and use; unlocks powerful drug upgrades."], "div", ["indent"]);
- App.Events.addNode(t, [highlight(highlight("Surgery upgrade:"), ["bold", "note"]), "enables several extreme surgical options like virginity restoration and hermaphrodite creation."], "div", ["indent"]);
- r.toNode("p");
-
- r.push(highlight("Special Upgrades", ["div"]));
- r.push("Upgrades obtained during special events are listed here for reference. They cannot be purchased normally. Week:");
- r.toNode("div");
- App.Events.addNode(t, [highlight("24:"), "Arming yourself and or your", link("drones", "Security Drones"), "if installed."], "div", ["indent"]);
- App.Events.addNode(t, [highlight("62:"), "Establishing mercs."], "div", ["indent"]);
- App.Events.addNode(t, [highlight("65:"), "Giving your established mercs a unique title."], "div", ["indent"]);
- App.Events.addNode(t, [highlight("72 or later:"), "Establish the", link("Special Force"), "(if the mod is enabled)."], "div", ["indent"]);
+	App.Events.addNode(t, [`There are a lot of upgrades available for your arcology, ${properTitle()}. Please relax; some panic upon reviewing the options is normal. This list should familiarize you with your choices.`], "div", "note");
+
+	t.append(App.UI.DOM.makeElement("h3", "Construction"));
+	r.push("The first upgrade section on the arcology management menu offers an escalating series of generic upgrades for the arcology. A few of these have minor beneficial side effects, but all share the same main effect: they raise the arcology's maximum prosperity level. You will be informed on the end of week report if your arcology is nearing, at, or over this level. Upgrading early is", highlight("not", ["note"]), "useless, since prosperity will increase more rapidly if the cap is much higher than the current prosperity level.");
+	r.toParagraph();
+
+	t.append(App.UI.DOM.makeElement("h3", "Facilities"));
+	r.push("These upgrades unlock the various facilities, which are detailed", link("here.", "Facilities"));
+	r.toParagraph();
+
+	t.append(App.UI.DOM.makeElement("h3", "Penthouse Improvements"));
+	r.push("The master suite and Head Girl suite options function like facilities. The master suite is the facility for the fucktoy assignment, and the Head Girl suite can house a single slave for her use.");
+	r.toNode("div");
+
+	App.Events.addNode(t, [highlight("Kitchen upgrade:", ["bold", "note"]), "this increases the chances of success for dieting and opens up additional dietary options."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Feeding phalli:", ["bold", "note"]), "unbroken slaves will find this disgusting, but it can cause beneficial oral fetishes to appear."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Drug fuckmachines:", ["bold", "note"]), "unbroken slaves will resent this, but it may cause beneficial anal fetishes to appear."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Personal armory:", ["bold", "note"]), "unlocks bodyguard options on the main menu."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Pharmaceutical Fabricator:", ["bold", "note"]), "requires a lot of", link("reputation", "Arcologies and Reputation"), "green", "to buy and use; unlocks powerful drug upgrades."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Surgery upgrade:", ["bold", "note"]), "enables several extreme surgical options like virginity restoration and hermaphrodite creation."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("Media Hub:", ["bold", "note"]), "allows you to produce, encode, and stream videos of your slaves' daily lives to popular online pornography sites."], "div", ["indent"]);
+
+	t.append(App.UI.DOM.makeElement("h3", "Special Upgrades"));
+	r.push("Upgrades obtained during special events are listed here for reference. They cannot be purchased normally. Week:");
+	r.toNode("div");
+	App.Events.addNode(t, [highlight("24:"), "Arming yourself and or your", link("drones", "Security Drones"), "if installed."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("62:"), "Establishing mercs."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("65:"), "Giving your established mercs a unique title."], "div", ["indent"]);
+	App.Events.addNode(t, [highlight("72 or later:"), "Establish the", link("Special Force"), "(if the mod is enabled)."], "div", ["indent"]);
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("Personal Assistant", function() {
  const t = new DocumentFragment();
@@ -82,7 +80,7 @@ App.Encyclopedia.addArticle("Personal Assistant", function() {
 	r.toNode("p", ["note"]);
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("The Wardrobe", function() {
  const t = new DocumentFragment();
@@ -95,7 +93,7 @@ App.Encyclopedia.addArticle("The Wardrobe", function() {
 	r.toParagraph();
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("The Auto Salon", function() {
  const t = new DocumentFragment();
@@ -112,7 +110,7 @@ App.Encyclopedia.addArticle("The Auto Salon", function() {
 	r.toParagraph();
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("The Body Mod Studio", function() {
  const t = new DocumentFragment();
@@ -128,7 +126,7 @@ App.Encyclopedia.addArticle("The Body Mod Studio", function() {
 	r.toNode("p", ["note"]);
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("The Remote Surgery", function() {
  const t = new DocumentFragment();
@@ -147,7 +145,7 @@ App.Encyclopedia.addArticle("The Remote Surgery", function() {
 	r.toNode("p", ["note"]);
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("The Pharmaceutical Fab", function() {
  const t = new DocumentFragment();
@@ -160,7 +158,7 @@ App.Encyclopedia.addArticle("The Pharmaceutical Fab", function() {
 	r.toNode("div");
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("Security Drones", function() {
  const t = new DocumentFragment();
@@ -185,7 +183,7 @@ App.Encyclopedia.addArticle("Security Drones", function() {
 	r.toParagraph();
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("Water Filtration", function() {
  const t = new DocumentFragment();
@@ -207,7 +205,7 @@ App.Encyclopedia.addArticle("Water Filtration", function() {
 	r.toParagraph();
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
 
 App.Encyclopedia.addArticle("Slave Nutrition", function() {
  const t = new DocumentFragment();
@@ -229,9 +227,37 @@ App.Encyclopedia.addArticle("Slave Nutrition", function() {
 	r.toParagraph();
 
  return t;
-}, "X-SeriesArchology");
+}, "X-SeriesArcology");
+
+App.Encyclopedia.addArticle("Media Hub", function() {
+	const r = new SpacedTextAccumulator();
+
+	r.push("Not everyone can be a Free Cities titan. But thanks to the power of the internet, everyone can watch!");
+	r.toNode("div", ["note"]);
+
+	r.push("—", App.UI.DOM.makeElement("span", `Porn Insider magazine, October 2035: "Free Cities Pornography: a new era of sex slave voyeurism"`, ["note"]));
+	r.toNode("p", ["note"]);
+
+	r.push("Constructing and upgrading the Media Hub allows you to produce and stream pornographic videos featuring your slaves for the world to see (and pay for).");
+	r.toParagraph();
+
+	r.push("Slaves featured in pornography will gain viewers and fame over time. Some may even become world-famous porn stars in their own right, with a little help.");
+	r.toParagraph();
+
+	r.push("Slaves with pretty faces will gain viewership significantly faster. Particularly ugly slaves may benefit from having their faces covered with a mask, or covered by a", App.Encyclopedia.Dialog.linkDOM("fuckdoll", "Fuckdolls"), "suit.");
+	r.push("Viewership can also be driven by investing cash in promotion and advertising, or by search engine optimization and feed hacking.");
+	r.toParagraph();
+
+	r.push("Slaves will produce porn in a variety of genres based on their characteristics. By default, her viewers will decide what she focuses on with their views and credits, but you can upgrade the media hub to allow you to choose a particular genre for a slave to focus on. Having too many slaves focusing on a particular genre will decrease the ability of that genre to draw new viewers. Genres associated with", App.Encyclopedia.Dialog.linkDOM("paraphilias", "Paraphilias"), "will have their viewership increase fastest, followed by", App.Encyclopedia.Dialog.linkDOM("fetish", "Fetishes"), "genres. More general genres (such as those based on age, weight, and build) grow slowly, and genres associated with sexual", App.Encyclopedia.Dialog.linkDOM("quirks", "Quirks"), "grow slowest of all, and are likely to require investment to promote.");
+	r.toParagraph();
+
+	r.push("If you stop producing porn of a particular slave, her viewership will decline over time, until she is once again unknown.");
+	r.toParagraph();
+
+	return r.container();
+}, "X-SeriesArcology");
 
-App.Encyclopedia.addCategory("X-SeriesArchology", function() {
+App.Encyclopedia.addCategory("X-SeriesArcology", function() {
  const r = [];
 	if (V.encyclopedia !== "The X-Series Arcology") {
 		r.push(App.Encyclopedia.Dialog.linkDOM("The X-Series Arcology"));
@@ -246,5 +272,6 @@ App.Encyclopedia.addCategory("X-SeriesArchology", function() {
  r.push(App.Encyclopedia.Dialog.linkDOM("Security Drones"));
  r.push(App.Encyclopedia.Dialog.linkDOM("Water Filtration"));
  r.push(App.Encyclopedia.Dialog.linkDOM("Slave Nutrition"));
+ r.push(App.Encyclopedia.Dialog.linkDOM("Media Hub"));
  return App.UI.DOM.generateLinksStrip(r);
 }); 
diff --git a/src/gui/options/options.js b/src/gui/options/options.js
index 41848665b7ffb3da12bda4b004cb34a047f5da94..19b5ca8aee23b2ef4460fd1ff68d77c691c86c5a 100644
--- a/src/gui/options/options.js
+++ b/src/gui/options/options.js
@@ -882,6 +882,9 @@ App.Intro.display = function(isIntro) {
 	options.addOption("Purchase options are", "purchaseStyle")
 		.addValue("Links", 'link').addValue("Buttons", 'button');
 
+	options.addOption("Default Rules Assistant mode is", "raDefaultMode")
+		.addValue("Simple", 0).addValue("Advanced", 1);
+
 	el.append(options.render());
 
 	r = [];
diff --git a/src/gui/quicklinks.js b/src/gui/quicklinks.js
index 8b1a5b37b696191731f4a363c9a8310ed6968976..5af78e852e750b9a0c541aa5f159e6c52cb25999 100644
--- a/src/gui/quicklinks.js
+++ b/src/gui/quicklinks.js
@@ -66,6 +66,7 @@ App.UI.quickMenu = (function() {
 			"Prosthetic Lab": true,
 			"Wardrobe": true,
 			"Toy Shop": true,
+			"Media Studio": true,
 			"The Black Market": true,
 		},
 		Tools: {
@@ -98,6 +99,7 @@ App.UI.quickMenu = (function() {
 		"Future Society": () => !V.FSAnnounced,
 		"Gene Lab": () => !V.geneticMappingUpgrade,
 		"Toy Shop": () => !V.toyShop,
+		"Media Studio": () => !V.studio,
 		"Head Girl Suite": () => !V.HGSuite,
 		"Implant Manufactory": () => !V.ImplantProductionUpgrade,
 		"Incubator": () => V.incubator.capacity === 0,
diff --git a/src/gui/storyCaption.js b/src/gui/storyCaption.js
index 324ca31d9da14b8cc5086f67173357268056e159..2c99fa7dcbe38a4860570ad0b53fa4a1f003cc77 100644
--- a/src/gui/storyCaption.js
+++ b/src/gui/storyCaption.js
@@ -90,7 +90,7 @@ App.UI.storyCaption = function() {
 		if (V.arcologies[0].weeks !== V.week) {
 			App.UI.DOM.appendNewElement("div", tooltip, `${capFirstChar(years(V.arcologies[0].weeks))} in ${V.arcologies[0].name}`);
 		}
-		App.UI.DOM.appendNewElement("span", fragment, App.UI.DOM.spanWithTooltip(`Week ${V.week}`, tooltip, ['bold']));
+		App.UI.DOM.appendNewElement("span", fragment, App.UI.DOM.spanWithTooltip(`Week ${num(V.week)}`, tooltip, ['bold']));
 		fragment.append(div);
 		App.UI.DOM.appendNewElement("div", fragment, `Week of ${asDateString(V.week)}`);
 
diff --git a/src/interaction/artificialInsemination.js b/src/interaction/artificialInsemination.js
index 9b5d83e556143fe853f7537ddd28b2b5c660ff4c..e5feacfe5549696c5beda4b405f2d63fecc85039 100644
--- a/src/interaction/artificialInsemination.js
+++ b/src/interaction/artificialInsemination.js
@@ -7,7 +7,7 @@ App.UI.SlaveInteract.artificialInsemination = function() {
 
 	App.UI.DOM.appendNewElement("p", f, `${getSlave(V.AS).slaveName} is prepped for fertilization; now you must select a target to harvest sperm from.`, "scene-intro");
 
-	App.UI.DOM.appendNewElement("h2", f, "Select an eligible slave to serve as the semen donatrix");
+	App.UI.DOM.appendNewElement("h2", f, "Select an eligible slave to serve as the semen donor");
 
 	r = [];
 	let any = false;
diff --git a/src/interaction/main/mainLinks.js b/src/interaction/main/mainLinks.js
index 1013d1f1288cc7c85002f6476f1f01313cae9ba7..e971f096e45c095077216ba1975e4ddb9f55c5b7 100644
--- a/src/interaction/main/mainLinks.js
+++ b/src/interaction/main/mainLinks.js
@@ -6,7 +6,7 @@ App.UI.View.mainLinks = function() {
 	const PA = V.personalAttention.task === PersonalAttention.TRAINING ? V.personalAttention.slaves.map(x => getSlave(x.ID)) : [];
 	let fragment = document.createDocumentFragment();
 
-	if (V.PC.health.shortDamage >= 30) {
+	if (onBedRest(V.PC, true) && V.PC.dick < -4000) { // Impossible condition to prevent scope creep. Need to finish this later, not right now.
 		fragment.append(`The injuries received in the recent battle prevent you from undertaking tiring efforts.`);
 	} else {
 		switch (V.personalAttention.task) {
diff --git a/src/interaction/sellSlave.js b/src/interaction/sellSlave.js
index c315f6e05e333284c1249015c9f9af7b5ea103cd..7c5e288d394e8e3fd4aa0a41c194566d0bd3b63e 100644
--- a/src/interaction/sellSlave.js
+++ b/src/interaction/sellSlave.js
@@ -1176,7 +1176,7 @@ App.Interact.sellSlave = function(slave) {
 					let slaveImpact;
 					r.push(`${slave.slaveName} is seen nine months later with an enormous pregnancy and the most content look on ${his} face. ${He}`);
 					if (hasAnyArms(slave)) {
-						r.push(`gently pats ${his} quadruplet filled belly and lets off a moan as ${his} children kick in response.`);
+						r.push(`gently pats ${his} quadruplet-filled belly and lets off a moan as ${his} children kick in response.`);
 					} else {
 						r.push(`moans lewdly as ${his} children kick away in ${his} womb.`);
 					}
@@ -2723,7 +2723,7 @@ App.Interact.sellSlave = function(slave) {
 					r.push(`The mercenary sniper greets ${slave.slaveName} before the two of them head off for a battlefield halfway around the world. "Let's hope you've got a good eye for political assassinations," he says humorlessly.`);
 					for (const s of V.slaves) {
 						if (s.skill.combat <= 15) {
-							s.devotion -= 3;
+							s.trust -= 3;
 							slaveImpact = 1;
 						}
 					}
diff --git a/src/interaction/siDescription.js b/src/interaction/siDescription.js
index b24edf931f997596a1dec77510d81b973a965f14..fa38f4753551bf78336d63322d98130cc3c8f081 100644
--- a/src/interaction/siDescription.js
+++ b/src/interaction/siDescription.js
@@ -10,7 +10,7 @@ App.UI.SlaveInteract.description = function(slave) {
 		descriptionOptions.id = "description-options";
 		el.append(descriptionOptions);
 
-		el.append(App.Desc.longSlave(slave, {noArt: true}));
+		el.append(App.Desc.longSlave(slave, {noArt: true, links: true}));
 
 		descriptionLink.append(showOptions());
 		el.append(descriptionLink);
diff --git a/src/interaction/siRecords.js b/src/interaction/siRecords.js
index 8581fc8610adfc5f236f543f2e0809c099df23d2..18abe00a1dbe5626197224cefd1b5fbbb15443a5 100644
--- a/src/interaction/siRecords.js
+++ b/src/interaction/siRecords.js
@@ -18,167 +18,128 @@ App.UI.SlaveInteract.records = function(slave, refresh) {
 
 		if (slave.porn.prestige === 3) {
 			App.UI.DOM.appendNewElement("div", el, `${He} is so prestigious in the realm of ${slave.porn.fameType} porn that ${his} fame is self-sustaining.`, ["note"]);
-		} else if (slave.porn.feed === 0) {
-			r = [];
-			r.push(`The media hub is not releasing highlights of ${his} sex life.`);
-			r.push(
-				App.UI.DOM.link(
-					"Release",
-					() => {
-						slave.porn.feed = 1;
-						refresh();
-					}
-				)
-			);
-			App.Events.addNode(el, r, "div");
 		} else {
-			r = [];
-			r.push(`The media hub is releasing highlights of ${his} sex life`);
-			if (slave.porn.spending < 500) {
-				r.push(`to those who can find it.`);
-			} else if (slave.porn.spending < 2500) {
-				r.push(`on several websites.`);
-			} else if (slave.porn.spending > 5000) {
-				r.push(`through your old distributor.`);
-			} else {
-				r.push(`on many websites.`);
-			}
-			if (slave.porn.spending === 0) {
-				linkArray = [];
-				linkArray.push(
+			if (slave.porn.feed === 0) {
+				r = [];
+				r.push(`The media hub is not releasing highlights of ${his} sex life.`);
+				r.push(
 					App.UI.DOM.link(
-						"Halt",
+						"Release",
 						() => {
-							slave.porn.feed = 0;
-							slave.porn.focus = "none";
+							slave.porn.feed = 1;
 							refresh();
 						}
 					)
 				);
-				linkArray.push(
-					App.UI.DOM.link(
-						"Publicize",
-						() => {
-							slave.porn.spending += 1000;
-							refresh();
-						},
-						[],
-						"",
-						`Will cost ${cashFormat(1000)} weekly.`
-					)
-				);
-				r.push(App.UI.DOM.generateLinksStrip(linkArray));
 				App.Events.addNode(el, r, "div");
 			} else {
-				r.push(
-					App.UI.DOM.makeTextBox(
-						slave.porn.spending,
-						v => {
-							slave.porn.spending = v;
-						},
-						true
-					)
-				);
-				r.push(`weekly is spent to publicize them.`);
-
-				linkArray = [];
-				linkArray.push(
-					App.UI.DOM.link(
-						"Halt",
-						() => {
-							slave.porn.spending = 0;
-							slave.porn.feed = 0;
-							slave.porn.focus = "none";
-							V.PCSlutContacts = 1;
-							refresh();
-						}
-					)
-				);
-				if (slave.porn.spending <= 4000) {
+				r = [];
+				r.push(`The media hub is releasing highlights of ${his} sex life`);
+				if (slave.porn.spending < 500) {
+					r.push(`to those who can find it.`);
+				} else if (slave.porn.spending < 2500) {
+					r.push(`on several websites.`);
+				} else if (slave.porn.spending > 5000) {
+					r.push(`through your old distributor.`);
+				} else {
+					r.push(`on many websites.`);
+				}
+				if (slave.porn.spending === 0) {
+					linkArray = [];
 					linkArray.push(
 						App.UI.DOM.link(
-							"Increase",
+							"Halt",
+							() => {
+								slave.porn.feed = 0;
+								slave.porn.focus = "none";
+								refresh();
+							}
+						)
+					);
+					linkArray.push(
+						App.UI.DOM.link(
+							"Publicize",
 							() => {
 								slave.porn.spending += 1000;
 								refresh();
 							},
 							[],
 							"",
-							`Spending more than ${cashFormat(5000)} weekly will have no effect.`
+							`Will cost ${cashFormat(1000)} weekly.`
 						)
 					);
-				}
-				linkArray.push(
-					App.UI.DOM.link(
-						"Decrease",
-						() => {
-							slave.porn.spending -= 1000;
-							refresh();
-						},
-						[],
-						"",
-						`Will cost ${cashFormat(1000)} weekly.`
-					)
-				);
-				r.push(App.UI.DOM.generateLinksStrip(linkArray));
-				App.Events.addNode(el, r, "div");
+					r.push(App.UI.DOM.generateLinksStrip(linkArray));
+					App.Events.addNode(el, r, "div");
+				} else {
+					r.push(
+						App.UI.DOM.makeTextBox(
+							slave.porn.spending,
+							v => {
+								slave.porn.spending = v;
+							},
+							true
+						)
+					);
+					r.push(`weekly is spent to publicize them.`);
 
-				if (V.PC.career === "escort" || V.PC.career === "prostitute" || V.PC.career === "child prostitute") {
-					r = [];
-					if (V.PC.career === "escort") {
-						r.push(`You retain some contacts from your past life in the industry that may be willing to cut you some discounts should you return to it.`);
-					} else {
-						r.push(`You were approached in the past to star in some adult films and they may be willing to cut you some discounts should you accept their offer.`);
-					}
-					if (V.PCSlutContacts !== 2) {
-						r.push(`You are not baring your body for all to see.`);
-						r.push(
-							App.UI.DOM.link(
-								`Star in porn for a discount`,
-								() => {
-									V.PCSlutContacts = 2;
-									refresh();
-								}
-							)
-						);
-					} else {
-						if (V.PC.career === "escort") {
-							r.push(`You are starring in hardcore porn once more.`);
-						} else if (V.PC.actualAge < V.minimumSlaveAge) {
-							r.push(`You are taking part in porn that may disturb people.`);
-						} else {
-							r.push(`You are starring in some hardcore porn.`);
-						}
-						r.push(
+					linkArray = [];
+					linkArray.push(
+						App.UI.DOM.link(
+							"Halt",
+							() => {
+								slave.porn.spending = 0;
+								slave.porn.feed = 0;
+								slave.porn.focus = "none";
+								refresh();
+							}
+						)
+					);
+					if (slave.porn.spending <= 4000) {
+						linkArray.push(
 							App.UI.DOM.link(
-								`Stop doing porn for a discount`,
+								"Increase",
 								() => {
-									V.PCSlutContacts = 1;
+									slave.porn.spending += 1000;
 									refresh();
-								}
+								},
+								[],
+								"",
+								`Spending more than ${cashFormat(5000)} weekly will have no effect.`
 							)
 						);
 					}
+					linkArray.push(
+						App.UI.DOM.link(
+							"Decrease",
+							() => {
+								slave.porn.spending -= 1000;
+								refresh();
+							}
+						)
+					);
+					r.push(App.UI.DOM.generateLinksStrip(linkArray));
 					App.Events.addNode(el, r, "div");
 				}
-			}
-			if (V.studioFeed === 1) {
-				r = [];
-				if (slave.porn.viewerCount < 100) {
-					r.push(`${He} lacks the fame in porn needed to discern what ${his} feed is getting tagged as.`);
-				} else {
-					if (slave.porn.prestige > 0) {
-						r.push(`${He} is known for ${slave.porn.fameType === "generic" ? `standard, vanilla` : slave.porn.fameType} porn${(slave.porn.prestige > 1) ? ` and viewers have grown to expect it from ${him}` : ``}.`);
-					}
-					if (slave.porn.focus === "none") {
-						r.push(`You are allowing ${his} viewers to guide the direction of ${his} content.`);
+				if (V.studioFeed === 1) {
+					if (slave.porn.viewerCount < 100) {
+						r.push(`${He} lacks the fame in porn needed to discern what ${his} feed is getting tagged as.`);
 					} else {
-						r.push(`You are focusing attention on the ${slave.porn.focus} aspect of ${his} content.`);
+						r = [];
+						if (slave.porn.prestige > 0) {
+							r.push(`${He} is known for ${slave.porn.fameType === "generic" ? `standard, vanilla` : slave.porn.fameType} porn${(slave.porn.prestige > 1) ? ` and viewers have grown to expect it from ${him}` : ``}.`);
+						}
+						if (slave.porn.focus === "none") {
+							r.push(`You are allowing ${his} viewers to guide the direction of ${his} content.`);
+						} else {
+							r.push(`You are focusing attention on the ${slave.porn.focus} aspect of ${his} content.`);
+						}
+						r.push(App.Porn.genreChoiceLinks("Slave Interact", slave));
+						App.Events.addNode(el, r, "div");
 					}
-					r.push(App.Porn.genreChoiceLinks("Slave Interact", slave));
 				}
-				App.Events.addNode(el, r, "div");
 			}
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.combineNodes(App.Porn.makeFameProgressChart(slave)));
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.combineNodes("Current viewership breakdown:", App.Porn.makeViewershipChart(slave)));
 		}
 	}
 	App.UI.DOM.appendNewElement("h3", el, "Financial");
diff --git a/src/interaction/siWardrobe.js b/src/interaction/siWardrobe.js
index 49c5533360ee4824d881d2a95a77fab856204beb..59e81ea3c8a644f3ee184e4bdfab9f33dfd63ddf 100644
--- a/src/interaction/siWardrobe.js
+++ b/src/interaction/siWardrobe.js
@@ -856,7 +856,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		switch (category) {
 			case "clothes":
 				if (itemName === "no clothing") {
-					desc.push("Increases devotion for resistant humiliations fetishists and nymphos.");
+					desc.push("Increases devotion for resistant slaves, humiliation fetishists, submissives and nymphos.");
 				} else if (item) {
 					switch (item.exposure) {
 						case 4:
diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js
index de7d23f5e493a7c68ae95f163e849d437d912989..7d87dcc00f9af106f2a737a8e13b15498ba945e0 100644
--- a/src/js/DefaultRules.js
+++ b/src/js/DefaultRules.js
@@ -1655,15 +1655,15 @@ globalThis.DefaultRules = function(slave) {
 			if (!isAmputee(slave) && App.RA.shallShrink(slave.muscles, rule.muscles, 8)) {
 				if (slave.diet !== "slimming") {
 					slave.diet = "slimming";
-					message(`${slave.slaveName} has been put on a slimming exercise regime.`, sourceRecord.muscles);
+					message(`${slave.slaveName} has been put on a slimming exercise regime.`, sourceRecord.muscles.val);
 				}
 			} else if (!isAmputee(slave) && App.RA.shallGrow(slave.muscles, rule.muscles, 2)) {
 				if (slave.diet !== "muscle building") {
 					slave.diet = "muscle building";
-					message(`${slave.slaveName} has been put on a muscle building exercise regime.`, sourceRecord.muscles);
+					message(`${slave.slaveName} has been put on a muscle building exercise regime.`, sourceRecord.muscles.val);
 				}
 			} else if (!isAmputee(slave) && ["slimming", "muscle building"].includes(slave.diet)) {
-				message(`${slave.slaveName} is at the target musculature, so ${his} diet has been normalized.`, sourceRecord.muscles);
+				message(`${slave.slaveName} is at the target musculature, so ${his} diet has been normalized.`, sourceRecord.diet);
 				dietRule(slave, rule);
 			} else {
 				dietRule(slave, rule);
@@ -1759,10 +1759,10 @@ globalThis.DefaultRules = function(slave) {
 		function dietPills(slave) {
 			if (slave.drugs === "appetite suppressors" && slave.diet !== "restricted") {
 				slave.drugs = "no drugs";
-				message(`${slave.slaveName} no longer needs to lose weight, so ${he}'s no longer being given appetite suppressors.`, [sourceRecord.diet, sourceRecord.weight.max, sourceRecord.weight.min]);
+				message(`${slave.slaveName} no longer needs to lose weight, so ${he}'s no longer being given appetite suppressors.`, [sourceRecord.diet, sourceRecord.weight?.max, sourceRecord.weight?.min]);
 			} else if (slave.diet === "restricted" && V.arcologies[0].FSSlimnessEnthusiastResearch === 1 && slave.drugs === "no drugs") {
 				slave.drugs = "appetite suppressors";
-				message(`${slave.slaveName} needs to lose weight, so ${he} will be given weight loss pills.`, [sourceRecord.diet, sourceRecord.weight.max, sourceRecord.weight.min]);
+				message(`${slave.slaveName} needs to lose weight, so ${he} will be given weight loss pills.`, [sourceRecord.diet, sourceRecord.weight?.max, sourceRecord.weight?.min]);
 			}
 		}
 	}
@@ -1851,13 +1851,13 @@ globalThis.DefaultRules = function(slave) {
 	 */
 	function ProcessPregnancyDrugs(slave, rule) {
 		if (slave.pregKnown === 1 && rule.pregSpeed !== null && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset") && slave.indentureRestrictions < 1 && slave.broodmother === 0) {
-			if (rule.pregSpeed === "slow" && slave.preg < slave.pregData.normalBirth) {
+			if (rule.pregSpeed === "slow" && slave.preg < slave.pregData.normalBirth && slave.pregControl !== "slow gestation") {
 				slave.pregControl = "slow gestation";
 				message(`${slave.slaveName} is pregnant, so ${he} has been put on the gestation slowing agents.`, sourceRecord.pregSpeed);
-			} else if (rule.pregSpeed === "fast" && slave.preg < slave.pregData.normalBirth && slave.health.condition > -50) {
+			} else if (rule.pregSpeed === "fast" && slave.preg < slave.pregData.normalBirth && slave.health.condition > -50 && slave.pregControl !== "speed up") {
 				slave.pregControl = "speed up";
 				message(`${slave.slaveName} is pregnant, so ${he} has been put on rapid gestation agents. CAUTION! Can be dangerous. Clinic supervision is recommended.`, sourceRecord.pregSpeed);
-			} else if (rule.pregSpeed === "suppress" && slave.preg >= slave.pregData.minLiveBirth && slave.health.condition > -50) {
+			} else if (rule.pregSpeed === "suppress" && slave.preg >= slave.pregData.minLiveBirth && slave.health.condition > -50 && slave.pregControl !== "labor suppressors") {
 				slave.pregControl = "labor suppressors";
 				message(`${slave.slaveName} is ready to birth, so ${he} has been put on labor suppressing agents.`, sourceRecord.pregSpeed);
 			} else if (rule.pregSpeed === "stimulate" && slave.preg > slave.pregData.normalBirth - 2 && slave.preg > slave.pregData.minLiveBirth && slave.health.condition > -50) {
diff --git a/src/js/birth/birth.js b/src/js/birth/birth.js
index bf57b8a58cfe61c7dd16dda79fd081086e0ea4ba..8114ebdf66c5fab21381bddb088a89a34519f44a 100644
--- a/src/js/birth/birth.js
+++ b/src/js/birth/birth.js
@@ -3671,7 +3671,7 @@ globalThis.birth = function(slave, {birthStorm = false, cSection = false, artRen
 
 				case Job.MADAM:
 					if (random(1, 20) > suddenBirth) {
-						r.push(`${He} heads to a private room in the back of the club accompanied by an influential patron. ${He} settles ${himself} onto his lap and begins working on birthing ${firstText} baby,`);
+						r.push(`${He} heads to a private room in the back of the brothel accompanied by an influential patron. ${He} settles ${himself} onto his lap and begins working on birthing ${firstText} baby,`);
 						if (slave.geneticQuirks.uterineHypersensitivity === 2) {
 							r.push(`convulsing with orgasms in the process and`);
 						}
diff --git a/src/js/dTree.min.js b/src/js/dTree.min.js
deleted file mode 100644
index 763229745b4f0a14cca35e4266268d9882de2a77..0000000000000000000000000000000000000000
--- a/src/js/dTree.min.js
+++ /dev/null
@@ -1,151 +0,0 @@
-/* This is the minified version of lodash, d3 and dTree */
-;
-(function (window, define, exports) {
-/**
-* @license
-* Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
-*/
-;(function(){function n(n,t){return n.set(t[0],t[1]),n}function t(n,t){return n.add(t),n}function r(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function e(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u<i;){var o=n[u];t(e,o,r(o),n)}return e}function u(n,t){for(var r=-1,e=null==n?0:n.length;++r<e&&false!==t(n[r],r,n););return n}function i(n,t){for(var r=null==n?0:n.length;r--&&false!==t(n[r],r,n););
-return n}function o(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(!t(n[r],r,n))return false;return true}function f(n,t){for(var r=-1,e=null==n?0:n.length,u=0,i=[];++r<e;){var o=n[r];t(o,r,n)&&(i[u++]=o)}return i}function c(n,t){return!(null==n||!n.length)&&-1<d(n,t,0)}function a(n,t,r){for(var e=-1,u=null==n?0:n.length;++e<u;)if(r(t,n[e]))return true;return false}function l(n,t){for(var r=-1,e=null==n?0:n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function s(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];
-return n}function h(n,t,r,e){var u=-1,i=null==n?0:n.length;for(e&&i&&(r=n[++u]);++u<i;)r=t(r,n[u],u,n);return r}function p(n,t,r,e){var u=null==n?0:n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function _(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(t(n[r],r,n))return true;return false}function v(n,t,r){var e;return r(n,function(n,r,u){if(t(n,r,u))return e=r,false}),e}function g(n,t,r,e){var u=n.length;for(r+=e?1:-1;e?r--:++r<u;)if(t(n[r],r,n))return r;return-1}function d(n,t,r){if(t===t)n:{
---r;for(var e=n.length;++r<e;)if(n[r]===t){n=r;break n}n=-1}else n=g(n,b,r);return n}function y(n,t,r,e){--r;for(var u=n.length;++r<u;)if(e(n[r],t))return r;return-1}function b(n){return n!==n}function x(n,t){var r=null==n?0:n.length;return r?k(n,t)/r:P}function j(n){return function(t){return null==t?F:t[n]}}function w(n){return function(t){return null==n?F:n[t]}}function m(n,t,r,e,u){return u(n,function(n,u,i){r=e?(e=false,n):t(r,n,u,i)}),r}function A(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;
-return n}function k(n,t){for(var r,e=-1,u=n.length;++e<u;){var i=t(n[e]);i!==F&&(r=r===F?i:r+i)}return r}function E(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function O(n,t){return l(t,function(t){return[t,n[t]]})}function S(n){return function(t){return n(t)}}function I(n,t){return l(t,function(t){return n[t]})}function R(n,t){return n.has(t)}function z(n,t){for(var r=-1,e=n.length;++r<e&&-1<d(t,n[r],0););return r}function W(n,t){for(var r=n.length;r--&&-1<d(t,n[r],0););return r}function B(n){
-return"\\"+Tn[n]}function L(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function U(n,t){return function(r){return n(t(r))}}function C(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r];o!==t&&"__lodash_placeholder__"!==o||(n[r]="__lodash_placeholder__",i[u++]=r)}return i}function D(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function M(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=[n,n]}),r}function T(n){if(Bn.test(n)){
-for(var t=zn.lastIndex=0;zn.test(n);)++t;n=t}else n=tt(n);return n}function $(n){return Bn.test(n)?n.match(zn)||[]:n.split("")}var F,N=1/0,P=NaN,Z=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],q=/\b__p\+='';/g,V=/\b(__p\+=)''\+/g,K=/(__e\(.*?\)|\b__t\))\+'';/g,G=/&(?:amp|lt|gt|quot|#39);/g,H=/[&<>"']/g,J=RegExp(G.source),Y=RegExp(H.source),Q=/<%-([\s\S]+?)%>/g,X=/<%([\s\S]+?)%>/g,nn=/<%=([\s\S]+?)%>/g,tn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,rn=/^\w*$/,en=/^\./,un=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,on=/[\\^$.*+?()[\]{}|]/g,fn=RegExp(on.source),cn=/^\s+|\s+$/g,an=/^\s+/,ln=/\s+$/,sn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,hn=/\{\n\/\* \[wrapped with (.+)\] \*/,pn=/,? & /,_n=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,vn=/\\(\\)?/g,gn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,dn=/\w*$/,yn=/^[-+]0x[0-9a-f]+$/i,bn=/^0b[01]+$/i,xn=/^\[object .+?Constructor\]$/,jn=/^0o[0-7]+$/i,wn=/^(?:0|[1-9]\d*)$/,mn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,An=/($^)/,kn=/['\n\r\u2028\u2029\\]/g,En="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",On="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+En,Sn="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",In=RegExp("['\u2019]","g"),Rn=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),zn=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+Sn+En,"g"),Wn=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)|\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)|\\d+",On].join("|"),"g"),Bn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),Ln=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Un="Array Buffer DataView Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Promise RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Cn={};
-Cn["[object Float32Array]"]=Cn["[object Float64Array]"]=Cn["[object Int8Array]"]=Cn["[object Int16Array]"]=Cn["[object Int32Array]"]=Cn["[object Uint8Array]"]=Cn["[object Uint8ClampedArray]"]=Cn["[object Uint16Array]"]=Cn["[object Uint32Array]"]=true,Cn["[object Arguments]"]=Cn["[object Array]"]=Cn["[object ArrayBuffer]"]=Cn["[object Boolean]"]=Cn["[object DataView]"]=Cn["[object Date]"]=Cn["[object Error]"]=Cn["[object Function]"]=Cn["[object Map]"]=Cn["[object Number]"]=Cn["[object Object]"]=Cn["[object RegExp]"]=Cn["[object Set]"]=Cn["[object String]"]=Cn["[object WeakMap]"]=false;
-var Dn={};Dn["[object Arguments]"]=Dn["[object Array]"]=Dn["[object ArrayBuffer]"]=Dn["[object DataView]"]=Dn["[object Boolean]"]=Dn["[object Date]"]=Dn["[object Float32Array]"]=Dn["[object Float64Array]"]=Dn["[object Int8Array]"]=Dn["[object Int16Array]"]=Dn["[object Int32Array]"]=Dn["[object Map]"]=Dn["[object Number]"]=Dn["[object Object]"]=Dn["[object RegExp]"]=Dn["[object Set]"]=Dn["[object String]"]=Dn["[object Symbol]"]=Dn["[object Uint8Array]"]=Dn["[object Uint8ClampedArray]"]=Dn["[object Uint16Array]"]=Dn["[object Uint32Array]"]=true,
-Dn["[object Error]"]=Dn["[object Function]"]=Dn["[object WeakMap]"]=false;var Mn,Tn={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$n=parseFloat,Fn=parseInt,Nn=typeof global=="object"&&global&&global.Object===Object&&global,Pn=typeof self=="object"&&self&&self.Object===Object&&self,Zn=Nn||Pn||Function("return this")(),qn=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Vn=qn&&typeof module=="object"&&module&&!module.nodeType&&module,Kn=Vn&&Vn.exports===qn,Gn=Kn&&Nn.process;
-n:{try{Mn=Gn&&Gn.binding&&Gn.binding("util");break n}catch(n){}Mn=void 0}var Hn=Mn&&Mn.isArrayBuffer,Jn=Mn&&Mn.isDate,Yn=Mn&&Mn.isMap,Qn=Mn&&Mn.isRegExp,Xn=Mn&&Mn.isSet,nt=Mn&&Mn.isTypedArray,tt=j("length"),rt=w({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I",
-"\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C",
-"\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i",
-"\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S",
-"\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe",
-"\u0149":"'n","\u017f":"s"}),et=w({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}),ut=w({"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'"}),it=function w(En){function On(n){if(xu(n)&&!af(n)&&!(n instanceof Mn)){if(n instanceof zn)return n;if(ci.call(n,"__wrapped__"))return Pe(n)}return new zn(n)}function Sn(){}function zn(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=F}function Mn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,
-this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Tn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Nn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Pn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function qn(n){var t=-1,r=null==n?0:n.length;for(this.__data__=new Pn;++t<r;)this.add(n[t])}function Vn(n){
-this.size=(this.__data__=new Nn(n)).size}function Gn(n,t){var r,e=af(n),u=!e&&cf(n),i=!e&&!u&&sf(n),o=!e&&!u&&!i&&gf(n),u=(e=e||u||i||o)?E(n.length,ri):[],f=u.length;for(r in n)!t&&!ci.call(n,r)||e&&("length"==r||i&&("offset"==r||"parent"==r)||o&&("buffer"==r||"byteLength"==r||"byteOffset"==r)||Re(r,f))||u.push(r);return u}function tt(n){var t=n.length;return t?n[cr(0,t-1)]:F}function ot(n,t){return Te(Mr(n),gt(t,0,n.length))}function ft(n){return Te(Mr(n))}function ct(n,t,r){(r===F||hu(n[t],r))&&(r!==F||t in n)||_t(n,t,r);
-}function at(n,t,r){var e=n[t];ci.call(n,t)&&hu(e,r)&&(r!==F||t in n)||_t(n,t,r)}function lt(n,t){for(var r=n.length;r--;)if(hu(n[r][0],t))return r;return-1}function st(n,t,r,e){return oo(n,function(n,u,i){t(e,n,r(n),i)}),e}function ht(n,t){return n&&Tr(t,Lu(t),n)}function pt(n,t){return n&&Tr(t,Uu(t),n)}function _t(n,t,r){"__proto__"==t&&Ei?Ei(n,t,{configurable:true,enumerable:true,value:r,writable:true}):n[t]=r}function vt(n,t){for(var r=-1,e=t.length,u=Hu(e),i=null==n;++r<e;)u[r]=i?F:Wu(n,t[r]);return u;
-}function gt(n,t,r){return n===n&&(r!==F&&(n=n<=r?n:r),t!==F&&(n=n>=t?n:t)),n}function dt(n,t,r,e,i,o){var f,c=1&t,a=2&t,l=4&t;if(r&&(f=i?r(n,e,i,o):r(n)),f!==F)return f;if(!bu(n))return n;if(e=af(n)){if(f=Ee(n),!c)return Mr(n,f)}else{var s=yo(n),h="[object Function]"==s||"[object GeneratorFunction]"==s;if(sf(n))return Wr(n,c);if("[object Object]"==s||"[object Arguments]"==s||h&&!i){if(f=a||h?{}:Oe(n),!c)return a?Fr(n,pt(f,n)):$r(n,ht(f,n))}else{if(!Dn[s])return i?n:{};f=Se(n,s,dt,c)}}if(o||(o=new Vn),
-i=o.get(n))return i;o.set(n,f);var a=l?a?ye:de:a?Uu:Lu,p=e?F:a(n);return u(p||n,function(e,u){p&&(u=e,e=n[u]),at(f,u,dt(e,t,r,u,n,o))}),f}function yt(n){var t=Lu(n);return function(r){return bt(r,n,t)}}function bt(n,t,r){var e=r.length;if(null==n)return!e;for(n=ni(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===F&&!(u in n)||!i(o))return false}return true}function xt(n,t,r){if(typeof n!="function")throw new ei("Expected a function");return jo(function(){n.apply(F,r)},t)}function jt(n,t,r,e){var u=-1,i=c,o=true,f=n.length,s=[],h=t.length;
-if(!f)return s;r&&(t=l(t,S(r))),e?(i=a,o=false):200<=t.length&&(i=R,o=false,t=new qn(t));n:for(;++u<f;){var p=n[u],_=null==r?p:r(p),p=e||0!==p?p:0;if(o&&_===_){for(var v=h;v--;)if(t[v]===_)continue n;s.push(p)}else i(t,_,e)||s.push(p)}return s}function wt(n,t){var r=true;return oo(n,function(n,e,u){return r=!!t(n,e,u)}),r}function mt(n,t,r){for(var e=-1,u=n.length;++e<u;){var i=n[e],o=t(i);if(null!=o&&(f===F?o===o&&!Au(o):r(o,f)))var f=o,c=i}return c}function At(n,t){var r=[];return oo(n,function(n,e,u){
-t(n,e,u)&&r.push(n)}),r}function kt(n,t,r,e,u){var i=-1,o=n.length;for(r||(r=Ie),u||(u=[]);++i<o;){var f=n[i];0<t&&r(f)?1<t?kt(f,t-1,r,e,u):s(u,f):e||(u[u.length]=f)}return u}function Et(n,t){return n&&co(n,t,Lu)}function Ot(n,t){return n&&ao(n,t,Lu)}function St(n,t){return f(t,function(t){return gu(n[t])})}function It(n,t){t=Rr(t,n);for(var r=0,e=t.length;null!=n&&r<e;)n=n[$e(t[r++])];return r&&r==e?n:F}function Rt(n,t,r){return t=t(n),af(n)?t:s(t,r(n))}function zt(n){if(null==n)n=n===F?"[object Undefined]":"[object Null]";else if(ki&&ki in ni(n)){
-var t=ci.call(n,ki),r=n[ki];try{n[ki]=F;var e=true}catch(n){}var u=si.call(n);e&&(t?n[ki]=r:delete n[ki]),n=u}else n=si.call(n);return n}function Wt(n,t){return n>t}function Bt(n,t){return null!=n&&ci.call(n,t)}function Lt(n,t){return null!=n&&t in ni(n)}function Ut(n,t,r){for(var e=r?a:c,u=n[0].length,i=n.length,o=i,f=Hu(i),s=1/0,h=[];o--;){var p=n[o];o&&t&&(p=l(p,S(t))),s=Mi(p.length,s),f[o]=!r&&(t||120<=u&&120<=p.length)?new qn(o&&p):F}var p=n[0],_=-1,v=f[0];n:for(;++_<u&&h.length<s;){var g=p[_],d=t?t(g):g,g=r||0!==g?g:0;
-if(v?!R(v,d):!e(h,d,r)){for(o=i;--o;){var y=f[o];if(y?!R(y,d):!e(n[o],d,r))continue n}v&&v.push(d),h.push(g)}}return h}function Ct(n,t,r){var e={};return Et(n,function(n,u,i){t(e,r(n),u,i)}),e}function Dt(n,t,e){return t=Rr(t,n),n=2>t.length?n:It(n,vr(t,0,-1)),t=null==n?n:n[$e(Ge(t))],null==t?F:r(t,n,e)}function Mt(n){return xu(n)&&"[object Arguments]"==zt(n)}function Tt(n){return xu(n)&&"[object ArrayBuffer]"==zt(n)}function $t(n){return xu(n)&&"[object Date]"==zt(n)}function Ft(n,t,r,e,u){if(n===t)t=true;else if(null==n||null==t||!xu(n)&&!xu(t))t=n!==n&&t!==t;else n:{
-var i=af(n),o=af(t),f=i?"[object Array]":yo(n),c=o?"[object Array]":yo(t),f="[object Arguments]"==f?"[object Object]":f,c="[object Arguments]"==c?"[object Object]":c,a="[object Object]"==f,o="[object Object]"==c;if((c=f==c)&&sf(n)){if(!sf(t)){t=false;break n}i=true,a=false}if(c&&!a)u||(u=new Vn),t=i||gf(n)?_e(n,t,r,e,Ft,u):ve(n,t,f,r,e,Ft,u);else{if(!(1&r)&&(i=a&&ci.call(n,"__wrapped__"),f=o&&ci.call(t,"__wrapped__"),i||f)){n=i?n.value():n,t=f?t.value():t,u||(u=new Vn),t=Ft(n,t,r,e,u);break n}if(c)t:if(u||(u=new Vn),
-i=1&r,f=de(n),o=f.length,c=de(t).length,o==c||i){for(a=o;a--;){var l=f[a];if(!(i?l in t:ci.call(t,l))){t=false;break t}}if((c=u.get(n))&&u.get(t))t=c==t;else{c=true,u.set(n,t),u.set(t,n);for(var s=i;++a<o;){var l=f[a],h=n[l],p=t[l];if(e)var _=i?e(p,h,l,t,n,u):e(h,p,l,n,t,u);if(_===F?h!==p&&!Ft(h,p,r,e,u):!_){c=false;break}s||(s="constructor"==l)}c&&!s&&(r=n.constructor,e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(c=false)),
-u.delete(n),u.delete(t),t=c}}else t=false;else t=false}}return t}function Nt(n){return xu(n)&&"[object Map]"==yo(n)}function Pt(n,t,r,e){var u=r.length,i=u,o=!e;if(null==n)return!i;for(n=ni(n);u--;){var f=r[u];if(o&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return false}for(;++u<i;){var f=r[u],c=f[0],a=n[c],l=f[1];if(o&&f[2]){if(a===F&&!(c in n))return false}else{if(f=new Vn,e)var s=e(a,l,c,n,t,f);if(s===F?!Ft(l,a,3,e,f):!s)return false}}return true}function Zt(n){return!(!bu(n)||li&&li in n)&&(gu(n)?_i:xn).test(Fe(n))}function qt(n){
-return xu(n)&&"[object RegExp]"==zt(n)}function Vt(n){return xu(n)&&"[object Set]"==yo(n)}function Kt(n){return xu(n)&&yu(n.length)&&!!Cn[zt(n)]}function Gt(n){return typeof n=="function"?n:null==n?Nu:typeof n=="object"?af(n)?Xt(n[0],n[1]):Qt(n):Vu(n)}function Ht(n){if(!Le(n))return Ci(n);var t,r=[];for(t in ni(n))ci.call(n,t)&&"constructor"!=t&&r.push(t);return r}function Jt(n,t){return n<t}function Yt(n,t){var r=-1,e=pu(n)?Hu(n.length):[];return oo(n,function(n,u,i){e[++r]=t(n,u,i)}),e}function Qt(n){
-var t=me(n);return 1==t.length&&t[0][2]?Ue(t[0][0],t[0][1]):function(r){return r===n||Pt(r,n,t)}}function Xt(n,t){return We(n)&&t===t&&!bu(t)?Ue($e(n),t):function(r){var e=Wu(r,n);return e===F&&e===t?Bu(r,n):Ft(t,e,3)}}function nr(n,t,r,e,u){n!==t&&co(t,function(i,o){if(bu(i)){u||(u=new Vn);var f=u,c=n[o],a=t[o],l=f.get(a);if(l)ct(n,o,l);else{var l=e?e(c,a,o+"",n,t,f):F,s=l===F;if(s){var h=af(a),p=!h&&sf(a),_=!h&&!p&&gf(a),l=a;h||p||_?af(c)?l=c:_u(c)?l=Mr(c):p?(s=false,l=Wr(a,true)):_?(s=false,l=Lr(a,true)):l=[]:wu(a)||cf(a)?(l=c,
-cf(c)?l=Ru(c):(!bu(c)||r&&gu(c))&&(l=Oe(a))):s=false}s&&(f.set(a,l),nr(l,a,r,e,f),f.delete(a)),ct(n,o,l)}}else f=e?e(n[o],i,o+"",n,t,u):F,f===F&&(f=i),ct(n,o,f)},Uu)}function tr(n,t){var r=n.length;if(r)return t+=0>t?r:0,Re(t,r)?n[t]:F}function rr(n,t,r){var e=-1;return t=l(t.length?t:[Nu],S(je())),n=Yt(n,function(n){return{a:l(t,function(t){return t(n)}),b:++e,c:n}}),A(n,function(n,t){var e;n:{e=-1;for(var u=n.a,i=t.a,o=u.length,f=r.length;++e<o;){var c=Ur(u[e],i[e]);if(c){e=e>=f?c:c*("desc"==r[e]?-1:1);
-break n}}e=n.b-t.b}return e})}function er(n,t){return ur(n,t,function(t,r){return Bu(n,r)})}function ur(n,t,r){for(var e=-1,u=t.length,i={};++e<u;){var o=t[e],f=It(n,o);r(f,o)&&pr(i,Rr(o,n),f)}return i}function ir(n){return function(t){return It(t,n)}}function or(n,t,r,e){var u=e?y:d,i=-1,o=t.length,f=n;for(n===t&&(t=Mr(t)),r&&(f=l(n,S(r)));++i<o;)for(var c=0,a=t[i],a=r?r(a):a;-1<(c=u(f,a,c,e));)f!==n&&wi.call(f,c,1),wi.call(n,c,1);return n}function fr(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];
-if(r==e||u!==i){var i=u;Re(u)?wi.call(n,u,1):mr(n,u)}}}function cr(n,t){return n+zi(Fi()*(t-n+1))}function ar(n,t){var r="";if(!n||1>t||9007199254740991<t)return r;do t%2&&(r+=n),(t=zi(t/2))&&(n+=n);while(t);return r}function lr(n,t){return wo(Ce(n,t,Nu),n+"")}function sr(n){return tt(Du(n))}function hr(n,t){var r=Du(n);return Te(r,gt(t,0,r.length))}function pr(n,t,r,e){if(!bu(n))return n;t=Rr(t,n);for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++u<i;){var c=$e(t[u]),a=r;if(u!=o){var l=f[c],a=e?e(l,c,f):F;
-a===F&&(a=bu(l)?l:Re(t[u+1])?[]:{})}at(f,c,a),f=f[c]}return n}function _r(n){return Te(Du(n))}function vr(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Hu(u);++e<u;)r[e]=n[e+t];return r}function gr(n,t){var r;return oo(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function dr(n,t,r){var e=0,u=null==n?e:n.length;if(typeof t=="number"&&t===t&&2147483647>=u){for(;e<u;){var i=e+u>>>1,o=n[i];null!==o&&!Au(o)&&(r?o<=t:o<t)?e=i+1:u=i}return u}return yr(n,t,Nu,r);
-}function yr(n,t,r,e){t=r(t);for(var u=0,i=null==n?0:n.length,o=t!==t,f=null===t,c=Au(t),a=t===F;u<i;){var l=zi((u+i)/2),s=r(n[l]),h=s!==F,p=null===s,_=s===s,v=Au(s);(o?e||_:a?_&&(e||h):f?_&&h&&(e||!p):c?_&&h&&!p&&(e||!v):p||v?0:e?s<=t:s<t)?u=l+1:i=l}return Mi(i,4294967294)}function br(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r],f=t?t(o):o;if(!r||!hu(f,c)){var c=f;i[u++]=0===o?0:o}}return i}function xr(n){return typeof n=="number"?n:Au(n)?P:+n}function jr(n){if(typeof n=="string")return n;
-if(af(n))return l(n,jr)+"";if(Au(n))return uo?uo.call(n):"";var t=n+"";return"0"==t&&1/n==-N?"-0":t}function wr(n,t,r){var e=-1,u=c,i=n.length,o=true,f=[],l=f;if(r)o=false,u=a;else if(200<=i){if(u=t?null:po(n))return D(u);o=false,u=R,l=new qn}else l=t?[]:f;n:for(;++e<i;){var s=n[e],h=t?t(s):s,s=r||0!==s?s:0;if(o&&h===h){for(var p=l.length;p--;)if(l[p]===h)continue n;t&&l.push(h),f.push(s)}else u(l,h,r)||(l!==f&&l.push(h),f.push(s))}return f}function mr(n,t){return t=Rr(t,n),n=2>t.length?n:It(n,vr(t,0,-1)),
-null==n||delete n[$e(Ge(t))]}function Ar(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++i<u)&&t(n[i],i,n););return r?vr(n,e?0:i,e?i+1:u):vr(n,e?i+1:0,e?u:i)}function kr(n,t){var r=n;return r instanceof Mn&&(r=r.value()),h(t,function(n,t){return t.func.apply(t.thisArg,s([n],t.args))},r)}function Er(n,t,r){var e=n.length;if(2>e)return e?wr(n[0]):[];for(var u=-1,i=Hu(e);++u<e;)for(var o=n[u],f=-1;++f<e;)f!=u&&(i[u]=jt(i[u]||o,n[f],t,r));return wr(kt(i,1),t,r)}function Or(n,t,r){for(var e=-1,u=n.length,i=t.length,o={};++e<u;)r(o,n[e],e<i?t[e]:F);
-return o}function Sr(n){return _u(n)?n:[]}function Ir(n){return typeof n=="function"?n:Nu}function Rr(n,t){return af(n)?n:We(n,t)?[n]:mo(zu(n))}function zr(n,t,r){var e=n.length;return r=r===F?e:r,!t&&r>=e?n:vr(n,t,r)}function Wr(n,t){if(t)return n.slice();var r=n.length,r=yi?yi(r):new n.constructor(r);return n.copy(r),r}function Br(n){var t=new n.constructor(n.byteLength);return new di(t).set(new di(n)),t}function Lr(n,t){return new n.constructor(t?Br(n.buffer):n.buffer,n.byteOffset,n.length)}function Ur(n,t){
-if(n!==t){var r=n!==F,e=null===n,u=n===n,i=Au(n),o=t!==F,f=null===t,c=t===t,a=Au(t);if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n<t||a&&r&&u&&!e&&!i||f&&r&&u||!o&&u||!c)return-1}return 0}function Cr(n,t,r,e){var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Di(i-o,0),l=Hu(c+a);for(e=!e;++f<c;)l[f]=t[f];for(;++u<o;)(e||u<i)&&(l[r[u]]=n[u]);for(;a--;)l[f++]=n[u++];return l}function Dr(n,t,r,e){var u=-1,i=n.length,o=-1,f=r.length,c=-1,a=t.length,l=Di(i-f,0),s=Hu(l+a);
-for(e=!e;++u<l;)s[u]=n[u];for(l=u;++c<a;)s[l+c]=t[c];for(;++o<f;)(e||u<i)&&(s[l+r[o]]=n[u++]);return s}function Mr(n,t){var r=-1,e=n.length;for(t||(t=Hu(e));++r<e;)t[r]=n[r];return t}function Tr(n,t,r,e){var u=!r;r||(r={});for(var i=-1,o=t.length;++i<o;){var f=t[i],c=e?e(r[f],n[f],f,r,n):F;c===F&&(c=n[f]),u?_t(r,f,c):at(r,f,c)}return r}function $r(n,t){return Tr(n,vo(n),t)}function Fr(n,t){return Tr(n,go(n),t)}function Nr(n,t){return function(r,u){var i=af(r)?e:st,o=t?t():{};return i(r,n,je(u,2),o);
-}}function Pr(n){return lr(function(t,r){var e=-1,u=r.length,i=1<u?r[u-1]:F,o=2<u?r[2]:F,i=3<n.length&&typeof i=="function"?(u--,i):F;for(o&&ze(r[0],r[1],o)&&(i=3>u?F:i,u=1),t=ni(t);++e<u;)(o=r[e])&&n(t,o,e,i);return t})}function Zr(n,t){return function(r,e){if(null==r)return r;if(!pu(r))return n(r,e);for(var u=r.length,i=t?u:-1,o=ni(r);(t?i--:++i<u)&&false!==e(o[i],i,o););return r}}function qr(n){return function(t,r,e){var u=-1,i=ni(t);e=e(t);for(var o=e.length;o--;){var f=e[n?o:++u];if(false===r(i[f],f,i))break;
-}return t}}function Vr(n,t,r){function e(){return(this&&this!==Zn&&this instanceof e?i:n).apply(u?r:this,arguments)}var u=1&t,i=Hr(n);return e}function Kr(n){return function(t){t=zu(t);var r=Bn.test(t)?$(t):F,e=r?r[0]:t.charAt(0);return t=r?zr(r,1).join(""):t.slice(1),e[n]()+t}}function Gr(n){return function(t){return h($u(Tu(t).replace(In,"")),n,"")}}function Hr(n){return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:
-return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=io(n.prototype),t=n.apply(r,t);return bu(t)?t:r}}function Jr(n,t,e){function u(){for(var o=arguments.length,f=Hu(o),c=o,a=xe(u);c--;)f[c]=arguments[c];return c=3>o&&f[0]!==a&&f[o-1]!==a?[]:C(f,a),o-=c.length,o<e?fe(n,t,Xr,u.placeholder,F,f,c,F,F,e-o):r(this&&this!==Zn&&this instanceof u?i:n,this,f);
-}var i=Hr(n);return u}function Yr(n){return function(t,r,e){var u=ni(t);if(!pu(t)){var i=je(r,3);t=Lu(t),r=function(n){return i(u[n],n,u)}}return r=n(t,r,e),-1<r?u[i?t[r]:r]:F}}function Qr(n){return ge(function(t){var r=t.length,e=r,u=zn.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if(typeof i!="function")throw new ei("Expected a function");if(u&&!o&&"wrapper"==be(i))var o=new zn([],true)}for(e=o?e:r;++e<r;)var i=t[e],u=be(i),f="wrapper"==u?_o(i):F,o=f&&Be(f[0])&&424==f[1]&&!f[4].length&&1==f[9]?o[be(f[0])].apply(o,f[3]):1==i.length&&Be(i)?o[u]():o.thru(i);
-return function(){var n=arguments,e=n[0];if(o&&1==n.length&&af(e))return o.plant(e).value();for(var u=0,n=r?t[u].apply(this,n):e;++u<r;)n=t[u].call(this,n);return n}})}function Xr(n,t,r,e,u,i,o,f,c,a){function l(){for(var d=arguments.length,y=Hu(d),b=d;b--;)y[b]=arguments[b];if(_){var x,j=xe(l),b=y.length;for(x=0;b--;)y[b]===j&&++x}if(e&&(y=Cr(y,e,u,_)),i&&(y=Dr(y,i,o,_)),d-=x,_&&d<a)return j=C(y,j),fe(n,t,Xr,l.placeholder,r,y,j,f,c,a-d);if(j=h?r:this,b=p?j[n]:n,d=y.length,f){x=y.length;for(var w=Mi(f.length,x),m=Mr(y);w--;){
-var A=f[w];y[w]=Re(A,x)?m[A]:F}}else v&&1<d&&y.reverse();return s&&c<d&&(y.length=c),this&&this!==Zn&&this instanceof l&&(b=g||Hr(b)),b.apply(j,y)}var s=128&t,h=1&t,p=2&t,_=24&t,v=512&t,g=p?F:Hr(n);return l}function ne(n,t){return function(r,e){return Ct(r,n,t(e))}}function te(n,t){return function(r,e){var u;if(r===F&&e===F)return t;if(r!==F&&(u=r),e!==F){if(u===F)return e;typeof r=="string"||typeof e=="string"?(r=jr(r),e=jr(e)):(r=xr(r),e=xr(e)),u=n(r,e)}return u}}function re(n){return ge(function(t){
-return t=l(t,S(je())),lr(function(e){var u=this;return n(t,function(n){return r(n,u,e)})})})}function ee(n,t){t=t===F?" ":jr(t);var r=t.length;return 2>r?r?ar(t,n):t:(r=ar(t,Ri(n/T(t))),Bn.test(t)?zr($(r),0,n).join(""):r.slice(0,n))}function ue(n,t,e,u){function i(){for(var t=-1,c=arguments.length,a=-1,l=u.length,s=Hu(l+c),h=this&&this!==Zn&&this instanceof i?f:n;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++t];return r(h,o?e:this,s)}var o=1&t,f=Hr(n);return i}function ie(n){return function(t,r,e){
-e&&typeof e!="number"&&ze(t,r,e)&&(r=e=F),t=Eu(t),r===F?(r=t,t=0):r=Eu(r),e=e===F?t<r?1:-1:Eu(e);var u=-1;r=Di(Ri((r-t)/(e||1)),0);for(var i=Hu(r);r--;)i[n?r:++u]=t,t+=e;return i}}function oe(n){return function(t,r){return typeof t=="string"&&typeof r=="string"||(t=Iu(t),r=Iu(r)),n(t,r)}}function fe(n,t,r,e,u,i,o,f,c,a){var l=8&t,s=l?o:F;o=l?F:o;var h=l?i:F;return i=l?F:i,t=(t|(l?32:64))&~(l?64:32),4&t||(t&=-4),u=[n,t,u,h,s,i,o,f,c,a],r=r.apply(F,u),Be(n)&&xo(r,u),r.placeholder=e,De(r,n,t)}function ce(n){
-var t=Xu[n];return function(n,r){if(n=Iu(n),r=null==r?0:Mi(Ou(r),292)){var e=(zu(n)+"e").split("e"),e=t(e[0]+"e"+(+e[1]+r)),e=(zu(e)+"e").split("e");return+(e[0]+"e"+(+e[1]-r))}return t(n)}}function ae(n){return function(t){var r=yo(t);return"[object Map]"==r?L(t):"[object Set]"==r?M(t):O(t,n(t))}}function le(n,t,r,e,u,i,o,f){var c=2&t;if(!c&&typeof n!="function")throw new ei("Expected a function");var a=e?e.length:0;if(a||(t&=-97,e=u=F),o=o===F?o:Di(Ou(o),0),f=f===F?f:Ou(f),a-=u?u.length:0,64&t){
-var l=e,s=u;e=u=F}var h=c?F:_o(n);return i=[n,t,r,e,u,l,s,i,o,f],h&&(r=i[1],n=h[1],t=r|n,e=128==n&&8==r||128==n&&256==r&&i[7].length<=h[8]||384==n&&h[7].length<=h[8]&&8==r,131>t||e)&&(1&n&&(i[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=i[3],i[3]=e?Cr(e,r,h[4]):r,i[4]=e?C(i[3],"__lodash_placeholder__"):h[4]),(r=h[5])&&(e=i[5],i[5]=e?Dr(e,r,h[6]):r,i[6]=e?C(i[5],"__lodash_placeholder__"):h[6]),(r=h[7])&&(i[7]=r),128&n&&(i[8]=null==i[8]?h[8]:Mi(i[8],h[8])),null==i[9]&&(i[9]=h[9]),i[0]=h[0],i[1]=t),n=i[0],t=i[1],
-r=i[2],e=i[3],u=i[4],f=i[9]=i[9]===F?c?0:n.length:Di(i[9]-a,0),!f&&24&t&&(t&=-25),De((h?lo:xo)(t&&1!=t?8==t||16==t?Jr(n,t,f):32!=t&&33!=t||u.length?Xr.apply(F,i):ue(n,t,r,e):Vr(n,t,r),i),n,t)}function se(n,t,r,e){return n===F||hu(n,ii[r])&&!ci.call(e,r)?t:n}function he(n,t,r,e,u,i){return bu(n)&&bu(t)&&(i.set(t,n),nr(n,t,F,he,i),i.delete(t)),n}function pe(n){return wu(n)?F:n}function _e(n,t,r,e,u,i){var o=1&r,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return false;if((c=i.get(n))&&i.get(t))return c==t;var c=-1,a=true,l=2&r?new qn:F;
-for(i.set(n,t),i.set(t,n);++c<f;){var s=n[c],h=t[c];if(e)var p=o?e(h,s,c,t,n,i):e(s,h,c,n,t,i);if(p!==F){if(p)continue;a=false;break}if(l){if(!_(t,function(n,t){if(!R(l,t)&&(s===n||u(s,n,r,e,i)))return l.push(t)})){a=false;break}}else if(s!==h&&!u(s,h,r,e,i)){a=false;break}}return i.delete(n),i.delete(t),a}function ve(n,t,r,e,u,i,o){switch(r){case"[object DataView]":if(n.byteLength!=t.byteLength||n.byteOffset!=t.byteOffset)break;n=n.buffer,t=t.buffer;case"[object ArrayBuffer]":if(n.byteLength!=t.byteLength||!i(new di(n),new di(t)))break;
-return true;case"[object Boolean]":case"[object Date]":case"[object Number]":return hu(+n,+t);case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object RegExp]":case"[object String]":return n==t+"";case"[object Map]":var f=L;case"[object Set]":if(f||(f=D),n.size!=t.size&&!(1&e))break;return(r=o.get(n))?r==t:(e|=2,o.set(n,t),t=_e(f(n),f(t),e,u,i,o),o.delete(n),t);case"[object Symbol]":if(eo)return eo.call(n)==eo.call(t)}return false}function ge(n){return wo(Ce(n,F,Ve),n+"")}function de(n){
-return Rt(n,Lu,vo)}function ye(n){return Rt(n,Uu,go)}function be(n){for(var t=n.name+"",r=Ji[t],e=ci.call(Ji,t)?r.length:0;e--;){var u=r[e],i=u.func;if(null==i||i==n)return u.name}return t}function xe(n){return(ci.call(On,"placeholder")?On:n).placeholder}function je(){var n=On.iteratee||Pu,n=n===Pu?Gt:n;return arguments.length?n(arguments[0],arguments[1]):n}function we(n,t){var r=n.__data__,e=typeof t;return("string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t)?r[typeof t=="string"?"string":"hash"]:r.map;
-}function me(n){for(var t=Lu(n),r=t.length;r--;){var e=t[r],u=n[e];t[r]=[e,u,u===u&&!bu(u)]}return t}function Ae(n,t){var r=null==n?F:n[t];return Zt(r)?r:F}function ke(n,t,r){t=Rr(t,n);for(var e=-1,u=t.length,i=false;++e<u;){var o=$e(t[e]);if(!(i=null!=n&&r(n,o)))break;n=n[o]}return i||++e!=u?i:(u=null==n?0:n.length,!!u&&yu(u)&&Re(o,u)&&(af(n)||cf(n)))}function Ee(n){var t=n.length,r=n.constructor(t);return t&&"string"==typeof n[0]&&ci.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Oe(n){
-return typeof n.constructor!="function"||Le(n)?{}:io(bi(n))}function Se(r,e,u,i){var o=r.constructor;switch(e){case"[object ArrayBuffer]":return Br(r);case"[object Boolean]":case"[object Date]":return new o(+r);case"[object DataView]":return e=i?Br(r.buffer):r.buffer,new r.constructor(e,r.byteOffset,r.byteLength);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":
-case"[object Uint16Array]":case"[object Uint32Array]":return Lr(r,i);case"[object Map]":return e=i?u(L(r),1):L(r),h(e,n,new r.constructor);case"[object Number]":case"[object String]":return new o(r);case"[object RegExp]":return e=new r.constructor(r.source,dn.exec(r)),e.lastIndex=r.lastIndex,e;case"[object Set]":return e=i?u(D(r),1):D(r),h(e,t,new r.constructor);case"[object Symbol]":return eo?ni(eo.call(r)):{}}}function Ie(n){return af(n)||cf(n)||!!(mi&&n&&n[mi])}function Re(n,t){return t=null==t?9007199254740991:t,
-!!t&&(typeof n=="number"||wn.test(n))&&-1<n&&0==n%1&&n<t}function ze(n,t,r){if(!bu(r))return false;var e=typeof t;return!!("number"==e?pu(r)&&Re(t,r.length):"string"==e&&t in r)&&hu(r[t],n)}function We(n,t){if(af(n))return false;var r=typeof n;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=n&&!Au(n))||(rn.test(n)||!tn.test(n)||null!=t&&n in ni(t))}function Be(n){var t=be(n),r=On[t];return typeof r=="function"&&t in Mn.prototype&&(n===r||(t=_o(r),!!t&&n===t[0]))}function Le(n){var t=n&&n.constructor;
-return n===(typeof t=="function"&&t.prototype||ii)}function Ue(n,t){return function(r){return null!=r&&(r[n]===t&&(t!==F||n in ni(r)))}}function Ce(n,t,e){return t=Di(t===F?n.length-1:t,0),function(){for(var u=arguments,i=-1,o=Di(u.length-t,0),f=Hu(o);++i<o;)f[i]=u[t+i];for(i=-1,o=Hu(t+1);++i<t;)o[i]=u[i];return o[t]=e(f),r(n,this,o)}}function De(n,t,r){var e=t+"";t=wo;var u,i=Ne;return u=(u=e.match(hn))?u[1].split(pn):[],r=i(u,r),(i=r.length)&&(u=i-1,r[u]=(1<i?"& ":"")+r[u],r=r.join(2<i?", ":" "),
-e=e.replace(sn,"{\n/* [wrapped with "+r+"] */\n")),t(n,e)}function Me(n){var t=0,r=0;return function(){var e=Ti(),u=16-(e-r);if(r=e,0<u){if(800<=++t)return arguments[0]}else t=0;return n.apply(F,arguments)}}function Te(n,t){var r=-1,e=n.length,u=e-1;for(t=t===F?e:t;++r<t;){var e=cr(r,u),i=n[e];n[e]=n[r],n[r]=i}return n.length=t,n}function $e(n){if(typeof n=="string"||Au(n))return n;var t=n+"";return"0"==t&&1/n==-N?"-0":t}function Fe(n){if(null!=n){try{return fi.call(n)}catch(n){}return n+""}return"";
-}function Ne(n,t){return u(Z,function(r){var e="_."+r[0];t&r[1]&&!c(n,e)&&n.push(e)}),n.sort()}function Pe(n){if(n instanceof Mn)return n.clone();var t=new zn(n.__wrapped__,n.__chain__);return t.__actions__=Mr(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function Ze(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Ou(r),0>r&&(r=Di(e+r,0)),g(n,je(t,3),r)):-1}function qe(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==F&&(u=Ou(r),u=0>r?Di(e+u,0):Mi(u,e-1)),
-g(n,je(t,3),u,true)}function Ve(n){return(null==n?0:n.length)?kt(n,1):[]}function Ke(n){return n&&n.length?n[0]:F}function Ge(n){var t=null==n?0:n.length;return t?n[t-1]:F}function He(n,t){return n&&n.length&&t&&t.length?or(n,t):n}function Je(n){return null==n?n:Ni.call(n)}function Ye(n){if(!n||!n.length)return[];var t=0;return n=f(n,function(n){if(_u(n))return t=Di(n.length,t),true}),E(t,function(t){return l(n,j(t))})}function Qe(n,t){if(!n||!n.length)return[];var e=Ye(n);return null==t?e:l(e,function(n){
-return r(t,F,n)})}function Xe(n){return n=On(n),n.__chain__=true,n}function nu(n,t){return t(n)}function tu(){return this}function ru(n,t){return(af(n)?u:oo)(n,je(t,3))}function eu(n,t){return(af(n)?i:fo)(n,je(t,3))}function uu(n,t){return(af(n)?l:Yt)(n,je(t,3))}function iu(n,t,r){return t=r?F:t,t=n&&null==t?n.length:t,le(n,128,F,F,F,F,t)}function ou(n,t){var r;if(typeof t!="function")throw new ei("Expected a function");return n=Ou(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=F),
-r}}function fu(n,t,r){return t=r?F:t,n=le(n,8,F,F,F,F,F,t),n.placeholder=fu.placeholder,n}function cu(n,t,r){return t=r?F:t,n=le(n,16,F,F,F,F,F,t),n.placeholder=cu.placeholder,n}function au(n,t,r){function e(t){var r=c,e=a;return c=a=F,_=t,s=n.apply(e,r)}function u(n){var r=n-p;return n-=_,p===F||r>=t||0>r||g&&n>=l}function i(){var n=Jo();if(u(n))return o(n);var r,e=jo;r=n-_,n=t-(n-p),r=g?Mi(n,l-r):n,h=e(i,r)}function o(n){return h=F,d&&c?e(n):(c=a=F,s)}function f(){var n=Jo(),r=u(n);if(c=arguments,
-a=this,p=n,r){if(h===F)return _=n=p,h=jo(i,t),v?e(n):s;if(g)return h=jo(i,t),e(p)}return h===F&&(h=jo(i,t)),s}var c,a,l,s,h,p,_=0,v=false,g=false,d=true;if(typeof n!="function")throw new ei("Expected a function");return t=Iu(t)||0,bu(r)&&(v=!!r.leading,l=(g="maxWait"in r)?Di(Iu(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),f.cancel=function(){h!==F&&ho(h),_=0,c=p=a=h=F},f.flush=function(){return h===F?s:o(Jo())},f}function lu(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;return i.has(u)?i.get(u):(e=n.apply(this,e),
-r.cache=i.set(u,e)||i,e)}if(typeof n!="function"||null!=t&&typeof t!="function")throw new ei("Expected a function");return r.cache=new(lu.Cache||Pn),r}function su(n){if(typeof n!="function")throw new ei("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function hu(n,t){return n===t||n!==n&&t!==t}function pu(n){return null!=n&&yu(n.length)&&!gu(n);
-}function _u(n){return xu(n)&&pu(n)}function vu(n){if(!xu(n))return false;var t=zt(n);return"[object Error]"==t||"[object DOMException]"==t||typeof n.message=="string"&&typeof n.name=="string"&&!wu(n)}function gu(n){return!!bu(n)&&(n=zt(n),"[object Function]"==n||"[object GeneratorFunction]"==n||"[object AsyncFunction]"==n||"[object Proxy]"==n)}function du(n){return typeof n=="number"&&n==Ou(n)}function yu(n){return typeof n=="number"&&-1<n&&0==n%1&&9007199254740991>=n}function bu(n){var t=typeof n;return null!=n&&("object"==t||"function"==t);
-}function xu(n){return null!=n&&typeof n=="object"}function ju(n){return typeof n=="number"||xu(n)&&"[object Number]"==zt(n)}function wu(n){return!(!xu(n)||"[object Object]"!=zt(n))&&(n=bi(n),null===n||(n=ci.call(n,"constructor")&&n.constructor,typeof n=="function"&&n instanceof n&&fi.call(n)==hi))}function mu(n){return typeof n=="string"||!af(n)&&xu(n)&&"[object String]"==zt(n)}function Au(n){return typeof n=="symbol"||xu(n)&&"[object Symbol]"==zt(n)}function ku(n){if(!n)return[];if(pu(n))return mu(n)?$(n):Mr(n);
-if(Ai&&n[Ai]){n=n[Ai]();for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}return t=yo(n),("[object Map]"==t?L:"[object Set]"==t?D:Du)(n)}function Eu(n){return n?(n=Iu(n),n===N||n===-N?1.7976931348623157e308*(0>n?-1:1):n===n?n:0):0===n?n:0}function Ou(n){n=Eu(n);var t=n%1;return n===n?t?n-t:n:0}function Su(n){return n?gt(Ou(n),0,4294967295):0}function Iu(n){if(typeof n=="number")return n;if(Au(n))return P;if(bu(n)&&(n=typeof n.valueOf=="function"?n.valueOf():n,n=bu(n)?n+"":n),typeof n!="string")return 0===n?n:+n;
-n=n.replace(cn,"");var t=bn.test(n);return t||jn.test(n)?Fn(n.slice(2),t?2:8):yn.test(n)?P:+n}function Ru(n){return Tr(n,Uu(n))}function zu(n){return null==n?"":jr(n)}function Wu(n,t,r){return n=null==n?F:It(n,t),n===F?r:n}function Bu(n,t){return null!=n&&ke(n,t,Lt)}function Lu(n){return pu(n)?Gn(n):Ht(n)}function Uu(n){if(pu(n))n=Gn(n,true);else if(bu(n)){var t,r=Le(n),e=[];for(t in n)("constructor"!=t||!r&&ci.call(n,t))&&e.push(t);n=e}else{if(t=[],null!=n)for(r in ni(n))t.push(r);n=t}return n}function Cu(n,t){
-if(null==n)return{};var r=l(ye(n),function(n){return[n]});return t=je(t),ur(n,r,function(n,r){return t(n,r[0])})}function Du(n){return null==n?[]:I(n,Lu(n))}function Mu(n){return Nf(zu(n).toLowerCase())}function Tu(n){return(n=zu(n))&&n.replace(mn,rt).replace(Rn,"")}function $u(n,t,r){return n=zu(n),t=r?F:t,t===F?Ln.test(n)?n.match(Wn)||[]:n.match(_n)||[]:n.match(t)||[]}function Fu(n){return function(){return n}}function Nu(n){return n}function Pu(n){return Gt(typeof n=="function"?n:dt(n,1))}function Zu(n,t,r){
-var e=Lu(t),i=St(t,e);null!=r||bu(t)&&(i.length||!e.length)||(r=t,t=n,n=this,i=St(t,Lu(t)));var o=!(bu(r)&&"chain"in r&&!r.chain),f=gu(n);return u(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Mr(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,s([this.value()],arguments))})}),n}function qu(){}function Vu(n){return We(n)?j($e(n)):ir(n)}function Ku(){return[]}function Gu(){
-return false}En=null==En?Zn:it.defaults(Zn.Object(),En,it.pick(Zn,Un));var Hu=En.Array,Ju=En.Date,Yu=En.Error,Qu=En.Function,Xu=En.Math,ni=En.Object,ti=En.RegExp,ri=En.String,ei=En.TypeError,ui=Hu.prototype,ii=ni.prototype,oi=En["__core-js_shared__"],fi=Qu.prototype.toString,ci=ii.hasOwnProperty,ai=0,li=function(){var n=/[^.]+$/.exec(oi&&oi.keys&&oi.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),si=ii.toString,hi=fi.call(ni),pi=Zn._,_i=ti("^"+fi.call(ci).replace(on,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),vi=Kn?En.Buffer:F,gi=En.Symbol,di=En.Uint8Array,yi=vi?vi.f:F,bi=U(ni.getPrototypeOf,ni),xi=ni.create,ji=ii.propertyIsEnumerable,wi=ui.splice,mi=gi?gi.isConcatSpreadable:F,Ai=gi?gi.iterator:F,ki=gi?gi.toStringTag:F,Ei=function(){
-try{var n=Ae(ni,"defineProperty");return n({},"",{}),n}catch(n){}}(),Oi=En.clearTimeout!==Zn.clearTimeout&&En.clearTimeout,Si=Ju&&Ju.now!==Zn.Date.now&&Ju.now,Ii=En.setTimeout!==Zn.setTimeout&&En.setTimeout,Ri=Xu.ceil,zi=Xu.floor,Wi=ni.getOwnPropertySymbols,Bi=vi?vi.isBuffer:F,Li=En.isFinite,Ui=ui.join,Ci=U(ni.keys,ni),Di=Xu.max,Mi=Xu.min,Ti=Ju.now,$i=En.parseInt,Fi=Xu.random,Ni=ui.reverse,Pi=Ae(En,"DataView"),Zi=Ae(En,"Map"),qi=Ae(En,"Promise"),Vi=Ae(En,"Set"),Ki=Ae(En,"WeakMap"),Gi=Ae(ni,"create"),Hi=Ki&&new Ki,Ji={},Yi=Fe(Pi),Qi=Fe(Zi),Xi=Fe(qi),no=Fe(Vi),to=Fe(Ki),ro=gi?gi.prototype:F,eo=ro?ro.valueOf:F,uo=ro?ro.toString:F,io=function(){
-function n(){}return function(t){return bu(t)?xi?xi(t):(n.prototype=t,t=new n,n.prototype=F,t):{}}}();On.templateSettings={escape:Q,evaluate:X,interpolate:nn,variable:"",imports:{_:On}},On.prototype=Sn.prototype,On.prototype.constructor=On,zn.prototype=io(Sn.prototype),zn.prototype.constructor=zn,Mn.prototype=io(Sn.prototype),Mn.prototype.constructor=Mn,Tn.prototype.clear=function(){this.__data__=Gi?Gi(null):{},this.size=0},Tn.prototype.delete=function(n){return n=this.has(n)&&delete this.__data__[n],
-this.size-=n?1:0,n},Tn.prototype.get=function(n){var t=this.__data__;return Gi?(n=t[n],"__lodash_hash_undefined__"===n?F:n):ci.call(t,n)?t[n]:F},Tn.prototype.has=function(n){var t=this.__data__;return Gi?t[n]!==F:ci.call(t,n)},Tn.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=Gi&&t===F?"__lodash_hash_undefined__":t,this},Nn.prototype.clear=function(){this.__data__=[],this.size=0},Nn.prototype.delete=function(n){var t=this.__data__;return n=lt(t,n),!(0>n)&&(n==t.length-1?t.pop():wi.call(t,n,1),
---this.size,true)},Nn.prototype.get=function(n){var t=this.__data__;return n=lt(t,n),0>n?F:t[n][1]},Nn.prototype.has=function(n){return-1<lt(this.__data__,n)},Nn.prototype.set=function(n,t){var r=this.__data__,e=lt(r,n);return 0>e?(++this.size,r.push([n,t])):r[e][1]=t,this},Pn.prototype.clear=function(){this.size=0,this.__data__={hash:new Tn,map:new(Zi||Nn),string:new Tn}},Pn.prototype.delete=function(n){return n=we(this,n).delete(n),this.size-=n?1:0,n},Pn.prototype.get=function(n){return we(this,n).get(n);
-},Pn.prototype.has=function(n){return we(this,n).has(n)},Pn.prototype.set=function(n,t){var r=we(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},qn.prototype.add=qn.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},qn.prototype.has=function(n){return this.__data__.has(n)},Vn.prototype.clear=function(){this.__data__=new Nn,this.size=0},Vn.prototype.delete=function(n){var t=this.__data__;return n=t.delete(n),this.size=t.size,n},Vn.prototype.get=function(n){
-return this.__data__.get(n)},Vn.prototype.has=function(n){return this.__data__.has(n)},Vn.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Nn){var e=r.__data__;if(!Zi||199>e.length)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Pn(e)}return r.set(n,t),this.size=r.size,this};var oo=Zr(Et),fo=Zr(Ot,true),co=qr(),ao=qr(true),lo=Hi?function(n,t){return Hi.set(n,t),n}:Nu,so=Ei?function(n,t){return Ei(n,"toString",{configurable:true,enumerable:false,value:Fu(t),writable:true})}:Nu,ho=Oi||function(n){
-return Zn.clearTimeout(n)},po=Vi&&1/D(new Vi([,-0]))[1]==N?function(n){return new Vi(n)}:qu,_o=Hi?function(n){return Hi.get(n)}:qu,vo=Wi?function(n){return null==n?[]:(n=ni(n),f(Wi(n),function(t){return ji.call(n,t)}))}:Ku,go=Wi?function(n){for(var t=[];n;)s(t,vo(n)),n=bi(n);return t}:Ku,yo=zt;(Pi&&"[object DataView]"!=yo(new Pi(new ArrayBuffer(1)))||Zi&&"[object Map]"!=yo(new Zi)||qi&&"[object Promise]"!=yo(qi.resolve())||Vi&&"[object Set]"!=yo(new Vi)||Ki&&"[object WeakMap]"!=yo(new Ki))&&(yo=function(n){
-var t=zt(n);if(n=(n="[object Object]"==t?n.constructor:F)?Fe(n):"")switch(n){case Yi:return"[object DataView]";case Qi:return"[object Map]";case Xi:return"[object Promise]";case no:return"[object Set]";case to:return"[object WeakMap]"}return t});var bo=oi?gu:Gu,xo=Me(lo),jo=Ii||function(n,t){return Zn.setTimeout(n,t)},wo=Me(so),mo=function(n){n=lu(n,function(n){return 500===t.size&&t.clear(),n});var t=n.cache;return n}(function(n){var t=[];return en.test(n)&&t.push(""),n.replace(un,function(n,r,e,u){
-t.push(e?u.replace(vn,"$1"):r||n)}),t}),Ao=lr(function(n,t){return _u(n)?jt(n,kt(t,1,_u,true)):[]}),ko=lr(function(n,t){var r=Ge(t);return _u(r)&&(r=F),_u(n)?jt(n,kt(t,1,_u,true),je(r,2)):[]}),Eo=lr(function(n,t){var r=Ge(t);return _u(r)&&(r=F),_u(n)?jt(n,kt(t,1,_u,true),F,r):[]}),Oo=lr(function(n){var t=l(n,Sr);return t.length&&t[0]===n[0]?Ut(t):[]}),So=lr(function(n){var t=Ge(n),r=l(n,Sr);return t===Ge(r)?t=F:r.pop(),r.length&&r[0]===n[0]?Ut(r,je(t,2)):[]}),Io=lr(function(n){var t=Ge(n),r=l(n,Sr);return(t=typeof t=="function"?t:F)&&r.pop(),
-r.length&&r[0]===n[0]?Ut(r,F,t):[]}),Ro=lr(He),zo=ge(function(n,t){var r=null==n?0:n.length,e=vt(n,t);return fr(n,l(t,function(n){return Re(n,r)?+n:n}).sort(Ur)),e}),Wo=lr(function(n){return wr(kt(n,1,_u,true))}),Bo=lr(function(n){var t=Ge(n);return _u(t)&&(t=F),wr(kt(n,1,_u,true),je(t,2))}),Lo=lr(function(n){var t=Ge(n),t=typeof t=="function"?t:F;return wr(kt(n,1,_u,true),F,t)}),Uo=lr(function(n,t){return _u(n)?jt(n,t):[]}),Co=lr(function(n){return Er(f(n,_u))}),Do=lr(function(n){var t=Ge(n);return _u(t)&&(t=F),
-Er(f(n,_u),je(t,2))}),Mo=lr(function(n){var t=Ge(n),t=typeof t=="function"?t:F;return Er(f(n,_u),F,t)}),To=lr(Ye),$o=lr(function(n){var t=n.length,t=1<t?n[t-1]:F,t=typeof t=="function"?(n.pop(),t):F;return Qe(n,t)}),Fo=ge(function(n){function t(t){return vt(t,n)}var r=n.length,e=r?n[0]:0,u=this.__wrapped__;return!(1<r||this.__actions__.length)&&u instanceof Mn&&Re(e)?(u=u.slice(e,+e+(r?1:0)),u.__actions__.push({func:nu,args:[t],thisArg:F}),new zn(u,this.__chain__).thru(function(n){return r&&!n.length&&n.push(F),
-n})):this.thru(t)}),No=Nr(function(n,t,r){ci.call(n,r)?++n[r]:_t(n,r,1)}),Po=Yr(Ze),Zo=Yr(qe),qo=Nr(function(n,t,r){ci.call(n,r)?n[r].push(t):_t(n,r,[t])}),Vo=lr(function(n,t,e){var u=-1,i=typeof t=="function",o=pu(n)?Hu(n.length):[];return oo(n,function(n){o[++u]=i?r(t,n,e):Dt(n,t,e)}),o}),Ko=Nr(function(n,t,r){_t(n,r,t)}),Go=Nr(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Ho=lr(function(n,t){if(null==n)return[];var r=t.length;return 1<r&&ze(n,t[0],t[1])?t=[]:2<r&&ze(t[0],t[1],t[2])&&(t=[t[0]]),
-rr(n,kt(t,1),[])}),Jo=Si||function(){return Zn.Date.now()},Yo=lr(function(n,t,r){var e=1;if(r.length)var u=C(r,xe(Yo)),e=32|e;return le(n,e,t,r,u)}),Qo=lr(function(n,t,r){var e=3;if(r.length)var u=C(r,xe(Qo)),e=32|e;return le(t,e,n,r,u)}),Xo=lr(function(n,t){return xt(n,1,t)}),nf=lr(function(n,t,r){return xt(n,Iu(t)||0,r)});lu.Cache=Pn;var tf=lr(function(n,t){t=1==t.length&&af(t[0])?l(t[0],S(je())):l(kt(t,1),S(je()));var e=t.length;return lr(function(u){for(var i=-1,o=Mi(u.length,e);++i<o;)u[i]=t[i].call(this,u[i]);
-return r(n,this,u)})}),rf=lr(function(n,t){return le(n,32,F,t,C(t,xe(rf)))}),ef=lr(function(n,t){return le(n,64,F,t,C(t,xe(ef)))}),uf=ge(function(n,t){return le(n,256,F,F,F,t)}),of=oe(Wt),ff=oe(function(n,t){return n>=t}),cf=Mt(function(){return arguments}())?Mt:function(n){return xu(n)&&ci.call(n,"callee")&&!ji.call(n,"callee")},af=Hu.isArray,lf=Hn?S(Hn):Tt,sf=Bi||Gu,hf=Jn?S(Jn):$t,pf=Yn?S(Yn):Nt,_f=Qn?S(Qn):qt,vf=Xn?S(Xn):Vt,gf=nt?S(nt):Kt,df=oe(Jt),yf=oe(function(n,t){return n<=t}),bf=Pr(function(n,t){
-if(Le(t)||pu(t))Tr(t,Lu(t),n);else for(var r in t)ci.call(t,r)&&at(n,r,t[r])}),xf=Pr(function(n,t){Tr(t,Uu(t),n)}),jf=Pr(function(n,t,r,e){Tr(t,Uu(t),n,e)}),wf=Pr(function(n,t,r,e){Tr(t,Lu(t),n,e)}),mf=ge(vt),Af=lr(function(n){return n.push(F,se),r(jf,F,n)}),kf=lr(function(n){return n.push(F,he),r(Rf,F,n)}),Ef=ne(function(n,t,r){n[t]=r},Fu(Nu)),Of=ne(function(n,t,r){ci.call(n,t)?n[t].push(r):n[t]=[r]},je),Sf=lr(Dt),If=Pr(function(n,t,r){nr(n,t,r)}),Rf=Pr(function(n,t,r,e){nr(n,t,r,e)}),zf=ge(function(n,t){
-var r={};if(null==n)return r;var e=false;t=l(t,function(t){return t=Rr(t,n),e||(e=1<t.length),t}),Tr(n,ye(n),r),e&&(r=dt(r,7,pe));for(var u=t.length;u--;)mr(r,t[u]);return r}),Wf=ge(function(n,t){return null==n?{}:er(n,t)}),Bf=ae(Lu),Lf=ae(Uu),Uf=Gr(function(n,t,r){return t=t.toLowerCase(),n+(r?Mu(t):t)}),Cf=Gr(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Df=Gr(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Mf=Kr("toLowerCase"),Tf=Gr(function(n,t,r){return n+(r?"_":"")+t.toLowerCase();
-}),$f=Gr(function(n,t,r){return n+(r?" ":"")+Nf(t)}),Ff=Gr(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),Nf=Kr("toUpperCase"),Pf=lr(function(n,t){try{return r(n,F,t)}catch(n){return vu(n)?n:new Yu(n)}}),Zf=ge(function(n,t){return u(t,function(t){t=$e(t),_t(n,t,Yo(n[t],n))}),n}),qf=Qr(),Vf=Qr(true),Kf=lr(function(n,t){return function(r){return Dt(r,n,t)}}),Gf=lr(function(n,t){return function(r){return Dt(n,r,t)}}),Hf=re(l),Jf=re(o),Yf=re(_),Qf=ie(),Xf=ie(true),nc=te(function(n,t){return n+t},0),tc=ce("ceil"),rc=te(function(n,t){
-return n/t},1),ec=ce("floor"),uc=te(function(n,t){return n*t},1),ic=ce("round"),oc=te(function(n,t){return n-t},0);return On.after=function(n,t){if(typeof t!="function")throw new ei("Expected a function");return n=Ou(n),function(){if(1>--n)return t.apply(this,arguments)}},On.ary=iu,On.assign=bf,On.assignIn=xf,On.assignInWith=jf,On.assignWith=wf,On.at=mf,On.before=ou,On.bind=Yo,On.bindAll=Zf,On.bindKey=Qo,On.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return af(n)?n:[n]},
-On.chain=Xe,On.chunk=function(n,t,r){if(t=(r?ze(n,t,r):t===F)?1:Di(Ou(t),0),r=null==n?0:n.length,!r||1>t)return[];for(var e=0,u=0,i=Hu(Ri(r/t));e<r;)i[u++]=vr(n,e,e+=t);return i},On.compact=function(n){for(var t=-1,r=null==n?0:n.length,e=0,u=[];++t<r;){var i=n[t];i&&(u[e++]=i)}return u},On.concat=function(){var n=arguments.length;if(!n)return[];for(var t=Hu(n-1),r=arguments[0];n--;)t[n-1]=arguments[n];return s(af(r)?Mr(r):[r],kt(t,1))},On.cond=function(n){var t=null==n?0:n.length,e=je();return n=t?l(n,function(n){
-if("function"!=typeof n[1])throw new ei("Expected a function");return[e(n[0]),n[1]]}):[],lr(function(e){for(var u=-1;++u<t;){var i=n[u];if(r(i[0],this,e))return r(i[1],this,e)}})},On.conforms=function(n){return yt(dt(n,1))},On.constant=Fu,On.countBy=No,On.create=function(n,t){var r=io(n);return null==t?r:ht(r,t)},On.curry=fu,On.curryRight=cu,On.debounce=au,On.defaults=Af,On.defaultsDeep=kf,On.defer=Xo,On.delay=nf,On.difference=Ao,On.differenceBy=ko,On.differenceWith=Eo,On.drop=function(n,t,r){var e=null==n?0:n.length;
-return e?(t=r||t===F?1:Ou(t),vr(n,0>t?0:t,e)):[]},On.dropRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===F?1:Ou(t),t=e-t,vr(n,0,0>t?0:t)):[]},On.dropRightWhile=function(n,t){return n&&n.length?Ar(n,je(t,3),true,true):[]},On.dropWhile=function(n,t){return n&&n.length?Ar(n,je(t,3),true):[]},On.fill=function(n,t,r,e){var u=null==n?0:n.length;if(!u)return[];for(r&&typeof r!="number"&&ze(n,t,r)&&(r=0,e=u),u=n.length,r=Ou(r),0>r&&(r=-r>u?0:u+r),e=e===F||e>u?u:Ou(e),0>e&&(e+=u),e=r>e?0:Su(e);r<e;)n[r++]=t;
-return n},On.filter=function(n,t){return(af(n)?f:At)(n,je(t,3))},On.flatMap=function(n,t){return kt(uu(n,t),1)},On.flatMapDeep=function(n,t){return kt(uu(n,t),N)},On.flatMapDepth=function(n,t,r){return r=r===F?1:Ou(r),kt(uu(n,t),r)},On.flatten=Ve,On.flattenDeep=function(n){return(null==n?0:n.length)?kt(n,N):[]},On.flattenDepth=function(n,t){return null!=n&&n.length?(t=t===F?1:Ou(t),kt(n,t)):[]},On.flip=function(n){return le(n,512)},On.flow=qf,On.flowRight=Vf,On.fromPairs=function(n){for(var t=-1,r=null==n?0:n.length,e={};++t<r;){
-var u=n[t];e[u[0]]=u[1]}return e},On.functions=function(n){return null==n?[]:St(n,Lu(n))},On.functionsIn=function(n){return null==n?[]:St(n,Uu(n))},On.groupBy=qo,On.initial=function(n){return(null==n?0:n.length)?vr(n,0,-1):[]},On.intersection=Oo,On.intersectionBy=So,On.intersectionWith=Io,On.invert=Ef,On.invertBy=Of,On.invokeMap=Vo,On.iteratee=Pu,On.keyBy=Ko,On.keys=Lu,On.keysIn=Uu,On.map=uu,On.mapKeys=function(n,t){var r={};return t=je(t,3),Et(n,function(n,e,u){_t(r,t(n,e,u),n)}),r},On.mapValues=function(n,t){
-var r={};return t=je(t,3),Et(n,function(n,e,u){_t(r,e,t(n,e,u))}),r},On.matches=function(n){return Qt(dt(n,1))},On.matchesProperty=function(n,t){return Xt(n,dt(t,1))},On.memoize=lu,On.merge=If,On.mergeWith=Rf,On.method=Kf,On.methodOf=Gf,On.mixin=Zu,On.negate=su,On.nthArg=function(n){return n=Ou(n),lr(function(t){return tr(t,n)})},On.omit=zf,On.omitBy=function(n,t){return Cu(n,su(je(t)))},On.once=function(n){return ou(2,n)},On.orderBy=function(n,t,r,e){return null==n?[]:(af(t)||(t=null==t?[]:[t]),
-r=e?F:r,af(r)||(r=null==r?[]:[r]),rr(n,t,r))},On.over=Hf,On.overArgs=tf,On.overEvery=Jf,On.overSome=Yf,On.partial=rf,On.partialRight=ef,On.partition=Go,On.pick=Wf,On.pickBy=Cu,On.property=Vu,On.propertyOf=function(n){return function(t){return null==n?F:It(n,t)}},On.pull=Ro,On.pullAll=He,On.pullAllBy=function(n,t,r){return n&&n.length&&t&&t.length?or(n,t,je(r,2)):n},On.pullAllWith=function(n,t,r){return n&&n.length&&t&&t.length?or(n,t,F,r):n},On.pullAt=zo,On.range=Qf,On.rangeRight=Xf,On.rearg=uf,On.reject=function(n,t){
-return(af(n)?f:At)(n,su(je(t,3)))},On.remove=function(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],i=n.length;for(t=je(t,3);++e<i;){var o=n[e];t(o,e,n)&&(r.push(o),u.push(e))}return fr(n,u),r},On.rest=function(n,t){if(typeof n!="function")throw new ei("Expected a function");return t=t===F?t:Ou(t),lr(n,t)},On.reverse=Je,On.sampleSize=function(n,t,r){return t=(r?ze(n,t,r):t===F)?1:Ou(t),(af(n)?ot:hr)(n,t)},On.set=function(n,t,r){return null==n?n:pr(n,t,r)},On.setWith=function(n,t,r,e){return e=typeof e=="function"?e:F,
-null==n?n:pr(n,t,r,e)},On.shuffle=function(n){return(af(n)?ft:_r)(n)},On.slice=function(n,t,r){var e=null==n?0:n.length;return e?(r&&typeof r!="number"&&ze(n,t,r)?(t=0,r=e):(t=null==t?0:Ou(t),r=r===F?e:Ou(r)),vr(n,t,r)):[]},On.sortBy=Ho,On.sortedUniq=function(n){return n&&n.length?br(n):[]},On.sortedUniqBy=function(n,t){return n&&n.length?br(n,je(t,2)):[]},On.split=function(n,t,r){return r&&typeof r!="number"&&ze(n,t,r)&&(t=r=F),r=r===F?4294967295:r>>>0,r?(n=zu(n))&&(typeof t=="string"||null!=t&&!_f(t))&&(t=jr(t),
-!t&&Bn.test(n))?zr($(n),0,r):n.split(t,r):[]},On.spread=function(n,t){if(typeof n!="function")throw new ei("Expected a function");return t=null==t?0:Di(Ou(t),0),lr(function(e){var u=e[t];return e=zr(e,0,t),u&&s(e,u),r(n,this,e)})},On.tail=function(n){var t=null==n?0:n.length;return t?vr(n,1,t):[]},On.take=function(n,t,r){return n&&n.length?(t=r||t===F?1:Ou(t),vr(n,0,0>t?0:t)):[]},On.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===F?1:Ou(t),t=e-t,vr(n,0>t?0:t,e)):[]},On.takeRightWhile=function(n,t){
-return n&&n.length?Ar(n,je(t,3),false,true):[]},On.takeWhile=function(n,t){return n&&n.length?Ar(n,je(t,3)):[]},On.tap=function(n,t){return t(n),n},On.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new ei("Expected a function");return bu(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),au(n,t,{leading:e,maxWait:t,trailing:u})},On.thru=nu,On.toArray=ku,On.toPairs=Bf,On.toPairsIn=Lf,On.toPath=function(n){return af(n)?l(n,$e):Au(n)?[n]:Mr(mo(zu(n)))},On.toPlainObject=Ru,
-On.transform=function(n,t,r){var e=af(n),i=e||sf(n)||gf(n);if(t=je(t,4),null==r){var o=n&&n.constructor;r=i?e?new o:[]:bu(n)&&gu(o)?io(bi(n)):{}}return(i?u:Et)(n,function(n,e,u){return t(r,n,e,u)}),r},On.unary=function(n){return iu(n,1)},On.union=Wo,On.unionBy=Bo,On.unionWith=Lo,On.uniq=function(n){return n&&n.length?wr(n):[]},On.uniqBy=function(n,t){return n&&n.length?wr(n,je(t,2)):[]},On.uniqWith=function(n,t){return t=typeof t=="function"?t:F,n&&n.length?wr(n,F,t):[]},On.unset=function(n,t){return null==n||mr(n,t);
-},On.unzip=Ye,On.unzipWith=Qe,On.update=function(n,t,r){return null==n?n:pr(n,t,Ir(r)(It(n,t)),void 0)},On.updateWith=function(n,t,r,e){return e=typeof e=="function"?e:F,null!=n&&(n=pr(n,t,Ir(r)(It(n,t)),e)),n},On.values=Du,On.valuesIn=function(n){return null==n?[]:I(n,Uu(n))},On.without=Uo,On.words=$u,On.wrap=function(n,t){return rf(Ir(t),n)},On.xor=Co,On.xorBy=Do,On.xorWith=Mo,On.zip=To,On.zipObject=function(n,t){return Or(n||[],t||[],at)},On.zipObjectDeep=function(n,t){return Or(n||[],t||[],pr);
-},On.zipWith=$o,On.entries=Bf,On.entriesIn=Lf,On.extend=xf,On.extendWith=jf,Zu(On,On),On.add=nc,On.attempt=Pf,On.camelCase=Uf,On.capitalize=Mu,On.ceil=tc,On.clamp=function(n,t,r){return r===F&&(r=t,t=F),r!==F&&(r=Iu(r),r=r===r?r:0),t!==F&&(t=Iu(t),t=t===t?t:0),gt(Iu(n),t,r)},On.clone=function(n){return dt(n,4)},On.cloneDeep=function(n){return dt(n,5)},On.cloneDeepWith=function(n,t){return t=typeof t=="function"?t:F,dt(n,5,t)},On.cloneWith=function(n,t){return t=typeof t=="function"?t:F,dt(n,4,t)},
-On.conformsTo=function(n,t){return null==t||bt(n,t,Lu(t))},On.deburr=Tu,On.defaultTo=function(n,t){return null==n||n!==n?t:n},On.divide=rc,On.endsWith=function(n,t,r){n=zu(n),t=jr(t);var e=n.length,e=r=r===F?e:gt(Ou(r),0,e);return r-=t.length,0<=r&&n.slice(r,e)==t},On.eq=hu,On.escape=function(n){return(n=zu(n))&&Y.test(n)?n.replace(H,et):n},On.escapeRegExp=function(n){return(n=zu(n))&&fn.test(n)?n.replace(on,"\\$&"):n},On.every=function(n,t,r){var e=af(n)?o:wt;return r&&ze(n,t,r)&&(t=F),e(n,je(t,3));
-},On.find=Po,On.findIndex=Ze,On.findKey=function(n,t){return v(n,je(t,3),Et)},On.findLast=Zo,On.findLastIndex=qe,On.findLastKey=function(n,t){return v(n,je(t,3),Ot)},On.floor=ec,On.forEach=ru,On.forEachRight=eu,On.forIn=function(n,t){return null==n?n:co(n,je(t,3),Uu)},On.forInRight=function(n,t){return null==n?n:ao(n,je(t,3),Uu)},On.forOwn=function(n,t){return n&&Et(n,je(t,3))},On.forOwnRight=function(n,t){return n&&Ot(n,je(t,3))},On.get=Wu,On.gt=of,On.gte=ff,On.has=function(n,t){return null!=n&&ke(n,t,Bt);
-},On.hasIn=Bu,On.head=Ke,On.identity=Nu,On.includes=function(n,t,r,e){return n=pu(n)?n:Du(n),r=r&&!e?Ou(r):0,e=n.length,0>r&&(r=Di(e+r,0)),mu(n)?r<=e&&-1<n.indexOf(t,r):!!e&&-1<d(n,t,r)},On.indexOf=function(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Ou(r),0>r&&(r=Di(e+r,0)),d(n,t,r)):-1},On.inRange=function(n,t,r){return t=Eu(t),r===F?(r=t,t=0):r=Eu(r),n=Iu(n),n>=Mi(t,r)&&n<Di(t,r)},On.invoke=Sf,On.isArguments=cf,On.isArray=af,On.isArrayBuffer=lf,On.isArrayLike=pu,On.isArrayLikeObject=_u,
-On.isBoolean=function(n){return true===n||false===n||xu(n)&&"[object Boolean]"==zt(n)},On.isBuffer=sf,On.isDate=hf,On.isElement=function(n){return xu(n)&&1===n.nodeType&&!wu(n)},On.isEmpty=function(n){if(null==n)return true;if(pu(n)&&(af(n)||typeof n=="string"||typeof n.splice=="function"||sf(n)||gf(n)||cf(n)))return!n.length;var t=yo(n);if("[object Map]"==t||"[object Set]"==t)return!n.size;if(Le(n))return!Ht(n).length;for(var r in n)if(ci.call(n,r))return false;return true},On.isEqual=function(n,t){return Ft(n,t);
-},On.isEqualWith=function(n,t,r){var e=(r=typeof r=="function"?r:F)?r(n,t):F;return e===F?Ft(n,t,F,r):!!e},On.isError=vu,On.isFinite=function(n){return typeof n=="number"&&Li(n)},On.isFunction=gu,On.isInteger=du,On.isLength=yu,On.isMap=pf,On.isMatch=function(n,t){return n===t||Pt(n,t,me(t))},On.isMatchWith=function(n,t,r){return r=typeof r=="function"?r:F,Pt(n,t,me(t),r)},On.isNaN=function(n){return ju(n)&&n!=+n},On.isNative=function(n){if(bo(n))throw new Yu("Unsupported core-js use. Try https://npms.io/search?q=ponyfill.");
-return Zt(n)},On.isNil=function(n){return null==n},On.isNull=function(n){return null===n},On.isNumber=ju,On.isObject=bu,On.isObjectLike=xu,On.isPlainObject=wu,On.isRegExp=_f,On.isSafeInteger=function(n){return du(n)&&-9007199254740991<=n&&9007199254740991>=n},On.isSet=vf,On.isString=mu,On.isSymbol=Au,On.isTypedArray=gf,On.isUndefined=function(n){return n===F},On.isWeakMap=function(n){return xu(n)&&"[object WeakMap]"==yo(n)},On.isWeakSet=function(n){return xu(n)&&"[object WeakSet]"==zt(n)},On.join=function(n,t){
-return null==n?"":Ui.call(n,t)},On.kebabCase=Cf,On.last=Ge,On.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;if(r!==F&&(u=Ou(r),u=0>u?Di(e+u,0):Mi(u,e-1)),t===t){for(r=u+1;r--&&n[r]!==t;);n=r}else n=g(n,b,u,true);return n},On.lowerCase=Df,On.lowerFirst=Mf,On.lt=df,On.lte=yf,On.max=function(n){return n&&n.length?mt(n,Nu,Wt):F},On.maxBy=function(n,t){return n&&n.length?mt(n,je(t,2),Wt):F},On.mean=function(n){return x(n,Nu)},On.meanBy=function(n,t){return x(n,je(t,2))},On.min=function(n){
-return n&&n.length?mt(n,Nu,Jt):F},On.minBy=function(n,t){return n&&n.length?mt(n,je(t,2),Jt):F},On.stubArray=Ku,On.stubFalse=Gu,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return true},On.multiply=uc,On.nth=function(n,t){return n&&n.length?tr(n,Ou(t)):F},On.noConflict=function(){return Zn._===this&&(Zn._=pi),this},On.noop=qu,On.now=Jo,On.pad=function(n,t,r){n=zu(n);var e=(t=Ou(t))?T(n):0;return!t||e>=t?n:(t=(t-e)/2,ee(zi(t),r)+n+ee(Ri(t),r))},On.padEnd=function(n,t,r){
-n=zu(n);var e=(t=Ou(t))?T(n):0;return t&&e<t?n+ee(t-e,r):n},On.padStart=function(n,t,r){n=zu(n);var e=(t=Ou(t))?T(n):0;return t&&e<t?ee(t-e,r)+n:n},On.parseInt=function(n,t,r){return r||null==t?t=0:t&&(t=+t),$i(zu(n).replace(an,""),t||0)},On.random=function(n,t,r){if(r&&typeof r!="boolean"&&ze(n,t,r)&&(t=r=F),r===F&&(typeof t=="boolean"?(r=t,t=F):typeof n=="boolean"&&(r=n,n=F)),n===F&&t===F?(n=0,t=1):(n=Eu(n),t===F?(t=n,n=0):t=Eu(t)),n>t){var e=n;n=t,t=e}return r||n%1||t%1?(r=Fi(),Mi(n+r*(t-n+$n("1e-"+((r+"").length-1))),t)):cr(n,t);
-},On.reduce=function(n,t,r){var e=af(n)?h:m,u=3>arguments.length;return e(n,je(t,4),r,u,oo)},On.reduceRight=function(n,t,r){var e=af(n)?p:m,u=3>arguments.length;return e(n,je(t,4),r,u,fo)},On.repeat=function(n,t,r){return t=(r?ze(n,t,r):t===F)?1:Ou(t),ar(zu(n),t)},On.replace=function(){var n=arguments,t=zu(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},On.result=function(n,t,r){t=Rr(t,n);var e=-1,u=t.length;for(u||(u=1,n=F);++e<u;){var i=null==n?F:n[$e(t[e])];i===F&&(e=u,i=r),n=gu(i)?i.call(n):i;
-}return n},On.round=ic,On.runInContext=w,On.sample=function(n){return(af(n)?tt:sr)(n)},On.size=function(n){if(null==n)return 0;if(pu(n))return mu(n)?T(n):n.length;var t=yo(n);return"[object Map]"==t||"[object Set]"==t?n.size:Ht(n).length},On.snakeCase=Tf,On.some=function(n,t,r){var e=af(n)?_:gr;return r&&ze(n,t,r)&&(t=F),e(n,je(t,3))},On.sortedIndex=function(n,t){return dr(n,t)},On.sortedIndexBy=function(n,t,r){return yr(n,t,je(r,2))},On.sortedIndexOf=function(n,t){var r=null==n?0:n.length;if(r){
-var e=dr(n,t);if(e<r&&hu(n[e],t))return e}return-1},On.sortedLastIndex=function(n,t){return dr(n,t,true)},On.sortedLastIndexBy=function(n,t,r){return yr(n,t,je(r,2),true)},On.sortedLastIndexOf=function(n,t){if(null==n?0:n.length){var r=dr(n,t,true)-1;if(hu(n[r],t))return r}return-1},On.startCase=$f,On.startsWith=function(n,t,r){return n=zu(n),r=null==r?0:gt(Ou(r),0,n.length),t=jr(t),n.slice(r,r+t.length)==t},On.subtract=oc,On.sum=function(n){return n&&n.length?k(n,Nu):0},On.sumBy=function(n,t){return n&&n.length?k(n,je(t,2)):0;
-},On.template=function(n,t,r){var e=On.templateSettings;r&&ze(n,t,r)&&(t=F),n=zu(n),t=jf({},t,e,se),r=jf({},t.imports,e.imports,se);var u,i,o=Lu(r),f=I(r,o),c=0;r=t.interpolate||An;var a="__p+='";r=ti((t.escape||An).source+"|"+r.source+"|"+(r===nn?gn:An).source+"|"+(t.evaluate||An).source+"|$","g");var l="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,o,f,l){return e||(e=o),a+=n.slice(c,l).replace(kn,B),r&&(u=true,a+="'+__e("+r+")+'"),f&&(i=true,a+="';"+f+";\n__p+='"),
-e&&(a+="'+((__t=("+e+"))==null?'':__t)+'"),c=l+t.length,t}),a+="';",(t=t.variable)||(a="with(obj){"+a+"}"),a=(i?a.replace(q,""):a).replace(V,"$1").replace(K,"$1;"),a="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(u?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+a+"return __p}",t=Pf(function(){return Qu(o,l+"return "+a).apply(F,f)}),t.source=a,vu(t))throw t;return t},On.times=function(n,t){if(n=Ou(n),1>n||9007199254740991<n)return[];
-var r=4294967295,e=Mi(n,4294967295);for(t=je(t),n-=4294967295,e=E(e,t);++r<n;)t(r);return e},On.toFinite=Eu,On.toInteger=Ou,On.toLength=Su,On.toLower=function(n){return zu(n).toLowerCase()},On.toNumber=Iu,On.toSafeInteger=function(n){return n?gt(Ou(n),-9007199254740991,9007199254740991):0===n?n:0},On.toString=zu,On.toUpper=function(n){return zu(n).toUpperCase()},On.trim=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(cn,""):n&&(t=jr(t))?(n=$(n),r=$(t),t=z(n,r),r=W(n,r)+1,zr(n,t,r).join("")):n;
-},On.trimEnd=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(ln,""):n&&(t=jr(t))?(n=$(n),t=W(n,$(t))+1,zr(n,0,t).join("")):n},On.trimStart=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(an,""):n&&(t=jr(t))?(n=$(n),t=z(n,$(t)),zr(n,t).join("")):n},On.truncate=function(n,t){var r=30,e="...";if(bu(t))var u="separator"in t?t.separator:u,r="length"in t?Ou(t.length):r,e="omission"in t?jr(t.omission):e;n=zu(n);var i=n.length;if(Bn.test(n))var o=$(n),i=o.length;if(r>=i)return n;if(i=r-T(e),1>i)return e;
-if(r=o?zr(o,0,i).join(""):n.slice(0,i),u===F)return r+e;if(o&&(i+=r.length-i),_f(u)){if(n.slice(i).search(u)){var f=r;for(u.global||(u=ti(u.source,zu(dn.exec(u))+"g")),u.lastIndex=0;o=u.exec(f);)var c=o.index;r=r.slice(0,c===F?i:c)}}else n.indexOf(jr(u),i)!=i&&(u=r.lastIndexOf(u),-1<u&&(r=r.slice(0,u)));return r+e},On.unescape=function(n){return(n=zu(n))&&J.test(n)?n.replace(G,ut):n},On.uniqueId=function(n){var t=++ai;return zu(n)+t},On.upperCase=Ff,On.upperFirst=Nf,On.each=ru,On.eachRight=eu,On.first=Ke,
-Zu(On,function(){var n={};return Et(On,function(t,r){ci.call(On.prototype,r)||(n[r]=t)}),n}(),{chain:false}),On.VERSION="4.17.4",u("bind bindKey curry curryRight partial partialRight".split(" "),function(n){On[n].placeholder=On}),u(["drop","take"],function(n,t){Mn.prototype[n]=function(r){r=r===F?1:Di(Ou(r),0);var e=this.__filtered__&&!t?new Mn(this):this.clone();return e.__filtered__?e.__takeCount__=Mi(r,e.__takeCount__):e.__views__.push({size:Mi(r,4294967295),type:n+(0>e.__dir__?"Right":"")}),e},Mn.prototype[n+"Right"]=function(t){
-return this.reverse()[n](t).reverse()}}),u(["filter","map","takeWhile"],function(n,t){var r=t+1,e=1==r||3==r;Mn.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:je(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),u(["head","last"],function(n,t){var r="take"+(t?"Right":"");Mn.prototype[n]=function(){return this[r](1).value()[0]}}),u(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Mn.prototype[n]=function(){return this.__filtered__?new Mn(this):this[r](1);
-}}),Mn.prototype.compact=function(){return this.filter(Nu)},Mn.prototype.find=function(n){return this.filter(n).head()},Mn.prototype.findLast=function(n){return this.reverse().find(n)},Mn.prototype.invokeMap=lr(function(n,t){return typeof n=="function"?new Mn(this):this.map(function(r){return Dt(r,n,t)})}),Mn.prototype.reject=function(n){return this.filter(su(je(n)))},Mn.prototype.slice=function(n,t){n=Ou(n);var r=this;return r.__filtered__&&(0<n||0>t)?new Mn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),
-t!==F&&(t=Ou(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},Mn.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Mn.prototype.toArray=function(){return this.take(4294967295)},Et(Mn.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=On[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);u&&(On.prototype[t]=function(){function t(n){return n=u.apply(On,s([n],f)),e&&h?n[0]:n}var o=this.__wrapped__,f=e?[1]:arguments,c=o instanceof Mn,a=f[0],l=c||af(o);
-l&&r&&typeof a=="function"&&1!=a.length&&(c=l=false);var h=this.__chain__,p=!!this.__actions__.length,a=i&&!h,c=c&&!p;return!i&&l?(o=c?o:new Mn(this),o=n.apply(o,f),o.__actions__.push({func:nu,args:[t],thisArg:F}),new zn(o,h)):a&&c?n.apply(this,f):(o=this.thru(t),a?e?o.value()[0]:o.value():o)})}),u("pop push shift sort splice unshift".split(" "),function(n){var t=ui[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);On.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){
-var u=this.value();return t.apply(af(u)?u:[],n)}return this[r](function(r){return t.apply(af(r)?r:[],n)})}}),Et(Mn.prototype,function(n,t){var r=On[t];if(r){var e=r.name+"";(Ji[e]||(Ji[e]=[])).push({name:t,func:r})}}),Ji[Xr(F,2).name]=[{name:"wrapper",func:F}],Mn.prototype.clone=function(){var n=new Mn(this.__wrapped__);return n.__actions__=Mr(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Mr(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Mr(this.__views__),
-n},Mn.prototype.reverse=function(){if(this.__filtered__){var n=new Mn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},Mn.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=af(t),u=0>r,i=e?t.length:0;n=i;for(var o=this.__views__,f=0,c=-1,a=o.length;++c<a;){var l=o[c],s=l.size;switch(l.type){case"drop":f+=s;break;case"dropRight":n-=s;break;case"take":n=Mi(n,f+s);break;case"takeRight":f=Di(f,n-s)}}if(n={start:f,end:n},o=n.start,f=n.end,n=f-o,
-o=u?f:o-1,f=this.__iteratees__,c=f.length,a=0,l=Mi(n,this.__takeCount__),!e||!u&&i==n&&l==n)return kr(t,this.__actions__);e=[];n:for(;n--&&a<l;){for(o+=r,u=-1,i=t[o];++u<c;){var h=f[u],s=h.type,h=(0,h.iteratee)(i);if(2==s)i=h;else if(!h){if(1==s)continue n;break n}}e[a++]=i}return e},On.prototype.at=Fo,On.prototype.chain=function(){return Xe(this)},On.prototype.commit=function(){return new zn(this.value(),this.__chain__)},On.prototype.next=function(){this.__values__===F&&(this.__values__=ku(this.value()));
-var n=this.__index__>=this.__values__.length;return{done:n,value:n?F:this.__values__[this.__index__++]}},On.prototype.plant=function(n){for(var t,r=this;r instanceof Sn;){var e=Pe(r);e.__index__=0,e.__values__=F,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},On.prototype.reverse=function(){var n=this.__wrapped__;return n instanceof Mn?(this.__actions__.length&&(n=new Mn(this)),n=n.reverse(),n.__actions__.push({func:nu,args:[Je],thisArg:F}),new zn(n,this.__chain__)):this.thru(Je);
-},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return kr(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Ai&&(On.prototype[Ai]=tu),On}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=it, define(function(){return it})):Vn?((Vn.exports=it)._=it,qn._=it):Zn._=it}).call(this);
-
-// https://d3js.org Version 4.8.0. Copyright 2017 Mike Bostock.
-(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return Rs(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Qs?10:o>=Ks?5:o>=tf?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Qs?10:o>=Ks?5:o>=tf?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Qs?i*=10:o>=Ks?i*=5:o>=tf&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+t+",0)"}function a(t){return"translate(0,"+t+")"}function c(t){var n=t.bandwidth()/2;return t.round()&&(n=Math.round(n)),function(e){return t(e)+n}}function s(){return!this.__axis}function f(t,n){function e(e){var u=null==o?n.ticks?n.ticks.apply(n,i):n.domain():o,a=null==f?n.tickFormat?n.tickFormat.apply(n,i):xf:f,g=Math.max(l,0)+p,y=n.range(),m=y[0]+.5,x=y[y.length-1]+.5,b=(n.bandwidth?c:xf)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),S=T.exit(),N=T.enter().append("g").attr("class","tick"),k=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),k=k.merge(N.append("line").attr("stroke","#000").attr(r+"2",d*l).attr(v+"1",.5).attr(v+"2",.5)),E=E.merge(N.append("text").attr("fill","#000").attr(r,d*g).attr(v,.5).attr("dy",t===bf?"0em":t===Mf?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),k=k.transition(e),E=E.transition(e),S=S.transition(e).attr("opacity",Sf).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Sf).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),S.remove(),M.attr("d",t===Tf||t==wf?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),k.attr(r+"2",d*l),E.attr(r,d*g).text(a),w.filter(s).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===wf?"start":t===Tf?"end":"middle"),w.each(function(){this.__axis=b})}var r,i=[],o=null,f=null,l=6,h=6,p=3,d=t===bf||t===Tf?-1:1,v=t===Tf||t===wf?(r="x","y"):(r="y","x"),_=t===bf||t===Mf?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return i=mf.call(arguments),e},e.tickArguments=function(t){return arguments.length?(i=null==t?[]:mf.call(t),e):i.slice()},e.tickValues=function(t){return arguments.length?(o=null==t?null:mf.call(t),e):o&&o.slice()},e.tickFormat=function(t){return arguments.length?(f=t,e):f},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function l(t){return f(bf,t)}function h(t){return f(wf,t)}function p(t){return f(Mf,t)}function d(t){return f(Tf,t)}function v(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new _(r)}function _(t){this._=t}function g(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function y(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function m(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Nf,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function x(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===kf&&n.documentElement.namespaceURI===kf?n.createElement(t):n.createElementNS(e,t)}}function b(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function w(){return new M}function M(){this._="@"+(++zf).toString(36)}function T(t,n,e){return t=S(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function S(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function N(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function k(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function E(t,n,e){var r=Uf.hasOwnProperty(t.type)?T:S;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function A(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function C(){}function z(){return[]}function P(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function L(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new P(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function R(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=Zf+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)s=Zf+u.call(t,o[a],a,o),(c=f[s])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new P(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function q(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function U(t){return function(){this.removeAttribute(t)}}function D(t){return function(){this.removeAttributeNS(t.space,t.local)}}function O(t,n){return function(){this.setAttribute(t,n)}}function F(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function I(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function Y(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function B(t){return function(){this.style.removeProperty(t)}}function j(t,n,e){return function(){this.style.setProperty(t,n,e)}}function H(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function X(t){return function(){delete this[t]}}function V(t,n){return function(){this[t]=n}}function $(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function W(t){return t.trim().split(/^|\s+/)}function Z(t){return t.classList||new G(t)}function G(t){this._node=t,this._names=W(t.getAttribute("class")||"")}function J(t,n){for(var e=Z(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function Q(t,n){for(var e=Z(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function K(t){return function(){J(this,t)}}function tt(t){return function(){Q(this,t)}}function nt(t,n){return function(){(n.apply(this,arguments)?J:Q)(this,t)}}function et(){this.textContent=""}function rt(t){return function(){this.textContent=t}}function it(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function ot(){this.innerHTML=""}function ut(t){return function(){this.innerHTML=t}}function at(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ct(){this.nextSibling&&this.parentNode.appendChild(this)}function st(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ft(){return null}function lt(){var t=this.parentNode;t&&t.removeChild(this)}function ht(t,n,e){var r=cl(t),i=r.CustomEvent;i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function pt(t,n){return function(){return ht(this,t,n)}}function dt(t,n){return function(){return ht(this,t,n.apply(this,arguments))}}function vt(t,n){this._groups=t,this._parents=n}function _t(){return new vt([[document.documentElement]],bl)}function gt(){t.event.stopImmediatePropagation()}function yt(t,n){var e=t.document.documentElement,r=wl(t).on("dragstart.drag",null);n&&(r.on("click.drag",Nl,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function mt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function xt(){return!t.event.button}function bt(){return this.parentNode}function wt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Mt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Tt(){}function St(t){var n;return t=(t+"").trim().toLowerCase(),(n=Rl.exec(t))?(n=parseInt(n[1],16),new Ct(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=ql.exec(t))?Nt(parseInt(n[1],16)):(n=Ul.exec(t))?new Ct(n[1],n[2],n[3],1):(n=Dl.exec(t))?new Ct(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ol.exec(t))?kt(n[1],n[2],n[3],n[4]):(n=Fl.exec(t))?kt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Il.exec(t))?zt(n[1],n[2]/100,n[3]/100,1):(n=Yl.exec(t))?zt(n[1],n[2]/100,n[3]/100,n[4]):Bl.hasOwnProperty(t)?Nt(Bl[t]):"transparent"===t?new Ct(NaN,NaN,NaN,0):null}function Nt(t){return new Ct(t>>16&255,t>>8&255,255&t,1)}function kt(t,n,e,r){return r<=0&&(t=n=e=NaN),new Ct(t,n,e,r)}function Et(t){return t instanceof Tt||(t=St(t)),t?(t=t.rgb(),new Ct(t.r,t.g,t.b,t.opacity)):new Ct}function At(t,n,e,r){return 1===arguments.length?Et(t):new Ct(t,n,e,null==r?1:r)}function Ct(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function zt(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function Pt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Tt||(t=St(t)),!t)return new Rt;if(t instanceof Rt)return t;t=t.rgb();var n=t.r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Lt(t,n,e,r){return 1===arguments.length?Pt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function qt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function Ut(t){if(t instanceof Ot)return new Ot(t.l,t.a,t.b,t.opacity);if(t instanceof Xt){var n=t.h*jl;return new Ot(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Ct||(t=Et(t));var e=Bt(t.r),r=Bt(t.g),i=Bt(t.b),o=Ft((.4124564*e+.3575761*r+.1804375*i)/Xl),u=Ft((.2126729*e+.7151522*r+.072175*i)/Vl);return new Ot(116*u-16,500*(o-u),200*(u-Ft((.0193339*e+.119192*r+.9503041*i)/$l)),t.opacity)}function Dt(t,n,e,r){return 1===arguments.length?Ut(t):new Ot(t,n,e,null==r?1:r)}function Ot(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ft(t){return t>Jl?Math.pow(t,1/3):t/Gl+Wl}function It(t){return t>Zl?t*t*t:Gl*(t-Wl)}function Yt(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Bt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function jt(t){if(t instanceof Xt)return new Xt(t.h,t.c,t.l,t.opacity);t instanceof Ot||(t=Ut(t));var n=Math.atan2(t.b,t.a)*Hl;return new Xt(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Ht(t,n,e,r){return 1===arguments.length?jt(t):new Xt(t,n,e,null==r?1:r)}function Xt(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Vt(t){if(t instanceof Wt)return new Wt(t.h,t.s,t.l,t.opacity);t instanceof Ct||(t=Et(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(oh*r+rh*n-ih*e)/(oh+rh-ih),o=r-i,u=(eh*(e-i)-th*o)/nh,a=Math.sqrt(u*u+o*o)/(eh*i*(1-i)),c=a?Math.atan2(u,o)*Hl-120:NaN;return new Wt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Vt(t):new Wt(t,n,e,null==r?1:r)}function Wt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Zt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Gt(t,n){return function(e){return t+e*n}}function Jt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Qt(t,n){var e=n-t;return e?Gt(t,e>180||e<-180?e-360*Math.round(e/360):e):dh(isNaN(t)?n:t)}function Kt(t){return 1==(t=+t)?tn:function(n,e){return e-n?Jt(n,e,t):dh(isNaN(n)?e:n)}}function tn(t,n){var e=n-t;return e?Gt(t,e):dh(isNaN(t)?n:t)}function nn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=At(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function en(t){return function(){return t}}function rn(t){return function(n){return t(n)+""}}function on(t){return"none"===t?Eh:(uh||(uh=document.createElement("DIV"),ah=document.documentElement,ch=document.defaultView),uh.style.transform=t,t=ch.getComputedStyle(ah.appendChild(uh),null).getPropertyValue("transform"),ah.removeChild(uh),t=t.slice(7,-1).split(","),Ah(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))}function un(t){return null==t?Eh:(sh||(sh=document.createElementNS("http://www.w3.org/2000/svg","g")),sh.setAttribute("transform",t),(t=sh.transform.baseVal.consolidate())?(t=t.matrix,Ah(t.a,t.b,t.c,t.d,t.e,t.f)):Eh)}function an(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:xh(t,i)},{i:c-2,x:xh(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:xh(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:xh(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:xh(t,e)},{i:a-2,x:xh(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function cn(t){return((t=Math.exp(t))+1/t)/2}function sn(t){return((t=Math.exp(t))-1/t)/2}function fn(t){return((t=Math.exp(2*t))-1)/(t+1)}function ln(t){return function(n,e){var r=t((n=Lt(n)).h,(e=Lt(e)).h),i=tn(n.s,e.s),o=tn(n.l,e.l),u=tn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function hn(t,n){var e=tn((t=Dt(t)).l,(n=Dt(n)).l),r=tn(t.a,n.a),i=tn(t.b,n.b),o=tn(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}}function pn(t){return function(n,e){var r=t((n=Ht(n)).h,(e=Ht(e)).h),i=tn(n.c,e.c),o=tn(n.l,e.l),u=tn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function dn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=tn(n.s,r.s),u=tn(n.l,r.l),a=tn(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function vn(){return Vh||(Zh(_n),Vh=Wh.now()+$h)}function _n(){Vh=0}function gn(){this._call=this._time=this._next=null}function yn(t,n,e){var r=new gn;return r.restart(t,n,e),r}function mn(){vn(),++Yh;for(var t,n=fh;n;)(t=Vh-n._time)>=0&&n._call.call(null,t),n=n._next;--Yh}function xn(){Vh=(Xh=Wh.now())+$h,Yh=Bh=0;try{mn()}finally{Yh=0,wn(),Vh=0}}function bn(){var t=Wh.now(),n=t-Xh;n>Hh&&($h-=n,Xh=t)}function wn(){for(var t,n,e=fh,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:fh=n);lh=t,Mn(r)}function Mn(t){if(!Yh){Bh&&(Bh=clearTimeout(Bh));var n=t-Vh;n>24?(t<1/0&&(Bh=setTimeout(xn,n)),jh&&(jh=clearInterval(jh))):(jh||(Xh=Vh,jh=setInterval(bn,Hh)),Yh=1,Zh(xn))}}function Tn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>tp)throw new Error("too late");return e}function Sn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ep)throw new Error("too late");return e}function Nn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function kn(t,n,e){function r(t){e.state=np,e.timer.restart(i,e.delay,e.time),e.delay<=t&&i(t-e.delay)}function i(r){var s,f,l,h;if(e.state!==np)return u();for(s in c)if(h=c[s],h.name===e.name){if(h.state===rp)return Gh(i);h.state===ip?(h.state=up,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete c[s]):+s<n&&(h.state=up,h.timer.stop(),delete c[s])}if(Gh(function(){e.state===rp&&(e.state=ip,e.timer.restart(o,e.delay,e.time),o(r))}),e.state=ep,e.on.call("start",t,t.__data__,e.index,e.group),e.state===ep){for(e.state=rp,a=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(a[++f]=h);a.length=f+1}}function o(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=op,1),i=-1,o=a.length;++i<o;)a[i].call(null,r);e.state===op&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){e.state=up,e.timer.stop(),delete c[n];for(var r in c)return;delete t.__transition}var a,c=t.__transition;c[n]=e,e.timer=yn(r,0,e.time)}function En(t,n){var e,r;return function(){var i=Sn(this,t),o=i.tween;if(o!==e){r=e=o;for(var u=0,a=r.length;u<a;++u)if(r[u].name===n){r=r.slice(),r.splice(u,1);break}}i.tween=r}}function An(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Sn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Cn(t,n,e){var r=t._id;return t.each(function(){var t=Sn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Nn(t,r).value[n]}}function zn(t){return function(){this.removeAttribute(t)}}function Pn(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Ln(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Rn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function qn(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttribute(t):(u=this.getAttribute(t),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Un(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttributeNS(t.space,t.local):(u=this.getAttributeNS(t.space,t.local),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Dn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function On(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function Fn(t,n){return function(){Tn(this,t).delay=+n.apply(this,arguments)}}function In(t,n){return n=+n,function(){Tn(this,t).delay=n}}function Yn(t,n){return function(){Sn(this,t).duration=+n.apply(this,arguments)}}function Bn(t,n){return n=+n,function(){Sn(this,t).duration=n}}function jn(t,n){if("function"!=typeof n)throw new Error;return function(){Sn(this,t).ease=n}}function Hn(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Xn(t,n,e){var r,i,o=Hn(n)?Tn:Sn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Vn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function $n(t,n){var e,r,i;return function(){var o=cl(this).getComputedStyle(this,null),u=o.getPropertyValue(t),a=(this.style.removeProperty(t),o.getPropertyValue(t));return u===a?null:u===e&&a===r?i:i=n(e=u,r=a)}}function Wn(t){return function(){this.style.removeProperty(t)}}function Zn(t,n,e){var r,i;return function(){var o=cl(this).getComputedStyle(this,null).getPropertyValue(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Gn(t,n,e){var r,i,o;return function(){var u=cl(this).getComputedStyle(this,null),a=u.getPropertyValue(t),c=e(this);return null==c&&(this.style.removeProperty(t),c=u.getPropertyValue(t)),a===c?null:a===r&&c===i?o:o=n(r=a,i=c)}}function Jn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Qn(t){return function(){this.textContent=t}}function Kn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function te(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function ne(t){return _t().transition(t)}function ee(){return++Ap}function re(t){return+t}function ie(t){return t*t}function oe(t){return t*(2-t)}function ue(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function ae(t){return t*t*t}function ce(t){return--t*t*t+1}function se(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function fe(t){return 1-Math.cos(t*qp)}function le(t){return Math.sin(t*qp)}function he(t){return(1-Math.cos(Rp*t))/2}function pe(t){return Math.pow(2,10*t-10)}function de(t){return 1-Math.pow(2,-10*t)}function ve(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function _e(t){return 1-Math.sqrt(1-t*t)}function ge(t){return Math.sqrt(1- --t*t)}function ye(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function me(t){return 1-xe(1-t)}function xe(t){return(t=+t)<Up?Xp*t*t:t<Op?Xp*(t-=Dp)*t+Fp:t<Yp?Xp*(t-=Ip)*t+Bp:Xp*(t-=jp)*t+Hp}function be(t){return((t*=2)<=1?1-xe(1-t):xe(t-1)+1)/2}function we(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return Kp.time=vn(),Kp;return e}function Me(){t.event.stopImmediatePropagation()}function Te(t){return{type:t}}function Se(){return!t.event.button}function Ne(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function ke(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Ee(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Ae(t){var n=t.__brush;return n?n.dim.output(n.selection):null}function Ce(){return Pe(fd)}function ze(){return Pe(ld)}function Pe(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([Te("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",pd.overlay).merge(e).each(function(){var t=ke(this).extent;wl(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([Te("selection")]).enter().append("rect").attr("class","selection").attr("cursor",pd.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return pd[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=wl(this),n=ke(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-h/2:n[0][0]-h/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-h/2:n[0][1]-h/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+h:h}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+h:h})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=If(T);!U||w||M||(Math.abs(t[0]-O[0])>Math.abs(t[1]-O[1])?M=!0:w=!0),O=t,b=!0,od(),o()}function o(){var t;switch(m=O[0]-D[0],x=O[1]-D[1],N){case ad:case ud:k&&(m=Math.max(P-l,Math.min(R-v,m)),h=l+m,_=v+m),E&&(x=Math.max(L-p,Math.min(q-g,x)),d=p+x,y=g+x);break;case cd:k<0?(m=Math.max(P-l,Math.min(R-l,m)),h=l+m,_=v):k>0&&(m=Math.max(P-v,Math.min(R-v,m)),h=l,_=v+m),E<0?(x=Math.max(L-p,Math.min(q-p,x)),d=p+x,y=g):E>0&&(x=Math.max(L-g,Math.min(q-g,x)),d=p,y=g+x);break;case sd:k&&(h=Math.max(P,Math.min(R,l-m*k)),_=Math.max(P,Math.min(R,v+m*k))),E&&(d=Math.max(L,Math.min(q,p-x*E)),y=Math.max(L,Math.min(q,g+x*E)))}_<h&&(k*=-1,t=l,l=v,v=t,t=h,h=_,_=t,S in dd&&Y.attr("cursor",pd[S=dd[S]])),y<d&&(E*=-1,t=p,p=g,g=t,t=d,d=y,y=t,S in vd&&Y.attr("cursor",pd[S=vd[S]])),A.selection&&(z=A.selection),w&&(h=z[0][0],_=z[1][0]),M&&(d=z[0][1],y=z[1][1]),z[0][0]===h&&z[0][1]===d&&z[1][0]===_&&z[1][1]===y||(A.selection=[[h,d],[_,y]],r.call(T),F.brush())}function u(){if(Me(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),I.on("touchmove.brush touchend.brush touchcancel.brush",null)}else yt(t.event.view,b),B.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);I.attr("pointer-events","all"),Y.attr("cursor",pd.overlay),A.selection&&(z=A.selection),Ee(z)&&(A.selection=null,r.call(T)),F.end()}function a(){switch(t.event.keyCode){case 16:U=k&&E;break;case 18:N===cd&&(k&&(v=_-m*k,l=h+m*k),E&&(g=y-x*E,p=d+x*E),N=sd,o());break;case 32:N!==cd&&N!==sd||(k<0?v=_-m:k>0&&(l=h-m),E<0?g=y-x:E>0&&(p=d-x),N=ad,Y.attr("cursor",pd.selection),o());break;default:return}od()}function s(){switch(t.event.keyCode){case 16:U&&(w=M=U=!1,o());break;case 18:N===sd&&(k<0?v=_:k>0&&(l=h),E<0?g=y:E>0&&(p=d),N=cd,o());break;case 32:N===ad&&(t.event.altKey?(k&&(v=_-m*k,l=h+m*k),E&&(g=y-x*E,p=d+x*E),N=sd):(k<0?v=_:k>0&&(l=h),E<0?g=y:E>0&&(p=d),N=cd),Y.attr("cursor",pd[S]),o());break;default:return}od()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return od()}else if(c)return;if(f.apply(this,arguments)){var l,h,p,d,v,_,g,y,m,x,b,w,M,T=this,S=t.event.target.__data__.type,N="selection"===(t.event.metaKey?S="overlay":S)?ud:t.event.altKey?sd:cd,k=n===ld?null:_d[S],E=n===fd?null:gd[S],A=ke(T),C=A.extent,z=A.selection,P=C[0][0],L=C[0][1],R=C[1][0],q=C[1][1],U=k&&E&&t.event.shiftKey,D=If(T),O=D,F=i(T,arguments).beforestart();"overlay"===S?A.selection=z=[[l=n===ld?P:D[0],p=n===fd?L:D[1]],[v=n===ld?R:l,g=n===fd?q:p]]:(l=z[0][0],p=z[0][1],v=z[1][0],g=z[1][1]),h=l,d=p,_=v,y=g;var I=wl(T).attr("pointer-events","none"),Y=I.selectAll(".overlay").attr("cursor",pd[S]);if(t.event.touches)I.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var B=wl(t.event.view).on("keydown.brush",a,!0).on("keyup.brush",s,!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);kl(t.event.view)}Me(),cp(T),r.call(T),F.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=Ne,f=Se,l=v(e,"start","brush","end"),h=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&Ee(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=Sh(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();cp(t),u.selection=null==a||Ee(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){A(new id(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:rd([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:rd(!!t),e):f},e.handleSize=function(t){return arguments.length?(h=+t,e):h},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function Le(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function Re(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function qe(){return new Re}function Ue(t){return t.source}function De(t){return t.target}function Oe(t){return t.radius}function Fe(t){return t.startAngle}function Ie(t){return t.endAngle}function Ye(){}function Be(t,n){var e=new Ye;if(t instanceof Ye)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function je(){return{}}function He(t,n,e){t[n]=e}function Xe(){return Be()}function Ve(t,n,e){t.set(n,e)}function $e(){}function We(t,n){var e=new $e;if(t instanceof $e)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ze(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ge(t,n){var e=Ze(t);return function(r,i){return n(e(r),i,t)}}function Je(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Qe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,g=t._x1,y=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+g)/2))?v=o:g=o,(f=e>=(u=(_+y)/2))?_=u:y=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+g)/2))?v=o:g=o,(f=e>=(u=(_+y)/2))?_=u:y=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Ke(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Qe(this,u[e],a[e],t[e]);return this}function tr(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this}function nr(t){return t[0]}function er(t){return t[1]}function rr(t,n,e){var r=new ir(null==n?nr:n,null==e?er:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function ir(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function or(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function ur(t){return t.x+t.vx}function ar(t){return t.y+t.vy}function cr(t){return t.index}function sr(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function fr(t){return t.x}function lr(t){return t.y}function hr(t){return new pr(t)}function pr(t){if(!(n=Ev.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,
-f="g"):kv[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function dr(n){return Av=Pv(n),t.format=Av.format,t.formatPrefix=Av.formatPrefix,Av}function vr(){this.reset()}function _r(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function gr(t){return t>1?0:t<-1?__:Math.acos(t)}function yr(t){return t>1?g_:t<-1?-g_:Math.asin(t)}function mr(t){return(t=C_(t/2))*t}function xr(){}function br(t,n){t&&q_.hasOwnProperty(t.type)&&q_[t.type](t,n)}function wr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Mr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)wr(t[e],n,1);n.polygonEnd()}function Tr(){F_.point=Nr}function Sr(){kr(Dv,Ov)}function Nr(t,n){F_.point=kr,Dv=t,Ov=n,t*=b_,n*=b_,Fv=t,Iv=S_(n=n/2+y_),Yv=C_(n)}function kr(t,n){t*=b_,n*=b_,n=n/2+y_;var e=t-Fv,r=e>=0?1:-1,i=r*e,o=S_(n),u=C_(n),a=Yv*u,c=Iv*o+a*S_(i),s=a*r*C_(i);D_.add(T_(s,c)),Fv=t,Iv=o,Yv=u}function Er(t){return[T_(t[1],t[0]),yr(t[2])]}function Ar(t){var n=t[0],e=t[1],r=S_(e);return[r*S_(n),r*C_(n),C_(e)]}function Cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function zr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Pr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Rr(t){var n=P_(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function qr(t,n){Gv.push(Jv=[Bv=t,Hv=t]),n<jv&&(jv=n),n>Xv&&(Xv=n)}function Ur(t,n){var e=Ar([t*b_,n*b_]);if(Zv){var r=zr(Zv,e),i=[r[1],-r[0],0],o=zr(i,r);Rr(o),o=Er(o);var u,a=t-Vv,c=a>0?1:-1,s=o[0]*x_*c,f=w_(a)>180;f^(c*Vv<s&&s<c*t)?(u=o[1]*x_)>Xv&&(Xv=u):(s=(s+360)%360-180,f^(c*Vv<s&&s<c*t)?(u=-o[1]*x_)<jv&&(jv=u):(n<jv&&(jv=n),n>Xv&&(Xv=n))),f?t<Vv?Br(Bv,t)>Br(Bv,Hv)&&(Hv=t):Br(t,Hv)>Br(Bv,Hv)&&(Bv=t):Hv>=Bv?(t<Bv&&(Bv=t),t>Hv&&(Hv=t)):t>Vv?Br(Bv,t)>Br(Bv,Hv)&&(Hv=t):Br(t,Hv)>Br(Bv,Hv)&&(Bv=t)}else Gv.push(Jv=[Bv=t,Hv=t]);n<jv&&(jv=n),n>Xv&&(Xv=n),Zv=e,Vv=t}function Dr(){B_.point=Ur}function Or(){Jv[0]=Bv,Jv[1]=Hv,B_.point=qr,Zv=null}function Fr(t,n){if(Zv){var e=t-Vv;Y_.add(w_(e)>180?e+(e>0?360:-360):e)}else $v=t,Wv=n;F_.point(t,n),Ur(t,n)}function Ir(){F_.lineStart()}function Yr(){Fr($v,Wv),F_.lineEnd(),w_(Y_)>v_&&(Bv=-(Hv=180)),Jv[0]=Bv,Jv[1]=Hv,Zv=null}function Br(t,n){return(n-=t)<0?n+360:n}function jr(t,n){return t[0]-n[0]}function Hr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Xr(t,n){t*=b_,n*=b_;var e=S_(n);Vr(e*S_(t),e*C_(t),C_(n))}function Vr(t,n,e){++Qv,t_+=(t-t_)/Qv,n_+=(n-n_)/Qv,e_+=(e-e_)/Qv}function $r(){H_.point=Wr}function Wr(t,n){t*=b_,n*=b_;var e=S_(n);l_=e*S_(t),h_=e*C_(t),p_=C_(n),H_.point=Zr,Vr(l_,h_,p_)}function Zr(t,n){t*=b_,n*=b_;var e=S_(n),r=e*S_(t),i=e*C_(t),o=C_(n),u=T_(P_((u=h_*o-p_*i)*u+(u=p_*r-l_*o)*u+(u=l_*i-h_*r)*u),l_*r+h_*i+p_*o);Kv+=u,r_+=u*(l_+(l_=r)),i_+=u*(h_+(h_=i)),o_+=u*(p_+(p_=o)),Vr(l_,h_,p_)}function Gr(){H_.point=Xr}function Jr(){H_.point=Kr}function Qr(){ti(s_,f_),H_.point=Xr}function Kr(t,n){s_=t,f_=n,t*=b_,n*=b_,H_.point=ti;var e=S_(n);l_=e*S_(t),h_=e*C_(t),p_=C_(n),Vr(l_,h_,p_)}function ti(t,n){t*=b_,n*=b_;var e=S_(n),r=e*S_(t),i=e*C_(t),o=C_(n),u=h_*o-p_*i,a=p_*r-l_*o,c=l_*i-h_*r,s=P_(u*u+a*a+c*c),f=yr(s),l=s&&-f/s;u_+=l*u,a_+=l*a,c_+=l*c,Kv+=f,r_+=f*(l_+(l_=r)),i_+=f*(h_+(h_=i)),o_+=f*(p_+(p_=o)),Vr(l_,h_,p_)}function ni(t,n){return[t>__?t-m_:t<-__?t+m_:t,n]}function ei(t,n,e){return(t%=m_)?n||e?$_(ii(t),oi(n,e)):ii(t):n||e?oi(n,e):ni}function ri(t){return function(n,e){return n+=t,[n>__?n-m_:n<-__?n+m_:n,e]}}function ii(t){var n=ri(t);return n.invert=ri(-t),n}function oi(t,n){function e(t,n){var e=S_(n),a=S_(t)*e,c=C_(t)*e,s=C_(n),f=s*r+a*i;return[T_(c*o-f*u,a*r-s*i),yr(f*o+c*u)]}var r=S_(t),i=C_(t),o=S_(n),u=C_(n);return e.invert=function(t,n){var e=S_(n),a=S_(t)*e,c=C_(t)*e,s=C_(n),f=s*o-c*u;return[T_(c*o+s*u,a*r+f*i),yr(f*r-a*i)]},e}function ui(t,n,e,r,i,o){if(e){var u=S_(n),a=C_(n),c=r*e;null==i?(i=n+r*m_,o=n-c/2):(i=ai(u,i),o=ai(u,o),(r>0?i<o:i>o)&&(i+=r*m_));for(var s,f=i;r>0?f>o:f<o;f-=c)s=Er([u,-a*S_(f),-a*C_(f)]),t.point(s[0],s[1])}}function ai(t,n){n=Ar(n),n[0]-=t,Rr(n);var e=gr(-n[1]);return((-n[2]<0?-e:e)+m_-v_)%m_}function ci(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function si(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function fi(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return w_(r[0]-t)<v_?i>0?0:3:w_(r[0]-e)<v_?i>0?2:1:w_(r[1]-n)<v_?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&N.point(t,n)}function s(){for(var n=0,e=0,i=_.length;e<i;++e)for(var o,u,a=_[e],c=1,s=a.length,f=a[0],l=f[0],h=f[1];c<s;++c)o=l,u=h,f=a[c],l=f[0],h=f[1],u<=r?h>r&&(l-o)*(r-u)>(h-u)*(t-o)&&++n:h<=r&&(l-o)*(r-u)<(h-u)*(t-o)&&--n;return n}function f(){N=k,v=[],_=[],S=!0}function l(){var t=s(),n=S&&t,e=(v=lf(v)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&fg(v,a,t,o,u),u.polygonEnd()),N=u,v=_=g=null}function h(){E.point=d,_&&_.push(g=[]),T=!0,M=!1,b=w=NaN}function p(){v&&(d(y,m),x&&M&&k.rejoin(),v.push(k.result())),E.point=c,M&&N.lineEnd()}function d(o,u){var a=i(o,u);if(_&&g.push([o,u]),T)y=o,m=u,x=a,T=!1,a&&(N.lineStart(),N.point(o,u));else if(a&&M)N.point(o,u);else{var c=[b=Math.max(hg,Math.min(lg,b)),w=Math.max(hg,Math.min(lg,w))],s=[o=Math.max(hg,Math.min(lg,o)),u=Math.max(hg,Math.min(lg,u))];cg(c,s,t,n,e,r)?(M||(N.lineStart(),N.point(c[0],c[1])),N.point(s[0],s[1]),a||N.lineEnd(),S=!1):a&&(N.lineStart(),N.point(o,u),S=!1)}b=o,w=u,M=a}var v,_,g,y,m,x,b,w,M,T,S,N=u,k=ag(),E={point:c,lineStart:h,lineEnd:p,polygonStart:f,polygonEnd:l};return E}}function li(){gg.point=pi,gg.lineEnd=hi}function hi(){gg.point=gg.lineEnd=xr}function pi(t,n){t*=b_,n*=b_,W_=t,Z_=C_(n),G_=S_(n),gg.point=di}function di(t,n){t*=b_,n*=b_;var e=C_(n),r=S_(n),i=w_(t-W_),o=S_(i),u=C_(i),a=r*u,c=G_*e-Z_*r*o,s=Z_*e+G_*r*o;_g.add(T_(P_(a*a+c*c),s)),W_=t,Z_=e,G_=r}function vi(t,n){return!(!t||!Mg.hasOwnProperty(t.type))&&Mg[t.type](t,n)}function _i(t,n){return 0===bg(t,n)}function gi(t,n){var e=bg(t[0],t[1]);return bg(t[0],n)+bg(n,t[1])<=e+v_}function yi(t,n){return!!vg(t.map(mi),xi(n))}function mi(t){return t=t.map(xi),t.pop(),t}function xi(t){return[t[0]*b_,t[1]*b_]}function bi(t,n,e){var r=Js(t,n-v_,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function wi(t,n,e){var r=Js(t,n-v_,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Mi(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Js(N_(o/_)*_,i,_).map(h).concat(Js(N_(s/g)*g,c,g).map(p)).concat(Js(N_(r/d)*d,e,d).filter(function(t){return w_(t%_)>v_}).map(f)).concat(Js(N_(a/v)*v,u,v).filter(function(t){return w_(t%g)>v_}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,g=360,y=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(y)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(y)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],g=+n[1],t):[_,g]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(y=+n,f=bi(a,u,90),l=wi(r,e,y),h=bi(s,c,90),p=wi(o,i,y),t):y},t.extentMajor([[-180,-90+v_],[180,90-v_]]).extentMinor([[-180,-80-v_],[180,80+v_]])}function Ti(){return Mi()()}function Si(){Ag.point=Ni}function Ni(t,n){Ag.point=ki,J_=K_=t,Q_=tg=n}function ki(t,n){Eg.add(tg*t-K_*n),K_=t,tg=n}function Ei(){ki(J_,Q_)}function Ai(t,n){t<Cg&&(Cg=t),t>Pg&&(Pg=t),n<zg&&(zg=n),n>Lg&&(Lg=n)}function Ci(t,n){qg+=t,Ug+=n,++Dg}function zi(){Hg.point=Pi}function Pi(t,n){Hg.point=Li,Ci(rg=t,ig=n)}function Li(t,n){var e=t-rg,r=n-ig,i=P_(e*e+r*r);Og+=i*(rg+t)/2,Fg+=i*(ig+n)/2,Ig+=i,Ci(rg=t,ig=n)}function Ri(){Hg.point=Ci}function qi(){Hg.point=Di}function Ui(){Oi(ng,eg)}function Di(t,n){Hg.point=Oi,Ci(ng=rg=t,eg=ig=n)}function Oi(t,n){var e=t-rg,r=n-ig,i=P_(e*e+r*r);Og+=i*(rg+t)/2,Fg+=i*(ig+n)/2,Ig+=i,i=ig*t-rg*n,Yg+=i*(rg+t),Bg+=i*(ig+n),jg+=3*i,Ci(rg=t,ig=n)}function Fi(t){this._context=t}function Ii(t,n){Jg.point=Yi,Vg=Wg=t,$g=Zg=n}function Yi(t,n){Wg-=t,Zg-=n,Gg.add(P_(Wg*Wg+Zg*Zg)),Wg=t,Zg=n}function Bi(){this._string=[]}function ji(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Hi(t){return t.length>1}function Xi(t,n){return((t=t.x)[0]<0?t[1]-g_-v_:g_-t[1])-((n=n.x)[0]<0?n[1]-g_-v_:g_-n[1])}function Vi(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?__:-__,c=w_(o-e);w_(c-__)<v_?(t.point(e,r=(r+u)/2>0?g_:-g_),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=__&&(w_(e-i)<v_&&(e-=i*v_),w_(o-a)<v_&&(o-=a*v_),r=$i(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}function $i(t,n,e,r){var i,o,u=C_(t-e);return w_(u)>v_?M_((C_(n)*(o=S_(r))*C_(e)-C_(r)*(i=S_(n))*C_(t))/(i*o*u)):(n+r)/2}function Wi(t,n,e,r){var i;if(null==t)i=e*g_,r.point(-__,i),r.point(0,i),r.point(__,i),r.point(__,0),r.point(__,-i),r.point(0,-i),r.point(-__,-i),r.point(-__,0),r.point(-__,i);else if(w_(t[0]-n[0])>v_){var o=t[0]<n[0]?__:-__;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}function Zi(t){return function(n){var e=new Gi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Gi(){}function Ji(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),U_(e,t.stream(Rg));var u=Rg.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function Qi(t,n,e){return Ji(t,[[0,0],n],e)}function Ki(t){return Zi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function to(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var g=s-r,y=f-i,m=g*g+y*y;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=P_(x*x+b*b+w*w),T=yr(w/=M),S=w_(w_(w)-1)<v_||w_(o-l)<v_?(o+l)/2:T_(b,x),N=t(S,T),k=N[0],E=N[1],A=k-r,C=E-i,z=y*A-g*C;(z*z/m>n||w_((g*A+y*C)/m-.5)>.3||u*h+a*p+c*d<iy)&&(e(r,i,o,u,a,c,k,E,S,x/=M,b/=M,w,v,_),_.point(k,E),e(k,E,S,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){g=NaN,w.point=o,n.lineStart()}function o(r,i){var o=Ar([r,i]),u=t(r,i);e(g,y,_,m,x,b,g=u[0],y=u[1],_=r,m=o[0],x=o[1],b=o[2],ry,n),n.point(g,y)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=g,h=y,p=m,d=x,v=b,w.point=o}function s(){e(g,y,_,m,x,b,l,h,f,p,d,v,ry,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,g,y,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function no(t){return eo(function(){return t})()}function eo(t){function n(t){return t=f(t[0]*b_,t[1]*b_),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*x_,t[1]*x_]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=$_(s=ei(b,w,M),u);var t=u(m,x);return a=g-t[0]*_,c=y+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,g=480,y=250,m=0,x=0,b=0,w=0,M=0,T=null,S=ty,N=null,k=Ng,E=.5,A=oy(r,E);return n.stream=function(t){return d&&v===t?d:d=uy(S(s,A(k(v=t))))},n.clipAngle=function(t){return arguments.length?(S=+t?ny(T=t*b_,6*b_):(T=null,ty),o()):T*x_},n.clipExtent=function(t){return arguments.length?(k=null==t?(N=l=h=p=null,Ng):fi(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(g=+t[0],y=+t[1],i()):[g,y]},n.center=function(t){return arguments.length?(m=t[0]%360*b_,x=t[1]%360*b_,i()):[m*x_,x*x_]},n.rotate=function(t){return arguments.length?(b=t[0]%360*b_,w=t[1]%360*b_,M=t.length>2?t[2]%360*b_:0,i()):[b*x_,w*x_,M*x_]},n.precision=function(t){return arguments.length?(A=oy(r,E=t*t),o()):P_(E)},n.fitExtent=function(t,e){return Ji(n,t,e)},n.fitSize=function(t,e){return Qi(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function ro(t){var n=0,e=__/3,r=eo(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*b_,e=t[1]*b_):[n*x_,e*x_]},i}function io(t){function n(t,n){return[t*e,C_(n)/e]}var e=S_(t);return n.invert=function(t,n){return[t/e,yr(n*e)]},n}function oo(t,n){function e(t,n){var e=P_(o-2*i*C_(n))/i;return[e*C_(t*=i),u-e*S_(t)]}var r=C_(t),i=(r+C_(n))/2;if(w_(i)<v_)return io(t);var o=1+r*(2*i-r),u=P_(o)/i;return e.invert=function(t,n){var e=u-n;return[T_(t,w_(e))/i*z_(e),yr((o-(t*t+e*e)*i*i)/(2*i))]},e}function uo(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function ao(t){return function(n,e){var r=S_(n),i=S_(e),o=t(r*i);return[o*i*C_(n),o*C_(e)]}}function co(t){return function(n,e){var r=P_(n*n+e*e),i=t(r),o=C_(i),u=S_(i);return[T_(n*o,r*u),yr(r&&e*o/r)]}}function so(t,n){return[t,E_(L_((g_+n)/2))]}function fo(t){function n(){var n=__*a(),u=o(og(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===so?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=no(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function lo(t){return L_((g_+t)/2)}function ho(t,n){function e(t,n){o>0?n<-g_+v_&&(n=-g_+v_):n>g_-v_&&(n=g_-v_);var e=o/A_(lo(n),i);return[e*C_(i*t),o-e*S_(i*t)]}var r=S_(t),i=t===n?C_(t):E_(r/S_(n))/E_(lo(n)/lo(t)),o=r*A_(lo(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=z_(i)*P_(t*t+e*e);return[T_(t,w_(e))/i*z_(e),2*M_(A_(o/r,1/i))-g_]},e):so}function po(t,n){return[t,n]}function vo(t,n){function e(t,n){var e=o-n,r=i*t;return[e*C_(r),o-e*S_(r)]}var r=S_(t),i=t===n?C_(t):(r-S_(n))/(n-t),o=r/i+t;return w_(i)<v_?po:(e.invert=function(t,n){var e=o-n;return[T_(t,w_(e))/i*z_(e),o-z_(i)*P_(t*t+e*e)]},e)}function _o(t,n){var e=S_(n),r=S_(t)*e;return[e*C_(t)/r,C_(n)/r]}function go(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?Ng:Zi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function yo(t,n){return[S_(n)*C_(t),C_(n)]}function mo(t,n){var e=S_(n),r=1+S_(t)*e;return[e*C_(t)/r,C_(n)/r]}function xo(t,n){return[E_(L_((g_+n)/2)),-t]}function bo(t,n){return t.parent===n.parent?1:2}function wo(t){return t.reduce(Mo,0)/t.length}function Mo(t,n){return t+n.x}function To(t){return 1+t.reduce(So,0)}function So(t,n){return Math.max(t,n.y)}function No(t){for(var n;n=t.children;)t=n[0];return t}function ko(t){for(var n;n=t.children;)t=n[n.length-1];return t}function Eo(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Ao(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function Co(t,n){var e,r,i,o,u,a=new qo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=Po);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new qo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Ro)}function zo(){return Co(this).eachBefore(Lo)}function Po(t){return t.children}function Lo(t){t.data=t.data.data}function Ro(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function qo(t){this.data=t,this.depth=this.height=0,this.parent=null}function Uo(t){this._=t,this.next=null}function Do(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r-n.r;return i*i+1e-6>e*e+r*r}function Oo(t,n){var e,r,i,o=null,u=t.head;switch(n.length){case 1:e=Fo(n[0]);break;case 2:e=Io(n[0],n[1]);break;case 3:e=Yo(n[0],n[1],n[2])}for(;u;)i=u._,r=u.next,e&&Do(e,i)?o=u:(o?(t.tail=o,o.next=null):t.head=t.tail=null,n.push(i),e=Oo(t,n),n.pop(),t.head?(u.next=t.head,t.head=u):(u.next=null,t.head=t.tail=u),o=t.tail,o.next=r),u=r;return t.tail=o,e}function Fo(t){return{x:t.x,y:t.y,r:t.r}}function Io(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function Yo(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=2*(r-u),p=2*(i-a),d=2*(c-o),v=r*r+i*i-o*o-u*u-a*a+c*c,_=2*(r-s),g=2*(i-f),y=2*(l-o),m=r*r+i*i-o*o-s*s-f*f+l*l,x=_*p-h*g,b=(p*m-g*v)/x-r,w=(g*d-p*y)/x,M=(_*v-h*m)/x-i,T=(h*y-_*d)/x,S=w*w+T*T-1,N=2*(b*w+M*T+o),k=b*b+M*M-o*o,E=(-N-Math.sqrt(N*N-4*S*k))/(2*S);return{x:b+w*E+r,y:M+T*E+i,r:E}}function Bo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function jo(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function Ho(t,n,e){var r=t._,i=t.next._,o=r.r+i.r,u=(r.x*i.r+i.x*r.r)/o-n,a=(r.y*i.r+i.y*r.r)/o-e;return u*u+a*a}function Xo(t){this._=t,this.next=null,this.previous=null}function Vo(t){if(!(i=t.length))return 0;var n,e,r,i;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Bo(e,n,r=t[2]);var o,u,a,c,s,f,l,h=n.r*n.r,p=e.r*e.r,d=r.r*r.r,v=h+p+d,_=h*n.x+p*e.x+d*r.x,g=h*n.y+p*e.y+d*r.y;n=new Xo(n),e=new Xo(e),r=new Xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){Bo(n._,e._,r=t[a]),r=new Xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(jo(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(jo(s._,r._)){n=s,n.next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,v+=d=r._.r*r._.r,_+=d*r._.x,g+=d*r._.y,h=Ho(n,o=_/v,u=g/v);(r=r.next)!==e;)(d=Ho(r,o,u))<h&&(n=r,h=d);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Uy(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function $o(t){return null==t?null:Wo(t)}function Wo(t){if("function"!=typeof t)throw new Error;return t}function Zo(){return 0}function Go(t){return Math.sqrt(t.value)}function Jo(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Qo(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=Vo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Ko(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function tu(t){return t.id}function nu(t){return t.parentId}function eu(t,n){return t.parent===n.parent?1:2}function ru(t){var n=t.children;return n?n[0]:t.t}function iu(t){var n=t.children;return n?n[n.length-1]:t.t}function ou(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function uu(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)n=i[o],n.z+=e,n.m+=e,e+=n.s+(r+=n.c)}function au(t,n,e){return t.a.parent===n.parent?t.a:e}function cu(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function su(t){for(var n,e,r,i,o,u=new cu(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new cu(r[i],i)),e.parent=n;return(u.parent=new cu(null,0)).children=[u],u}function fu(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,g=[],y=n.children,m=0,x=0,b=y.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=y[x++].value}while(!f&&x<b);for(l=h=f,v=Math.max(s/c,c/s)/(w*t),_=f*f*v,d=Math.max(h/_,_/l);x<b;++x){if(f+=a=y[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}g.push(u={value:f,dice:c<s,children:y.slice(m,x)}),u.dice?Yy(u,e,r,i,w?r+=s*f/w:o):Wy(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return g}function lu(t,n){return t[0]-n[0]||t[1]-n[1]}function hu(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&rm(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function pu(t){if(!(t>=1))throw new Error;this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function du(t){if(!t._start)try{vu(t)}catch(n){if(t._tasks[t._ended+t._active-1])gu(t,n);else if(!t._data)throw n}}function vu(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=_u(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||cm)}}function _u(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?gu(t,e):(t._data[n]=r,t._waiting?du(t):yu(t))))}}function gu(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,yu(t)}function yu(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function mu(t){return new pu(arguments.length?+t:1/0)}function xu(t){return function(n,e){t(null==n?e:null)}}function bu(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function wu(t,n){return function(e){return t(e.responseText,n)}}function Mu(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==km)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=Be(),r=[],i=km;return t=null==t?[]:Nm.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=Be();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=Nm.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Mu().domain(r).range(t).unknown(i)},n}function Tu(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Js(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Mu().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Tu().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function Su(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return Su(n())},t}function Nu(){return Su(Tu().paddingInner(1))}function ku(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:Em(n)}function Eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function Au(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function Cu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function zu(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=Ds(t,n,1,i)-1;return u[e](o[e](n))}}function Pu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function Lu(t,n){function e(){return i=Math.min(a.length,c.length)>2?zu:Cu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?Eu(t):t,s)))(+n)}var i,o,u,a=Cm,c=Cm,s=Sh,f=!1;return r.invert=function(t){return(u||(u=i(c,a,ku,f?Au(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=Sm.call(t,Am),e()):a.slice()},r.range=function(t){return arguments.length?(c=Nm.call(t),e()):c.slice()},r.rangeRound=function(t){return c=Nm.call(t),s=Nh,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function Ru(t){var n=t.domain;return t.ticks=function(t){var e=n();return nf(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return zm(n(),t,e)},t.nice=function(e){var r=n(),o=r.length-1,u=null==e?10:e,a=r[0],c=r[o],s=i(a,c,u);return s&&(s=i(Math.floor(a/s)*s,Math.ceil(c/s)*s,u),r[0]=Math.floor(a/s)*s,r[o]=Math.ceil(c/s)*s,n(r)),t},t}function qu(){var t=Lu(ku,xh);return t.copy=function(){return Pu(t,qu())},Ru(t)}function Uu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=Sm.call(e,Am),t):n.slice()},t.copy=function(){return Uu().domain(n)},Ru(t)}function Du(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:Em(n)}function Ou(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function Fu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Iu(t){return 10===t?Fu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function Yu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function Bu(t){return function(n){return-t(-n)}}function ju(){function n(){return o=Yu(i),u=Iu(i),r()[0]<0&&(o=Bu(o),u=Bu(u)),e}var e=Lu(Du,Ou).domain([1,10]),r=e.domain,i=10,o=Yu(10),u=Iu(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=nf(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(Pm(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return Pu(e,ju().base(i))},e}function Hu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function Xu(){function t(t,n){return(n=Hu(n,e)-(t=Hu(t,e)))?function(r){return(Hu(r,e)-t)/n}:Em(n)}function n(t,n){return n=Hu(n,e)-(t=Hu(t,e)),function(r){return Hu(t+n*r,1/e)}}var e=1,r=Lu(t,n),i=r.domain;return r.exponent=function(t){return arguments.length?(e=+t,i(i())):e},r.copy=function(){return Pu(r,Xu().exponent(e))},Ru(r)}function Vu(){return Xu().exponent(.5)}function $u(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=of(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[Ds(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(Rs),t()},n.range=function(n){return arguments.length?(r=Nm.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return $u().domain(e).range(r)},n}function Wu(){function t(t){if(t<=t)return u[Ds(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=Nm.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return Wu().domain([e,r]).range(u)},Ru(t)}function Zu(){function t(t){if(t<=t)return e[Ds(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=Nm.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=Nm.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return Zu().domain(n).range(e)},t}function Gu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Gu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return Lm.setTime(+n),Rm.setTime(+r),t(Lm),t(Rm),Math.floor(e(Lm,Rm))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Ju(t){return Gu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Dm)/Om})}function Qu(t){return Gu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/Om})}function Ku(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function ta(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function na(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function ea(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Ux[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=na(1900)
-;if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?ta(na(i.y)).getUTCDay():n(na(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,ta(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=B[i in Ux?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function i(t,n,e){var r=C.exec(n.slice(e));return r?(t.p=z[r[0].toLowerCase()],e+r[0].length):-1}function o(t,n,e){var r=R.exec(n.slice(e));return r?(t.w=q[r[0].toLowerCase()],e+r[0].length):-1}function u(t,n,e){var r=P.exec(n.slice(e));return r?(t.w=L[r[0].toLowerCase()],e+r[0].length):-1}function a(t,n,e){var r=O.exec(n.slice(e));return r?(t.m=F[r[0].toLowerCase()],e+r[0].length):-1}function c(t,n,e){var r=U.exec(n.slice(e));return r?(t.m=D[r[0].toLowerCase()],e+r[0].length):-1}function s(t,n,e){return r(t,w,n,e)}function f(t,n,e){return r(t,M,n,e)}function l(t,n,e){return r(t,T,n,e)}function h(t){return k[t.getDay()]}function p(t){return N[t.getDay()]}function d(t){return A[t.getMonth()]}function v(t){return E[t.getMonth()]}function _(t){return S[+(t.getHours()>=12)]}function g(t){return k[t.getUTCDay()]}function y(t){return N[t.getUTCDay()]}function m(t){return A[t.getUTCMonth()]}function x(t){return E[t.getUTCMonth()]}function b(t){return S[+(t.getUTCHours()>=12)]}var w=t.dateTime,M=t.date,T=t.time,S=t.periods,N=t.days,k=t.shortDays,E=t.months,A=t.shortMonths,C=oa(S),z=ua(S),P=oa(N),L=ua(N),R=oa(k),q=ua(k),U=oa(E),D=ua(E),O=oa(A),F=ua(A),I={a:h,A:p,b:d,B:v,c:null,d:ba,e:ba,H:wa,I:Ma,j:Ta,L:Sa,m:Na,M:ka,p:_,S:Ea,U:Aa,w:Ca,W:za,x:null,X:null,y:Pa,Y:La,Z:Ra,"%":Za},Y={a:g,A:y,b:m,B:x,c:null,d:qa,e:qa,H:Ua,I:Da,j:Oa,L:Fa,m:Ia,M:Ya,p:b,S:Ba,U:ja,w:Ha,W:Xa,x:null,X:null,y:Va,Y:$a,Z:Wa,"%":Za},B={a:o,A:u,b:a,B:c,c:s,d:da,e:da,H:_a,I:_a,j:va,L:ma,m:pa,M:ga,p:i,S:ya,U:ca,w:aa,W:sa,x:f,X:l,y:la,Y:fa,Z:ha,"%":xa};return I.x=n(M,I),I.X=n(T,I),I.c=n(w,I),Y.x=n(M,Y),Y.X=n(T,Y),Y.c=n(w,Y),{format:function(t){var e=n(t+="",I);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Ku);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",Y);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,ta);return n.toString=function(){return t},n}}}function ra(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function ia(t){return t.replace(Fx,"\\$&")}function oa(t){return new RegExp("^(?:"+t.map(ia).join("|")+")","i")}function ua(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function aa(t,n,e){var r=Dx.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function ca(t,n,e){var r=Dx.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function sa(t,n,e){var r=Dx.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function fa(t,n,e){var r=Dx.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function la(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ha(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function pa(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function da(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function va(t,n,e){var r=Dx.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function _a(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function ga(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function ya(t,n,e){var r=Dx.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function ma(t,n,e){var r=Dx.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function xa(t,n,e){var r=Ox.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function ba(t,n){return ra(t.getDate(),n,2)}function wa(t,n){return ra(t.getHours(),n,2)}function Ma(t,n){return ra(t.getHours()%12||12,n,2)}function Ta(t,n){return ra(1+Xm.count(sx(t),t),n,3)}function Sa(t,n){return ra(t.getMilliseconds(),n,3)}function Na(t,n){return ra(t.getMonth()+1,n,2)}function ka(t,n){return ra(t.getMinutes(),n,2)}function Ea(t,n){return ra(t.getSeconds(),n,2)}function Aa(t,n){return ra($m.count(sx(t),t),n,2)}function Ca(t){return t.getDay()}function za(t,n){return ra(Wm.count(sx(t),t),n,2)}function Pa(t,n){return ra(t.getFullYear()%100,n,2)}function La(t,n){return ra(t.getFullYear()%1e4,n,4)}function Ra(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+ra(n/60|0,"0",2)+ra(n%60,"0",2)}function qa(t,n){return ra(t.getUTCDate(),n,2)}function Ua(t,n){return ra(t.getUTCHours(),n,2)}function Da(t,n){return ra(t.getUTCHours()%12||12,n,2)}function Oa(t,n){return ra(1+vx.count(Lx(t),t),n,3)}function Fa(t,n){return ra(t.getUTCMilliseconds(),n,3)}function Ia(t,n){return ra(t.getUTCMonth()+1,n,2)}function Ya(t,n){return ra(t.getUTCMinutes(),n,2)}function Ba(t,n){return ra(t.getUTCSeconds(),n,2)}function ja(t,n){return ra(gx.count(Lx(t),t),n,2)}function Ha(t){return t.getUTCDay()}function Xa(t,n){return ra(yx.count(Lx(t),t),n,2)}function Va(t,n){return ra(t.getUTCFullYear()%100,n,2)}function $a(t,n){return ra(t.getUTCFullYear()%1e4,n,4)}function Wa(){return"+0000"}function Za(){return"%"}function Ga(n){return Rx=ea(n),t.timeFormat=Rx.format,t.timeParse=Rx.parse,t.utcFormat=Rx.utcFormat,t.utcParse=Rx.utcParse,Rx}function Ja(t){return t.toISOString()}function Qa(t){var n=new Date(t);return isNaN(n)?null:n}function Ka(t){return new Date(t)}function tc(t){return t instanceof Date?+t:+new Date(+t)}function nc(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?g:r(i)<i?y:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=qs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Wx,r/Wx,n),n=t):a?(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a],o=a[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=Lu(ku,xh),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),g=s("%I:%M"),y=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Bx],[a,5,5*Bx],[a,15,15*Bx],[a,30,30*Bx],[u,1,jx],[u,5,5*jx],[u,15,15*jx],[u,30,30*jx],[o,1,Hx],[o,3,3*Hx],[o,6,6*Hx],[o,12,12*Hx],[r,1,Xx],[r,2,2*Xx],[e,1,Vx],[n,1,$x],[n,3,3*$x],[t,1,Wx]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(Sm.call(t,tc)):d().map(Ka)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(Pm(e,t)):h},h.copy=function(){return Pu(h,nc(t,n,e,r,o,u,a,c,s))},h}function ec(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function rc(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return rc(t).domain([e,r]).clamp(i)},Ru(n)}function ic(t){return t>1?0:t<-1?xb:Math.acos(t)}function oc(t){return t>=1?bb:t<=-1?-bb:Math.asin(t)}function uc(t){return t.innerRadius}function ac(t){return t.outerRadius}function cc(t){return t.startAngle}function sc(t){return t.endAngle}function fc(t){return t&&t.padAngle}function lc(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function hc(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/yb(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,g=(p+v)/2,y=d-h,m=v-p,x=y*y+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*yb(vb(0,b*b*x-w*w)),T=(w*m-y*M)/x,S=(-w*y-m*M)/x,N=(w*m+y*M)/x,k=(-w*y+m*M)/x,E=T-_,A=S-g,C=N-_,z=k-g;return E*E+A*A>C*C+z*z&&(T=N,S=k),{cx:T,cy:S,x01:-f,y01:-l,x11:T*(i/b-1),y11:S*(i/b-1)}}function pc(t){this._context=t}function dc(t){return t[0]}function vc(t){return t[1]}function _c(t){this._curve=t}function gc(t){function n(n){return new _c(t(n))}return n._curve=t,n}function yc(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(gc(t)):n()._curve},t}function mc(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function xc(t){this._context=t}function bc(t){this._context=t}function wc(t){this._context=t}function Mc(t,n){this._basis=new xc(t),this._beta=n}function Tc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Sc(t,n){this._context=t,this._k=(1-n)/6}function Nc(t,n){this._context=t,this._k=(1-n)/6}function kc(t,n){this._context=t,this._k=(1-n)/6}function Ec(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>mb){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>mb){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function Ac(t,n){this._context=t,this._alpha=n}function Cc(t,n){this._context=t,this._alpha=n}function zc(t,n){this._context=t,this._alpha=n}function Pc(t){this._context=t}function Lc(t){return t<0?-1:1}function Rc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(Lc(o)+Lc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function qc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function Uc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function Dc(t){this._context=t}function Oc(t){this._context=new Fc(t)}function Fc(t){this._context=t}function Ic(t){return new Dc(t)}function Yc(t){return new Oc(t)}function Bc(t){this._context=t}function jc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function Hc(t,n){this._context=t,this._t=n}function Xc(t){return new Hc(t,0)}function Vc(t){return new Hc(t,1)}function $c(t,n){return t[n]}function Wc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function Zc(t){return t[0]}function Gc(t){return t[1]}function Jc(){this._=null}function Qc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Kc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ts(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function ns(t){for(;t.L;)t=t.L;return t}function es(t,n,e,r){var i=[null,null],o=Ew.push(i)-1;return i.left=t,i.right=n,e&&is(i,t,n,e),r&&is(i,n,t,r),Nw[t.index].halfedges.push(o),Nw[n.index].halfedges.push(o),i}function rs(t,n,e){var r=[n,e];return r.left=t,r}function is(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function os(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=a[0],l=a[1],h=0,p=1,d=f-c,v=l-s;if(o=n-c,d||!(o>0)){if(o/=d,d<0){if(o<h)return;o<p&&(p=o)}else if(d>0){if(o>p)return;o>h&&(h=o)}if(o=r-c,d||!(o<0)){if(o/=d,d<0){if(o>p)return;o>h&&(h=o)}else if(d>0){if(o<h)return;o<p&&(p=o)}if(o=e-s,v||!(o>0)){if(o/=v,v<0){if(o<h)return;o<p&&(p=o)}else if(v>0){if(o>p)return;o>h&&(h=o)}if(o=i-s,v||!(o<0)){if(o/=v,v<0){if(o>p)return;o>h&&(h=o)}else if(v>0){if(o<h)return;o<p&&(p=o)}return!(h>0||p<1)||(h>0&&(t[0]=[c+h*d,s+h*v]),p<1&&(t[1]=[c+p*d,s+p*v]),!0)}}}}}function us(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function as(t,n,e,r){for(var i,o=Ew.length;o--;)us(i=Ew[o],t,n,e,r)&&os(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>zw||Math.abs(i[0][1]-i[1][1])>zw)||delete Ew[o]}function cs(t){return Nw[t.index]={site:t,halfedges:[]}}function ss(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function fs(t,n){return n[+(n.left!==t.site)]}function ls(t,n){return n[+(n.left===t.site)]}function hs(){for(var t,n,e,r,i=0,o=Nw.length;i<o;++i)if((t=Nw[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=ss(t,Ew[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function ps(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=Nw.length,g=!0;for(i=0;i<_;++i)if(o=Nw[i]){for(u=o.site,c=o.halfedges,a=c.length;a--;)Ew[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)p=ls(o,Ew[c[a]]),d=p[0],v=p[1],f=fs(o,Ew[c[++a%s]]),l=f[0],h=f[1],(Math.abs(d-l)>zw||Math.abs(v-h)>zw)&&(c.splice(a,0,Ew.push(rs(u,p,Math.abs(d-t)<zw&&r-v>zw?[t,Math.abs(l-t)<zw?h:r]:Math.abs(v-r)<zw&&e-d>zw?[Math.abs(h-r)<zw?l:e,r]:Math.abs(d-e)<zw&&v-n>zw?[e,Math.abs(l-e)<zw?h:n]:Math.abs(v-n)<zw&&d-t>zw?[Math.abs(h-n)<zw?l:t,n]:null))-1),++s);s&&(g=!1)}if(g){var y,m,x,b=1/0;for(i=0,g=null;i<_;++i)(o=Nw[i])&&(u=o.site,y=u[0]-t,m=u[1]-n,(x=y*y+m*m)<b&&(b=x,g=o));if(g){var w=[t,n],M=[t,r],T=[e,r],S=[e,n];g.halfedges.push(Ew.push(rs(u=g.site,w,M))-1,Ew.push(rs(u,M,T))-1,Ew.push(rs(u,T,S))-1,Ew.push(rs(u,S,w))-1)}}for(i=0;i<_;++i)(o=Nw[i])&&(o.halfedges.length||delete Nw[i])}function ds(){Qc(this),this.x=this.y=this.arc=this.site=this.cy=null}function vs(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-Pw)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,g=Aw.pop()||new ds;g.arc=t,g.site=i,g.x=v+u,g.y=(g.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=g;for(var y=null,m=kw._;m;)if(g.y<m.y||g.y===m.y&&g.x<=m.x){if(!m.L){y=m.P;break}m=m.L}else{if(!m.R){y=m;break}m=m.R}kw.insert(y,g),y||(Tw=g)}}}}function _s(t){var n=t.circle;n&&(n.P||(Tw=n.N),kw.remove(n),Aw.push(n),Qc(n),t.circle=null)}function gs(){Qc(this),this.edge=this.site=this.circle=null}function ys(t){var n=Cw.pop()||new gs;return n.site=t,n}function ms(t){_s(t),Sw.remove(t),Cw.push(t),Qc(t)}function xs(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];ms(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<zw&&Math.abs(r-c.circle.cy)<zw;)o=c.P,a.unshift(c),ms(c),c=o;a.unshift(c),_s(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<zw&&Math.abs(r-s.circle.cy)<zw;)u=s.N,a.push(s),ms(s),s=u;a.push(s),_s(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],is(s.edge,c.site,s.site,i);c=a[0],s=a[l-1],s.edge=es(c.site,s.site,null,i),vs(c),vs(s)}function bs(t){for(var n,e,r,i,o=t[0],u=t[1],a=Sw._;a;)if((r=ws(a,u)-o)>zw)a=a.L;else{if(!((i=o-Ms(a,u))>zw)){r>-zw?(n=a.P,e=a):i>-zw?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}cs(t);var c=ys(t);if(Sw.insert(n,c),n||e){if(n===e)return _s(n),e=ys(n.site),Sw.insert(c,e),c.edge=e.edge=es(n.site,c.site),vs(n),void vs(e);if(!e)return void(c.edge=es(n.site,c.site));_s(n),_s(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,g=2*(h*_-p*v),y=h*h+p*p,m=v*v+_*_,x=[(_*y-p*m)/g+f,(h*m-v*y)/g+l];is(e.edge,s,d,x),c.edge=es(s,t,null,x),e.edge=es(t,d,null,x),vs(n),vs(e)}}function ws(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;e=u.site;var a=e[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Ms(t,n){var e=t.N;if(e)return ws(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Ts(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Ss(t,n){return n[1]-t[1]||n[0]-t[0]}function Ns(t,n){var e,r,i,o=t.sort(Ss).pop();for(Ew=[],Nw=new Array(t.length),Sw=new Jc,kw=new Jc;;)if(i=Tw,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(bs(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;xs(i.arc)}if(hs(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];as(u,a,c,s),ps(u,a,c,s)}this.edges=Ew,this.cells=Nw,Sw=kw=Ew=Nw=null}function ks(t,n,e){this.target=t,this.type=n,this.transform=e}function Es(t,n,e){this.k=t,this.x=n,this.y=e}function As(t){return t.__zoom||qw}function Cs(){t.event.stopImmediatePropagation()}function zs(){return!t.event.button}function Ps(){var t,n,e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,t=e.width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function Ls(){return this.__zoom||qw}var Rs=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},qs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},Us=qs(Rs),Ds=Us.right,Os=Us.left,Fs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},Is=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},Ys=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Bs=function(t){return null===t?NaN:+t},js=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=Bs(t[u]))||(r=e-a,a+=r/++o,c+=r*(e-a));else for(;++u<i;)isNaN(e=Bs(n(t[u],u,t)))||(r=e-a,a+=r/++o,c+=r*(e-a));if(o>1)return c/(o-1)},Hs=function(t,n){var e=js(t,n);return e?Math.sqrt(e):e},Xs=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},Vs=Array.prototype,$s=Vs.slice,Ws=Vs.map,Zs=function(t){return function(){return t}},Gs=function(t){return t},Js=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Qs=Math.sqrt(50),Ks=Math.sqrt(10),tf=Math.sqrt(2),nf=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},ef=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},rf=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Js(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)d=v[o]=[],d.x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)u=c[o],f<=u&&u<=l&&v[Ds(h,u,0,p)].push(t[o]);return v}var n=Gs,e=Xs,r=ef;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:Zs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:Zs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:Zs(Array.isArray(n)?$s.call(n):n),t):r},t},of=function(t,n,e){if(null==e&&(e=Bs),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},uf=function(t,n,e){return t=Ws.call(t,Bs).sort(Rs),Math.ceil((e-n)/(2*(of(t,.75)-of(t,.25))*Math.pow(t.length,-1/3)))},af=function(t,n,e){return Math.ceil((e-n)/(3.5*Hs(t)*Math.pow(t.length,-1/3)))},cf=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},sf=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=Bs(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=Bs(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},ff=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=Bs(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=Bs(n(t[i],i,t)))||o.push(e);return of(o.sort(Rs),.5)},lf=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(r=t[i],n=r.length;--n>=0;)e[--u]=r[n];return e},hf=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},pf=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},df=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=Rs);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},vf=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},_f=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},gf=function(t){if(!(i=t.length))return[];for(var n=-1,e=hf(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},yf=function(){return gf(arguments)},mf=Array.prototype.slice,xf=function(t){return t},bf=1,wf=2,Mf=3,Tf=4,Sf=1e-6,Nf={value:function(){}};_.prototype=v.prototype={constructor:_,on:function(t,n){var e,r=this._,i=g(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=m(r[e],t.name,n);else if(null==n)for(e in r)r[e]=m(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=y(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new _(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(r=this._[t],o=0,e=r.length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var kf="http://www.w3.org/1999/xhtml",Ef={svg:"http://www.w3.org/2000/svg",xhtml:kf,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},Af=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ef.hasOwnProperty(n)?{space:Ef[n],local:t}:t},Cf=function(t){var n=Af(t);return(n.local?b:x)(n)},zf=0;M.prototype=w.prototype={constructor:M,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var Pf=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Lf=document.documentElement;if(!Lf.matches){var Rf=Lf.webkitMatchesSelector||Lf.msMatchesSelector||Lf.mozMatchesSelector||Lf.oMatchesSelector;Pf=function(t){return function(){return Rf.call(this,t)}}}}var qf=Pf,Uf={};if(t.event=null,"undefined"!=typeof document){"onmouseenter"in document.documentElement||(Uf={mouseenter:"mouseover",mouseleave:"mouseout"})}var Df=function(t,n,e){var r,i,o=N(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?E:k,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},Of=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Ff=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},If=function(t){var n=Of();return n.changedTouches&&(n=n.changedTouches[0]),Ff(t,n)},Yf=function(t){return null==t?C:function(){return this.querySelector(t)}},Bf=function(t){"function"!=typeof t&&(t=Yf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new vt(r,this._parents)},jf=function(t){return null==t?z:function(){return this.querySelectorAll(t)}},Hf=function(t){"function"!=typeof t&&(t=jf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new vt(r,i)},Xf=function(t){"function"!=typeof t&&(t=qf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new vt(r,this._parents)},Vf=function(t){return new Array(t.length)},$f=function(){return new vt(this._enter||this._groups.map(Vf),this._parents)};P.prototype={constructor:P,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var Wf=function(t){return function(){return t}},Zf="$",Gf=function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?R:L,r=this._parents,i=this._groups;"function"!=typeof t&&(t=Wf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var g,y,m=0,x=0;m<d;++m)if(g=v[m]){for(m>=x&&(x=m+1);!(y=_[x])&&++x<d;);g._next=y||null}}return u=new vt(u,r),u._enter=a,u._exit=c,u},Jf=function(){return new vt(this._exit||this._groups.map(Vf),this._parents)},Qf=function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new vt(u,this._parents)},Kf=function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},tl=function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=q);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var u,a=e[o],c=a.length,s=i[o]=new Array(c),f=0;f<c;++f)(u=a[f])&&(s[f]=u);s.sort(n)}return new vt(i,this._parents).order()},nl=function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},el=function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},rl=function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},il=function(){var t=0;return this.each(function(){++t}),t},ol=function(){return!this.node()},ul=function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},al=function(t,n){var e=Af(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?D:U:"function"==typeof n?e.local?Y:I:e.local?F:O)(e,n))},cl=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView},sl=function(t,n,e){var r;return arguments.length>1?this.each((null==n?B:"function"==typeof n?H:j)(t,n,null==e?"":e)):cl(r=this.node()).getComputedStyle(r,null).getPropertyValue(t)},fl=function(t,n){return arguments.length>1?this.each((null==n?X:"function"==typeof n?$:V)(t,n)):this.node()[t]};G.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var ll=function(t,n){var e=W(t+"");if(arguments.length<2){for(var r=Z(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?nt:n?K:tt)(e,n))},hl=function(t){return arguments.length?this.each(null==t?et:("function"==typeof t?it:rt)(t)):this.node().textContent},pl=function(t){return arguments.length?this.each(null==t?ot:("function"==typeof t?at:ut)(t)):this.node().innerHTML},dl=function(){return this.each(ct)},vl=function(){return this.each(st)},_l=function(t){var n="function"==typeof t?t:Cf(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},gl=function(t,n){var e="function"==typeof t?t:Cf(t),r=null==n?ft:"function"==typeof n?n:Yf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},yl=function(){return this.each(lt)},ml=function(t){return arguments.length?this.property("__data__",t):this.node().__data__},xl=function(t,n){return this.each(("function"==typeof n?dt:pt)(t,n))},bl=[null];vt.prototype=_t.prototype={constructor:vt,select:Bf,selectAll:Hf,filter:Xf,data:Gf,enter:$f,exit:Jf,merge:Qf,order:Kf,sort:tl,call:nl,nodes:el,node:rl,size:il,empty:ol,each:ul,attr:al,style:sl,property:fl,classed:ll,text:hl,html:pl,raise:dl,lower:vl,append:_l,insert:gl,remove:yl,datum:ml,on:Df,dispatch:xl};var wl=function(t){return"string"==typeof t?new vt([[document.querySelector(t)]],[document.documentElement]):new vt([[t]],bl)},Ml=function(t){return"string"==typeof t?new vt([document.querySelectorAll(t)],[document.documentElement]):new vt([null==t?[]:t],bl)},Tl=function(t,n,e){arguments.length<3&&(e=n,n=Of().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Ff(t,r);return null},Sl=function(t,n){null==n&&(n=Of().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Ff(t,n[e]);return i},Nl=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},kl=function(t){var n=t.document.documentElement,e=wl(t).on("dragstart.drag",Nl,!0);"onselectstart"in n?e.on("selectstart.drag",Nl,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},El=function(t){return function(){return t}};mt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var Al=function(){function n(t){t.on("mousedown.drag",e).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!f&&l.apply(this,arguments)){var n=c("mouse",h.apply(this,arguments),If,this,arguments);n&&(wl(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),kl(t.event.view),gt(),s=!1,n("start"))}}function r(){Nl(),s=!0,d.mouse("drag")}function i(){
-wl(t.event.view).on("mousemove.drag mouseup.drag",null),yt(t.event.view,s),Nl(),d.mouse("end")}function o(){if(l.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=h.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,Tl,this,arguments))&&(gt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=d[r[n].identifier])&&(Nl(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(f&&clearTimeout(f),f=setTimeout(function(){f=null},500),n=0;n<i;++n)(e=d[r[n].identifier])&&(gt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=_.copy();if(A(new mt(n,"beforestart",a,e,g,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=p.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,v=f;switch(h){case"start":d[e]=t,p=g++;break;case"end":delete d[e],--g;case"drag":f=i(r,e),p=g}A(new mt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-v[0],f[1]-v[1],l),l.apply,l,[h,o,u])}}var s,f,l=xt,h=bt,p=wt,d={},_=v("start","drag","end"),g=0;return n.filter=function(t){return arguments.length?(l="function"==typeof t?t:El(!!t),n):l},n.container=function(t){return arguments.length?(h="function"==typeof t?t:El(t),n):h},n.subject=function(t){return arguments.length?(p="function"==typeof t?t:El(t),n):p},n.on=function(){var t=_.on.apply(_,arguments);return t===_?n:t},n},Cl=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},zl="\\s*([+-]?\\d+)\\s*",Pl="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",Ll="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Rl=/^#([0-9a-f]{3})$/,ql=/^#([0-9a-f]{6})$/,Ul=new RegExp("^rgb\\("+[zl,zl,zl]+"\\)$"),Dl=new RegExp("^rgb\\("+[Ll,Ll,Ll]+"\\)$"),Ol=new RegExp("^rgba\\("+[zl,zl,zl,Pl]+"\\)$"),Fl=new RegExp("^rgba\\("+[Ll,Ll,Ll,Pl]+"\\)$"),Il=new RegExp("^hsl\\("+[Pl,Ll,Ll]+"\\)$"),Yl=new RegExp("^hsla\\("+[Pl,Ll,Ll,Pl]+"\\)$"),Bl={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Cl(Tt,St,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),Cl(Ct,At,Mt(Tt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Ct(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Ct(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return t=isNaN(t)?1:Math.max(0,Math.min(1,t)),(1===t?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Cl(Rt,Lt,Mt(Tt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Ct(qt(t>=240?t-240:t+120,i,r),qt(t,i,r),qt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var jl=Math.PI/180,Hl=180/Math.PI,Xl=.95047,Vl=1,$l=1.08883,Wl=4/29,Zl=6/29,Gl=3*Zl*Zl,Jl=Zl*Zl*Zl;Cl(Ot,Dt,Mt(Tt,{brighter:function(t){return new Ot(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Ot(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Vl*It(t),n=Xl*It(n),e=$l*It(e),new Ct(Yt(3.2404542*n-1.5371385*t-.4985314*e),Yt(-.969266*n+1.8760108*t+.041556*e),Yt(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),Cl(Xt,Ht,Mt(Tt,{brighter:function(t){return new Xt(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Xt(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Ut(this).rgb()}}));var Ql=-.14861,Kl=1.78277,th=-.29227,nh=-.90649,eh=1.97294,rh=eh*nh,ih=eh*Kl,oh=Kl*th-nh*Ql;Cl(Wt,$t,Mt(Tt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Wt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Wt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*jl,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Ct(255*(n+e*(Ql*r+Kl*i)),255*(n+e*(th*r+nh*i)),255*(n+e*(eh*r)),this.opacity)}}));var uh,ah,ch,sh,fh,lh,hh=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Zt((e-r/n)*n,u,i,o,a)}},ph=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Zt((e-r/n)*n,i,o,u,a)}},dh=function(t){return function(){return t}},vh=function t(n){function e(t,n){var e=r((t=At(t)).r,(n=At(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=tn(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Kt(n);return e.gamma=t,e}(1),_h=nn(hh),gh=nn(ph),yh=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=Sh(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},mh=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},xh=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},bh=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=Sh(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},wh=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Mh=new RegExp(wh.source,"g"),Th=function(t,n){var e,r,i,o=wh.lastIndex=Mh.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=wh.exec(t))&&(r=Mh.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:xh(e,r)})),o=Mh.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?rn(c[0].x):en(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},Sh=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?dh(n):("number"===r?xh:"string"===r?(e=St(n))?(n=e,vh):Th:n instanceof St?vh:n instanceof Date?mh:Array.isArray(n)?yh:isNaN(n)?bh:xh)(t,n)},Nh=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},kh=180/Math.PI,Eh={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},Ah=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*kh,skewX:Math.atan(c)*kh,scaleX:u,scaleY:a}},Ch=an(on,"px, ","px)","deg)"),zh=an(un,", ",")",")"),Ph=Math.SQRT2,Lh=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/Ph,e=function(t){return[i+t*f,o+t*l,u*Math.exp(Ph*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),g=Math.log(Math.sqrt(v*v+1)-v);r=(g-_)/Ph,e=function(t){var n=t*r,e=cn(_),a=u/(2*p)*(e*fn(Ph*n+_)-sn(_));return[i+a*f,o+a*l,u*e/cn(Ph*n+_)]}}return e.duration=1e3*r,e},Rh=ln(Qt),qh=ln(tn),Uh=pn(Qt),Dh=pn(tn),Oh=dn(Qt),Fh=dn(tn),Ih=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},Yh=0,Bh=0,jh=0,Hh=1e3,Xh=0,Vh=0,$h=0,Wh="object"==typeof performance&&performance.now?performance:Date,Zh="function"==typeof requestAnimationFrame?requestAnimationFrame:function(t){setTimeout(t,17)};gn.prototype=yn.prototype={constructor:gn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?vn():+e)+(null==n?0:+n),this._next||lh===this||(lh?lh._next=this:fh=this,lh=this),this._call=t,this._time=e,Mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Mn())}};var Gh=function(t,n,e){var r=new gn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Jh=function(t,n,e){var r=new gn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?vn():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},Qh=v("start","end","interrupt"),Kh=[],tp=0,np=1,ep=2,rp=3,ip=4,op=5,up=6,ap=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};kn(t,e,{name:n,index:r,group:i,on:Qh,tween:Kh,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:tp})},cp=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>ep&&e.state<op,e.state=up,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},sp=function(t){return this.each(function(){cp(this,t)})},fp=function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Nn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?En:An)(e,t,n))},lp=function(t,n){var e;return("number"==typeof n?xh:n instanceof St?vh:(e=St(n))?(n=e,vh):Th)(t,n)},hp=function(t,n){var e=Af(t),r="transform"===e?zh:lp;return this.attrTween(t,"function"==typeof n?(e.local?Un:qn)(e,r,Cn(this,"attr."+t,n)):null==n?(e.local?Pn:zn)(e):(e.local?Rn:Ln)(e,r,n+""))},pp=function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=Af(t);return this.tween(e,(r.local?Dn:On)(r,n))},dp=function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Fn:In)(n,t)):Nn(this.node(),n).delay},vp=function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Yn:Bn)(n,t)):Nn(this.node(),n).duration},_p=function(t){var n=this._id;return arguments.length?this.each(jn(n,t)):Nn(this.node(),n).ease},gp=function(t){"function"!=typeof t&&(t=qf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new te(r,this._parents,this._name,this._id)},yp=function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new te(u,this._parents,this._name,this._id)},mp=function(t,n){var e=this._id;return arguments.length<2?Nn(this.node(),e).on.on(t):this.each(Xn(e,t,n))},xp=function(){return this.on("end.remove",Vn(this._id))},bp=function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Yf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,ap(l[h],n,e,h,l,Nn(a,e)));return new te(o,this._parents,n,e)},wp=function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=jf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=Nn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&ap(h,n,e,v,p,d);o.push(p),u.push(c)}return new te(o,u,n,e)},Mp=_t.prototype.constructor,Tp=function(){return new Mp(this._groups,this._parents)},Sp=function(t,n,e){var r="transform"==(t+="")?Ch:lp;return null==n?this.styleTween(t,$n(t,r)).on("end.style."+t,Wn(t)):this.styleTween(t,"function"==typeof n?Gn(t,r,Cn(this,"style."+t,n)):Zn(t,r,n+""),e)},Np=function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Jn(t,n,null==e?"":e))},kp=function(t){return this.tween("text","function"==typeof t?Kn(Cn(this,"text",t)):Qn(null==t?"":t+""))},Ep=function(){for(var t=this._name,n=this._id,e=ee(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=Nn(u,n);ap(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new te(r,this._parents,t,e)},Ap=0,Cp=_t.prototype;te.prototype=ne.prototype={constructor:te,select:bp,selectAll:wp,filter:gp,merge:yp,selection:Tp,transition:Ep,call:Cp.call,nodes:Cp.nodes,node:Cp.node,size:Cp.size,empty:Cp.empty,each:Cp.each,on:mp,attr:hp,attrTween:pp,style:Sp,styleTween:Np,text:kp,remove:xp,tween:fp,delay:dp,duration:vp,ease:_p};var zp=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Pp=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Lp=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Rp=Math.PI,qp=Rp/2,Up=4/11,Dp=6/11,Op=8/11,Fp=.75,Ip=9/11,Yp=10/11,Bp=.9375,jp=21/22,Hp=63/64,Xp=1/Up/Up,Vp=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),$p=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),Wp=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),Zp=2*Math.PI,Gp=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Zp);return r.amplitude=function(n){return t(n,e*Zp)},r.period=function(e){return t(n,e)},r}(1,.3),Jp=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Zp);return r.amplitude=function(n){return t(n,e*Zp)},r.period=function(e){return t(n,e)},r}(1,.3),Qp=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Zp);return r.amplitude=function(n){return t(n,e*Zp)},r.period=function(e){return t(n,e)},r}(1,.3),Kp={time:null,delay:0,duration:250,ease:se},td=function(t){var n,e;t instanceof te?(n=t._id,t=t._name):(n=ee(),(e=Kp).time=vn(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&ap(u,t,n,s,a,e||we(u,n));return new te(r,this._parents,t,n)};_t.prototype.interrupt=sp,_t.prototype.transition=td;var nd=[null],ed=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>np&&e.name===n)return new te([[t]],nd,n,+r)}return null},rd=function(t){return function(){return t}},id=function(t,n,e){this.target=t,this.type=n,this.selection=e},od=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},ud={name:"drag"},ad={name:"space"},cd={name:"handle"},sd={name:"center"},fd={name:"x",handles:["e","w"].map(Te),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},ld={name:"y",handles:["n","s"].map(Te),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},hd={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(Te),input:function(t){return t},output:function(t){return t}},pd={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},dd={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},vd={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},_d={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},gd={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},yd=function(){return Pe(hd)},md=Math.cos,xd=Math.sin,bd=Math.PI,wd=bd/2,Md=2*bd,Td=Math.max,Sd=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Js(l),d=[],v=[],_=v.groups=new Array(l),g=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Js(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),o=Td(0,Md-n*l)/o,c=o?n:Md/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var y=p[s],m=d[y][f],x=t[y][m],b=u,w=u+=x*o;g[m*l+y]={index:y,subindex:m,startAngle:b,endAngle:w,value:x}}_[y]={index:y,startAngle:a,endAngle:u,value:h[y]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=g[f*l+s],T=g[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Td(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=Le(n))._=n,t):i&&i._},t},Nd=Array.prototype.slice,kd=function(t){return function(){return t}},Ed=Math.PI,Ad=2*Ed,Cd=Ad-1e-6;Re.prototype=qe.prototype={constructor:Re,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),g=Math.sqrt(l),y=i*Math.tan((Ed-Math.acos((d+l-v)/(2*_*g)))/2),m=y/g,x=y/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,e=+e;var u=e*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Ad+Ad),l>Cd?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Ed)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var zd=function(){function t(){var t,a=Nd.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-wd,h=o.apply(this,a)-wd,p=f*md(l),d=f*xd(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-wd,g=o.apply(this,a)-wd;if(u||(u=t=qe()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===g||(u.quadraticCurveTo(0,0,v*md(_),v*xd(_)),u.arc(0,0,v,_,g)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=Ue,e=De,r=Oe,i=Fe,o=Ie,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:kd(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:kd(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:kd(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t};Ye.prototype=Be.prototype={constructor:Ye,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Pd=function(){function t(n,i,u,a){if(i>=o.length)return null!=r?r(n):null!=e?n.sort(e):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=Be(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,je,He)},map:function(n){return t(n,0,Xe,Ve)},entries:function(e){return n(t(e,0,Xe,Ve),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},Ld=Be.prototype;$e.prototype=We.prototype={constructor:$e,has:Ld.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Ld.remove,clear:Ld.clear,values:Ld.keys,size:Ld.size,empty:Ld.empty,each:Ld.each};var Rd=function(t){var n=[];for(var e in t)n.push(e);return n},qd=function(t){var n=[];for(var e in t)n.push(t[e]);return n},Ud=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},Dd=function(t){function n(t,n){var r,i,o=e(t,function(t,e){if(r)return r(t,e-1);i=t,r=n?Ge(t,n):Ze(t)});return o.columns=i,o}function e(t,n){function e(){if(f>=s)return u;if(i)return i=!1,o;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,n=t.charCodeAt(r+1),13===n?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var a=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++a);else if(n!==c)continue;return t.slice(e,f-a)}return t.slice(e)}for(var r,i,o={},u={},a=[],s=t.length,f=0,l=0;(r=e())!==u;){for(var h=[];r!==o&&r!==u;)h.push(r),r=e();n&&null==(h=n(h,l++))||a.push(h)}return a}function r(n,e){return null==e&&(e=Je(n)),[e.map(u).join(t)].concat(n.map(function(n){return e.map(function(t){return u(n[t])}).join(t)})).join("\n")}function i(t){return t.map(o).join("\n")}function o(n){return n.map(u).join(t)}function u(t){return null==t?"":a.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var a=new RegExp('["'+t+"\n\r]"),c=t.charCodeAt(0);return{parse:n,parseRows:e,format:r,formatRows:i}},Od=Dd(","),Fd=Od.parse,Id=Od.parseRows,Yd=Od.format,Bd=Od.formatRows,jd=Dd("\t"),Hd=jd.parse,Xd=jd.parseRows,Vd=jd.format,$d=jd.formatRows,Wd=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)i=r[e],u+=i.x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)i=r[e],i.x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},Zd=function(t){return function(){return t}},Gd=function(){return 1e-6*(Math.random()-.5)},Jd=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Qe(this.cover(n,e),n,e,t)},Qd=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},Kd=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},tv=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},nv=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},ev=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new nv(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,g=(o+a)/2;d.push(new nv(v[3],_,g,u,a),new nv(v[2],i,g,_,a),new nv(v[1],_,o,u,g),new nv(v[0],i,o,_,g)),(s=(n>=g)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var y=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=y*y+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},rv=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,g=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+g)/2))?v=c:g=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},iv=function(){return this._root},ov=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},uv=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new nv(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new nv(e,s,f,o,u)),(e=c[2])&&a.push(new nv(e,r,f,s,u)),(e=c[1])&&a.push(new nv(e,s,i,o,f)),(e=c[0])&&a.push(new nv(e,r,i,s,f))}return this},av=function(t){var n,e=[],r=[];for(this._root&&e.push(new nv(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new nv(o,u,a,f,l)),(o=i[1])&&e.push(new nv(o,f,a,c,l)),(o=i[2])&&e.push(new nv(o,u,l,f,s)),(o=i[3])&&e.push(new nv(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},cv=function(t){return arguments.length?(this._x=t,this):this._x},sv=function(t){return arguments.length?(this._y=t,this):this._y},fv=rr.prototype=ir.prototype;fv.copy=function(){var t,n,e=new ir(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=or(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=or(n));return e},fv.add=Jd,fv.addAll=Ke,fv.cover=Qd,fv.data=Kd,fv.extent=tv,fv.find=ev,fv.remove=rv,fv.removeAll=tr,fv.root=iv,fv.size=ov,fv.visit=uv,fv.visitAfter=av,fv.x=cv,fv.y=sv;var lv,hv=function(t){function n(){function t(t,n,e,r,i){var o=t.data,a=t.r,p=l+a;{if(!o)return n>s+p||r<s-p||e>f+p||i<f-p;if(o.index>c.index){var d=s-o.x-o.vx,v=f-o.y-o.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=Gd(),_+=d*d),0===v&&(v=Gd(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,c.vx+=(d*=_)*(p=(a*=a)/(h+a)),c.vy+=(v*=_)*p,o.vx-=d*(p=1-p),o.vy-=v*p)}}}for(var n,r,c,s,f,l,h,p=i.length,d=0;d<a;++d)for(r=rr(i,ur,ar).visitAfter(e),n=0;n<p;++n)c=i[n],l=o[c.index],h=l*l,s=c.x+c.vx,f=c.y+c.vy,r.visit(t)}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=Zd(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:Zd(+e),r(),n):t},n},pv=function(t){function n(t){return 1/Math.min(s[t.source.index],s[t.target.index])}function e(n){for(var e=0,r=t.length;e<d;++e)for(var i,o,c,s,l,h,p,v=0;v<r;++v)i=t[v],o=i.source,c=i.target,s=c.x+c.vx-o.x-o.vx||Gd(),l=c.y+c.vy-o.y-o.vy||Gd(),h=Math.sqrt(s*s+l*l),h=(h-a[v])/h*n*u[v],s*=h,l*=h,c.vx-=s*(p=f[v]),c.vy-=l*p,o.vx+=s*(p=1-p),o.vy+=l*p}function r(){if(c){var n,e,r=c.length,h=t.length,p=Be(c,l);for(n=0,s=new Array(r);n<h;++n)e=t[n],e.index=n,"object"!=typeof e.source&&(e.source=sr(p,e.source)),"object"!=typeof e.target&&(e.target=sr(p,e.target)),s[e.source.index]=(s[e.source.index]||0)+1,s[e.target.index]=(s[e.target.index]||0)+1;for(n=0,f=new Array(h);n<h;++n)e=t[n],f[n]=s[e.source.index]/(s[e.source.index]+s[e.target.index]);u=new Array(h),i(),a=new Array(h),o()}}function i(){if(c)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}function o(){if(c)for(var n=0,e=t.length;n<e;++n)a[n]=+p(t[n],n,t)}var u,a,c,s,f,l=cr,h=n,p=Zd(30),d=1;return null==t&&(t=[]),e.initialize=function(t){c=t,r()},e.links=function(n){return arguments.length?(t=n,r(),e):t},e.id=function(t){return arguments.length?(l=t,
-e):l},e.iterations=function(t){return arguments.length?(d=+t,e):d},e.strength=function(t){return arguments.length?(h="function"==typeof t?t:Zd(+t),i(),e):h},e.distance=function(t){return arguments.length?(p="function"==typeof t?t:Zd(+t),o(),e):p},e},dv=10,vv=Math.PI*(3-Math.sqrt(5)),_v=function(t){function n(){e(),p.call("tick",o),u<a&&(h.stop(),p.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)e=t[n],null==e.fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=dv*Math.sqrt(e),o=e*vv;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=Be(),h=yn(n),p=v("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return h.restart(n),o},stop:function(){return h.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)a=t[s],i=n-a.x,o=e-a.y,(u=i*i+o*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(p.on(t,n),o):p.on(t)}}},gv=function(){function t(t){var n,a=i.length,c=rr(i,fr,lr).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{n=t,n.x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=Gd(),p+=i*i),0===c&&(c=Gd(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=Gd(),p+=i*i),0===c&&(c=Gd(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=Zd(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:Zd(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},yv=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Zd(.1);return"function"!=typeof t&&(t=Zd(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:Zd(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:Zd(+r),e(),n):t},n},mv=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Zd(.1);return"function"!=typeof t&&(t=Zd(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:Zd(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:Zd(+r),e(),n):t},n},xv=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},bv=function(t){return t=xv(Math.abs(t)),t?t[1]:NaN},wv=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},Mv=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},Tv=function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},Sv=function(t,n){var e=xv(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(lv=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+xv(t,Math.max(0,n+o-1))[0]},Nv=function(t,n){var e=xv(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},kv={"":Tv,"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Nv(100*t,n)},r:Nv,s:Sv,X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Ev=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;hr.prototype=pr.prototype,pr.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var Av,Cv=function(t){return t},zv=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],Pv=function(t){function n(t){function n(t){var n,i,a,f=_,x=g;if("c"===v)x=y(t)+x,t="";else{t=+t;var b=t<0;if(t=y(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?zv[8+lv/3]:"")+(b&&"("===s?")":""),m)for(n=-1,i=t.length;++n<i;)if(48>(a=t.charCodeAt(n))||a>57){x=(46===a?o+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=r(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(e):"";switch(p&&l&&(t=r(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return u(t)}t=hr(t);var e=t.fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?i[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",g="$"===f?i[1]:/[%p]/.test(v)?a:"",y=kv[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}function e(t,e){var r=n((t=hr(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(bv(e)/3))),o=Math.pow(10,-i),u=zv[8+i/3];return function(t){return r(o*t)+u}}var r=t.grouping&&t.thousands?wv(t.grouping,t.thousands):Cv,i=t.currency,o=t.decimal,u=t.numerals?Mv(t.numerals):Cv,a=t.percent||"%";return{format:n,formatPrefix:e}};dr({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var Lv=function(t){return Math.max(0,-bv(Math.abs(t)))},Rv=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(bv(n)/3)))-bv(Math.abs(t)))},qv=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,bv(n)-bv(t))+1},Uv=function(){return new vr};vr.prototype={constructor:vr,reset:function(){this.s=this.t=0},add:function(t){_r(d_,t,this.t),_r(this,d_.s,this.s),this.s?this.t+=d_.t:this.s=d_.t},valueOf:function(){return this.s}};var Dv,Ov,Fv,Iv,Yv,Bv,jv,Hv,Xv,Vv,$v,Wv,Zv,Gv,Jv,Qv,Kv,t_,n_,e_,r_,i_,o_,u_,a_,c_,s_,f_,l_,h_,p_,d_=new vr,v_=1e-6,__=Math.PI,g_=__/2,y_=__/4,m_=2*__,x_=180/__,b_=__/180,w_=Math.abs,M_=Math.atan,T_=Math.atan2,S_=Math.cos,N_=Math.ceil,k_=Math.exp,E_=Math.log,A_=Math.pow,C_=Math.sin,z_=Math.sign||function(t){return t>0?1:t<0?-1:0},P_=Math.sqrt,L_=Math.tan,R_={Feature:function(t,n){br(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)br(e[r].geometry,n)}},q_={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){wr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)wr(e[r],n,0)},Polygon:function(t,n){Mr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Mr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)br(e[r],n)}},U_=function(t,n){t&&R_.hasOwnProperty(t.type)?R_[t.type](t,n):br(t,n)},D_=Uv(),O_=Uv(),F_={point:xr,lineStart:xr,lineEnd:xr,polygonStart:function(){D_.reset(),F_.lineStart=Tr,F_.lineEnd=Sr},polygonEnd:function(){var t=+D_;O_.add(t<0?m_+t:t),this.lineStart=this.lineEnd=this.point=xr},sphere:function(){O_.add(m_)}},I_=function(t){return O_.reset(),U_(t,F_),2*O_},Y_=Uv(),B_={point:qr,lineStart:Dr,lineEnd:Or,polygonStart:function(){B_.point=Fr,B_.lineStart=Ir,B_.lineEnd=Yr,Y_.reset(),F_.polygonStart()},polygonEnd:function(){F_.polygonEnd(),B_.point=qr,B_.lineStart=Dr,B_.lineEnd=Or,D_<0?(Bv=-(Hv=180),jv=-(Xv=90)):Y_>v_?Xv=90:Y_<-v_&&(jv=-90),Jv[0]=Bv,Jv[1]=Hv}},j_=function(t){var n,e,r,i,o,u,a;if(Xv=Hv=-(Bv=jv=1/0),Gv=[],U_(t,B_),e=Gv.length){for(Gv.sort(jr),n=1,r=Gv[0],o=[r];n<e;++n)i=Gv[n],Hr(r,i[0])||Hr(r,i[1])?(Br(r[0],i[1])>Br(r[0],r[1])&&(r[1]=i[1]),Br(i[0],r[1])>Br(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,e=o.length-1,n=0,r=o[e];n<=e;r=i,++n)i=o[n],(a=Br(r[1],i[0]))>u&&(u=a,Bv=i[0],Hv=r[1])}return Gv=Jv=null,Bv===1/0||jv===1/0?[[NaN,NaN],[NaN,NaN]]:[[Bv,jv],[Hv,Xv]]},H_={sphere:xr,point:Xr,lineStart:$r,lineEnd:Gr,polygonStart:function(){H_.lineStart=Jr,H_.lineEnd=Qr},polygonEnd:function(){H_.lineStart=$r,H_.lineEnd=Gr}},X_=function(t){Qv=Kv=t_=n_=e_=r_=i_=o_=u_=a_=c_=0,U_(t,H_);var n=u_,e=a_,r=c_,i=n*n+e*e+r*r;return i<1e-12&&(n=r_,e=i_,r=o_,Kv<v_&&(n=t_,e=n_,r=e_),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[T_(e,n)*x_,yr(r/P_(i))*x_]},V_=function(t){return function(){return t}},$_=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};ni.invert=ni;var W_,Z_,G_,J_,Q_,K_,tg,ng,eg,rg,ig,og=function(t){function n(n){return n=t(n[0]*b_,n[1]*b_),n[0]*=x_,n[1]*=x_,n}return t=ei(t[0]*b_,t[1]*b_,t.length>2?t[2]*b_:0),n.invert=function(n){return n=t.invert(n[0]*b_,n[1]*b_),n[0]*=x_,n[1]*=x_,n},n},ug=function(){function t(t,n){e.push(t=r(t,n)),t[0]*=x_,t[1]*=x_}function n(){var t=i.apply(this,arguments),n=o.apply(this,arguments)*b_,c=u.apply(this,arguments)*b_;return e=[],r=ei(-t[0]*b_,-t[1]*b_,0).invert,ui(a,n,c,1),t={type:"Polygon",coordinates:[e]},e=r=null,t}var e,r,i=V_([0,0]),o=V_(90),u=V_(6),a={point:t};return n.center=function(t){return arguments.length?(i="function"==typeof t?t:V_([+t[0],+t[1]]),n):i},n.radius=function(t){return arguments.length?(o="function"==typeof t?t:V_(+t),n):o},n.precision=function(t){return arguments.length?(u="function"==typeof t?t:V_(+t),n):u},n},ag=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:xr,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},cg=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=n[0],f=n[1],l=0,h=1,p=s-a,d=f-c;if(u=e-a,p||!(u>0)){if(u/=p,p<0){if(u<l)return;u<h&&(h=u)}else if(p>0){if(u>h)return;u>l&&(l=u)}if(u=i-a,p||!(u<0)){if(u/=p,p<0){if(u>h)return;u>l&&(l=u)}else if(p>0){if(u<l)return;u<h&&(h=u)}if(u=r-c,d||!(u>0)){if(u/=d,d<0){if(u<l)return;u<h&&(h=u)}else if(d>0){if(u>h)return;u>l&&(l=u)}if(u=o-c,d||!(u<0)){if(u/=d,d<0){if(u>h)return;u>l&&(l=u)}else if(d>0){if(u<l)return;u<h&&(h=u)}return l>0&&(t[0]=a+l*p,t[1]=c+l*d),h<1&&(n[0]=a+h*p,n[1]=c+h*d),!0}}}}},sg=function(t,n){return w_(t[0]-n[0])<v_&&w_(t[1]-n[1])<v_},fg=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if(sg(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a.push(e=new ci(r,t,null,!0)),c.push(e.o=new ci(r,null,e,!1)),a.push(e=new ci(u,t,null,!1)),c.push(e.o=new ci(u,null,e,!0))}}),a.length){for(c.sort(n),si(a),si(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}h=h.o,s=h.z,p=!p}while(!h.v);i.lineEnd()}}},lg=1e9,hg=-lg,pg=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=fi(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},dg=Uv(),vg=function(t,n){var e=n[0],r=n[1],i=[C_(e),-S_(e),0],o=0,u=0;dg.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+y_,d=C_(p),v=S_(p),_=0;_<f;++_,h=y,d=x,v=b,l=g){var g=s[_],y=g[0],m=g[1]/2+y_,x=C_(m),b=S_(m),w=y-h,M=w>=0?1:-1,T=M*w,S=T>__,N=d*x;if(dg.add(T_(N*M*C_(T),v*b+N*S_(T))),o+=S?w+M*m_:w,S^h>=e^y>=e){var k=zr(Ar(l),Ar(g));Rr(k);var E=zr(i,k);Rr(E);var A=(S^w>=0?-1:1)*yr(E[2]);(r>A||r===A&&(k[0]||k[1]))&&(u+=S^w>=0?1:-1)}}return(o<-v_||o<v_&&dg<-v_)^1&u},_g=Uv(),gg={sphere:xr,point:xr,lineStart:li,lineEnd:xr,polygonStart:xr,polygonEnd:xr},yg=function(t){return _g.reset(),U_(t,gg),+_g},mg=[null,null],xg={type:"LineString",coordinates:mg},bg=function(t,n){return mg[0]=t,mg[1]=n,yg(xg)},wg={Feature:function(t,n){return vi(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(vi(e[r].geometry,n))return!0;return!1}},Mg={Sphere:function(){return!0},Point:function(t,n){return _i(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(_i(e[r],n))return!0;return!1},LineString:function(t,n){return gi(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(gi(e[r],n))return!0;return!1},Polygon:function(t,n){return yi(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(yi(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(vi(e[r],n))return!0;return!1}},Tg=function(t,n){return(t&&wg.hasOwnProperty(t.type)?wg[t.type]:vi)(t,n)},Sg=function(t,n){var e=t[0]*b_,r=t[1]*b_,i=n[0]*b_,o=n[1]*b_,u=S_(r),a=C_(r),c=S_(o),s=C_(o),f=u*S_(e),l=u*C_(e),h=c*S_(i),p=c*C_(i),d=2*yr(P_(mr(o-r)+u*c*mr(i-e))),v=C_(d),_=d?function(t){var n=C_(t*=d)/v,e=C_(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[T_(i,r)*x_,T_(o,P_(r*r+i*i))*x_]}:function(){return[e*x_,r*x_]};return _.distance=d,_},Ng=function(t){return t},kg=Uv(),Eg=Uv(),Ag={point:xr,lineStart:xr,lineEnd:xr,polygonStart:function(){Ag.lineStart=Si,Ag.lineEnd=Ei},polygonEnd:function(){Ag.lineStart=Ag.lineEnd=Ag.point=xr,kg.add(w_(Eg)),Eg.reset()},result:function(){var t=kg/2;return kg.reset(),t}},Cg=1/0,zg=Cg,Pg=-Cg,Lg=Pg,Rg={point:Ai,lineStart:xr,lineEnd:xr,polygonStart:xr,polygonEnd:xr,result:function(){var t=[[Cg,zg],[Pg,Lg]];return Pg=Lg=-(zg=Cg=1/0),t}},qg=0,Ug=0,Dg=0,Og=0,Fg=0,Ig=0,Yg=0,Bg=0,jg=0,Hg={point:Ci,lineStart:zi,lineEnd:Ri,polygonStart:function(){Hg.lineStart=qi,Hg.lineEnd=Ui},polygonEnd:function(){Hg.point=Ci,Hg.lineStart=zi,Hg.lineEnd=Ri},result:function(){var t=jg?[Yg/jg,Bg/jg]:Ig?[Og/Ig,Fg/Ig]:Dg?[qg/Dg,Ug/Dg]:[NaN,NaN];return qg=Ug=Dg=Og=Fg=Ig=Yg=Bg=jg=0,t}};Fi.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,m_)}},result:xr};var Xg,Vg,$g,Wg,Zg,Gg=Uv(),Jg={point:xr,lineStart:function(){Jg.point=Ii},lineEnd:function(){Xg&&Yi(Vg,$g),Jg.point=xr},polygonStart:function(){Xg=!0},polygonEnd:function(){Xg=null},result:function(){var t=+Gg;return Gg.reset(),t}};Bi.prototype={_circle:ji(4.5),pointRadius:function(t){return this._circle=ji(t),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}}};var Qg=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),U_(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return U_(t,r(Ag)),Ag.result()},e.measure=function(t){return U_(t,r(Jg)),Jg.result()},e.bounds=function(t){return U_(t,r(Rg)),Rg.result()},e.centroid=function(t){return U_(t,r(Hg)),Hg.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,Ng):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new Bi):new Fi(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},Kg=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=y.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(Hi))}var p,d,v,_=n(o),g=i.invert(r[0],r[1]),y=ag(),m=n(y),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=lf(d);var t=vg(p,g);d.length?(x||(o.polygonStart(),x=!0),fg(d,Xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},ty=Kg(function(){return!0},Vi,Wi,[-__,-g_]),ny=function(t,n){function e(e,r,i,o){ui(o,t,n,i,e,r)}function r(t,n){return S_(t)*S_(n)>a}function i(t){var n,e,i,a,f;return{lineStart:function(){a=i=!1,f=1},point:function(l,h){var p,d=[l,h],v=r(l,h),_=c?v?0:u(l,h):v?u(l+(l<0?__:-__),h):0;if(!n&&(a=i=v)&&t.lineStart(),v!==i&&(p=o(n,d),(sg(n,p)||sg(d,p))&&(d[0]+=v_,d[1]+=v_,v=r(d[0],d[1]))),v!==i)f=0,v?(t.lineStart(),p=o(d,n),t.point(p[0],p[1])):(p=o(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(s&&n&&c^v){var g;_&e||!(g=o(d,n,!0))||(f=0,c?(t.lineStart(),t.point(g[0][0],g[0][1]),t.point(g[1][0],g[1][1]),t.lineEnd()):(t.point(g[1][0],g[1][1]),t.lineEnd(),t.lineStart(),t.point(g[0][0],g[0][1])))}!v||n&&sg(n,d)||t.point(d[0],d[1]),n=d,i=v,e=_},lineEnd:function(){i&&t.lineEnd(),n=null},clean:function(){return f|(a&&i)<<1}}}function o(t,n,e){var r=Ar(t),i=Ar(n),o=[1,0,0],u=zr(r,i),c=Cr(u,u),s=u[0],f=c-s*s;if(!f)return!e&&t;var l=a*c/f,h=-a*s/f,p=zr(o,u),d=Lr(o,l);Pr(d,Lr(u,h));var v=p,_=Cr(d,v),g=Cr(v,v),y=_*_-g*(Cr(d,d)-1);if(!(y<0)){var m=P_(y),x=Lr(v,(-_-m)/g);if(Pr(x,d),x=Er(x),!e)return x;var b,w=t[0],M=n[0],T=t[1],S=n[1];M<w&&(b=w,w=M,M=b);var N=M-w,k=w_(N-__)<v_,E=k||N<v_;if(!k&&S<T&&(b=T,T=S,S=b),E?k?T+S>0^x[1]<(w_(x[0]-w)<v_?T:S):T<=x[1]&&x[1]<=S:N>__^(w<=x[0]&&x[0]<=M)){var A=Lr(v,(-_+m)/g);return Pr(A,d),[x,Er(A)]}}}function u(n,e){var r=c?t:__-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var a=S_(t),c=a>0,s=w_(a)>v_;return Kg(r,i,e,c?[0,-t]:[-__,t-__])},ey=function(t){return{stream:Zi(t)}};Gi.prototype={constructor:Gi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var ry=16,iy=S_(30*b_),oy=function(t,n){return+n?to(t,n):Ki(t)},uy=Zi({point:function(t,n){this.stream.point(t*b_,n*b_)}}),ay=function(){return ro(oo).scale(155.424).center([0,33.6442])},cy=function(){return ay().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},sy=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=cy(),s=ay().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=ay().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=uo([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+v_,a+.12*e+v_],[r-.214*e-v_,a+.234*e-v_]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+v_,a+.166*e+v_],[r-.115*e-v_,a+.234*e-v_]]).stream(l),n()},t.fitExtent=function(n,e){return Ji(t,n,e)},t.fitSize=function(n,e){return Qi(t,n,e)},t.scale(1070)},fy=ao(function(t){return P_(2/(1+t))});fy.invert=co(function(t){return 2*yr(t/2)});var ly=function(){return no(fy).scale(124.75).clipAngle(179.999)},hy=ao(function(t){return(t=gr(t))&&t/C_(t)});hy.invert=co(function(t){return t});var py=function(){return no(hy).scale(79.4188).clipAngle(179.999)};so.invert=function(t,n){return[t,2*M_(k_(n))-g_]};var dy=function(){return fo(so).scale(961/m_)},vy=function(){return ro(ho).scale(109.5).parallels([30,30])};po.invert=po;var _y=function(){return no(po).scale(152.63)},gy=function(){return ro(vo).scale(131.154).center([0,13.9389])};_o.invert=co(M_);var yy=function(){return no(_o).scale(144.049).clipAngle(60)},my=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=Ng,p=null,d=Ng;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,Ng):fi(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=go((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=go(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=go(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=go(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ji(u,t,n)},fitSize:function(t,n){return Qi(u,t,n)}}};yo.invert=co(yr);var xy=function(){return no(yo).scale(249.5).clipAngle(90+v_)};mo.invert=co(function(t){return 2*M_(t)});var by=function(){return no(mo).scale(250).clipAngle(142)};xo.invert=function(t,n){return[-n,2*M_(k_(t))-g_]};var wy=function(){var t=fo(xo),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},My=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=wo(e),t.y=To(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=No(t),c=ko(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=bo,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},Ty=function(){return this.eachAfter(Eo)},Sy=function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},Ny=function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},ky=function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},Ey=function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},Ay=function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},Cy=function(t){for(var n=this,e=Ao(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},zy=function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},Py=function(){var t=[];return this.each(function(n){t.push(n)}),t},Ly=function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},Ry=function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n};qo.prototype=Co.prototype={constructor:qo,count:Ty,each:Sy,eachAfter:ky,eachBefore:Ny,sum:Ey,sort:Ay,path:Cy,ancestors:zy,descendants:Py,leaves:Ly,links:Ry,copy:zo};var qy=function(t){for(var n=(t=t.slice()).length,e=null,r=e;n;){var i=new Uo(t[n-1]);r=r?r.next=i:e=i,t[void 0]=t[--n]}return{head:e,tail:r}},Uy=function(t){return Oo(qy(t),[])},Dy=function(t){return Vo(t),t},Oy=function(t){return function(){return t}},Fy=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(Jo(n)).eachAfter(Qo(i,.5)).eachBefore(Ko(1)):t.eachBefore(Jo(Go)).eachAfter(Qo(Zo,1)).eachAfter(Qo(i,t.r/Math.min(e,r))).eachBefore(Ko(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=Zo;return t.radius=function(e){return arguments.length?(n=$o(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Oy(+n),t):i},t},Iy=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Yy=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)o=u[a],o.y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},By=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore(Iy),t}function n(t,n){return function(e){e.children&&Yy(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},jy="$",Hy={depth:-1},Xy={},Vy=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new qo(r),null!=(c=n(r,i,t))&&(c+="")&&(s=jy+(a.id=c),h[s]=s in h?Xy:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[jy+c]))throw new Error("missing: "+c);if(u===Xy)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Hy,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(Ro),o.parent=null,f>0)throw new Error("cycle");return o}var n=tu,e=nu;return t.id=function(e){return arguments.length?(n=Wo(e),t):n},t.parentId=function(n){return arguments.length?(e=Wo(n),t):e},t};cu.prototype=Object.create(qo.prototype);var $y=function(){function t(t){var r=su(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){uu(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=iu(a),i=ru(i),a&&i;)c=ru(c),u=iu(u),u.a=t,r=a.z+l-i.z-s+o(a._,i._),r>0&&(ou(au(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!iu(u)&&(u.t=a,u.m+=l-f),i&&!ru(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=eu,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},Wy=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)o=u[a],o.x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Zy=(1+Math.sqrt(5))/2,Gy=function t(n){function e(t,e,r,i,o){fu(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Zy),Jy=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore(Iy),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Gy,r=!1,i=1,o=1,u=[0],a=Zo,c=Zo,s=Zo,f=Zo,l=Zo;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Wo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Oy(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Oy(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Oy(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Oy(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Oy(+n),t):l},t},Qy=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,s.y1=a,void 0}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,g=e-_;if(u-r>a-i){var y=(r*g+u*_)/e;o(t,p,_,r,i,y,a),o(p,n,g,y,i,u,a)}else{var m=(i*g+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,g,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)
-},Ky=function(t,n,e,r,i){(1&t.depth?Wy:Yy)(t,n,e,r,i)},tm=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(a=u[l],c=a.children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Yy(a,e,r,i,r+=(o-r)*a.value/p):Wy(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=fu(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Zy),nm=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},em=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},rm=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},im=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(lu),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=hu(r),u=hu(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},om=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)o=t[l],e=o[0],r=o[1],r>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},um=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,o=t[r],u=o[0],a=o[1],n-=u,e-=a,c+=Math.sqrt(n*n+e*e);return c},am=[].slice,cm={};pu.prototype=mu.prototype={constructor:pu,defer:function(t){if("function"!=typeof t||this._call)throw new Error;if(null!=this._error)return this;var n=am.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),du(this),this},abort:function(){return null==this._error&&gu(this,new Error("abort")),this},await:function(t){if("function"!=typeof t||this._call)throw new Error;return this._call=function(n,e){t.apply(null,[n].concat(e))},yu(this),this},awaitAll:function(t){if("function"!=typeof t||this._call)throw new Error;return this._call=t,yu(this),this}};var sm=function(t,n){return t=null==t?0:+t,n=null==n?1:+n,1===arguments.length?(n=t,t=0):n-=t,function(){return Math.random()*n+t}},fm=function(t,n){var e,r;return t=null==t?0:+t,n=null==n?1:+n,function(){var i;if(null!=e)i=e,e=null;else do{e=2*Math.random()-1,i=2*Math.random()-1,r=e*e+i*i}while(!r||r>1);return t+n*i*Math.sqrt(-2*Math.log(r)/r)}},lm=function(){var t=fm.apply(this,arguments);return function(){return Math.exp(t())}},hm=function(t){return function(){for(var n=0,e=0;e<t;++e)n+=Math.random();return n}},pm=function(t){var n=hm(t);return function(){return n()/t}},dm=function(t){return function(){return-Math.log(1-Math.random())/t}},vm=function(t,n){function e(t){var n,e=s.status;if(!e&&bu(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=v("beforesend","progress","load","error"),c=Be(),s=new XMLHttpRequest,f=null,l=null,h=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(h=+t,r):h},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),h>0&&(s.timeout=h),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=xu(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},_m=function(t,n){return function(e,r){var i=vm(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},gm=_m("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),ym=_m("application/json",function(t){return JSON.parse(t.responseText)}),mm=_m("text/plain",function(t){return t.responseText}),xm=_m("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),bm=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=vm(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(wu(n,r=t)):r},o.row(r),i?o.get(i):o}},wm=bm("text/csv",Fd),Mm=bm("text/tab-separated-values",Hd),Tm=Array.prototype,Sm=Tm.map,Nm=Tm.slice,km={name:"implicit"},Em=function(t){return function(){return t}},Am=function(t){return+t},Cm=[0,1],zm=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch(r=hr(null==r?",f":r),r.type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=Rv(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=qv(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=Lv(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},Pm=function(t,n){t=t.slice();var e,r=0,i=t.length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},Lm=new Date,Rm=new Date,qm=Gu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});qm.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Gu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):qm:null};var Um=qm.range,Dm=6e4,Om=6048e5,Fm=Gu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),Im=Fm.range,Ym=Gu(function(t){t.setTime(Math.floor(t/Dm)*Dm)},function(t,n){t.setTime(+t+n*Dm)},function(t,n){return(n-t)/Dm},function(t){return t.getMinutes()}),Bm=Ym.range,jm=Gu(function(t){var n=t.getTimezoneOffset()*Dm%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),Hm=jm.range,Xm=Gu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Dm)/864e5},function(t){return t.getDate()-1}),Vm=Xm.range,$m=Ju(0),Wm=Ju(1),Zm=Ju(2),Gm=Ju(3),Jm=Ju(4),Qm=Ju(5),Km=Ju(6),tx=$m.range,nx=Wm.range,ex=Zm.range,rx=Gm.range,ix=Jm.range,ox=Qm.range,ux=Km.range,ax=Gu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),cx=ax.range,sx=Gu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});sx.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Gu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var fx=sx.range,lx=Gu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*Dm)},function(t,n){return(n-t)/Dm},function(t){return t.getUTCMinutes()}),hx=lx.range,px=Gu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),dx=px.range,vx=Gu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),_x=vx.range,gx=Qu(0),yx=Qu(1),mx=Qu(2),xx=Qu(3),bx=Qu(4),wx=Qu(5),Mx=Qu(6),Tx=gx.range,Sx=yx.range,Nx=mx.range,kx=xx.range,Ex=bx.range,Ax=wx.range,Cx=Mx.range,zx=Gu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Px=zx.range,Lx=Gu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Lx.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Gu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Rx,qx=Lx.range,Ux={"-":"",_:" ",0:"0"},Dx=/^\s*\d+/,Ox=/^%/,Fx=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ga({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Ix=Date.prototype.toISOString?Ja:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Yx=+new Date("2000-01-01T00:00:00.000Z")?Qa:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Bx=1e3,jx=60*Bx,Hx=60*jx,Xx=24*Hx,Vx=7*Xx,$x=30*Xx,Wx=365*Xx,Zx=function(){return nc(sx,ax,$m,Xm,jm,Ym,Fm,qm,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},Gx=function(){return nc(Lx,zx,gx,vx,px,lx,Fm,qm,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},Jx=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},Qx=Jx("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Kx=Jx("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),tb=Jx("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),nb=Jx("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),eb=Fh($t(300,.5,0),$t(-240,.5,1)),rb=Fh($t(-100,.75,.35),$t(80,1.5,.8)),ib=Fh($t(260,.75,.35),$t(80,1.5,.8)),ob=$t(),ub=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return ob.h=360*t-100,ob.s=1.5-1.5*n,ob.l=.8-.9*n,ob+""},ab=ec(Jx("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),cb=ec(Jx("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),sb=ec(Jx("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),fb=ec(Jx("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),lb=function(t){return function(){return t}},hb=Math.abs,pb=Math.atan2,db=Math.cos,vb=Math.max,_b=Math.min,gb=Math.sin,yb=Math.sqrt,mb=1e-12,xb=Math.PI,bb=xb/2,wb=2*xb,Mb=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-bb,p=u.apply(this,arguments)-bb,d=hb(p-h),v=p>h;if(c||(c=t=qe()),l<f&&(s=l,l=f,f=s),l>mb)if(d>wb-mb)c.moveTo(l*db(h),l*gb(h)),c.arc(0,0,l,h,p,!v),f>mb&&(c.moveTo(f*db(p),f*gb(p)),c.arc(0,0,f,p,h,v));else{var _,g,y=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,S=T>mb&&(i?+i.apply(this,arguments):yb(f*f+l*l)),N=_b(hb(l-f)/2,+r.apply(this,arguments)),k=N,E=N;if(S>mb){var A=oc(S/f*gb(T)),C=oc(S/l*gb(T));(w-=2*A)>mb?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>mb?(C*=v?1:-1,y+=C,m-=C):(M=0,y=m=(h+p)/2)}var z=l*db(y),P=l*gb(y),L=f*db(b),R=f*gb(b);if(N>mb){var q=l*db(m),U=l*gb(m),D=f*db(x),O=f*gb(x);if(d<xb){var F=w>mb?lc(z,P,D,O,q,U,L,R):[L,R],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/gb(ic((I*B+Y*j)/(yb(I*I+Y*Y)*yb(B*B+j*j)))/2),X=yb(F[0]*F[0]+F[1]*F[1]);k=_b(N,(f-X)/(H-1)),E=_b(N,(l-X)/(H+1))}}M>mb?E>mb?(_=hc(D,O,z,P,l,E,v),g=hc(q,U,L,R,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,pb(_.y01,_.x01),pb(g.y01,g.x01),!v):(c.arc(_.cx,_.cy,E,pb(_.y01,_.x01),pb(_.y11,_.x11),!v),c.arc(0,0,l,pb(_.cy+_.y11,_.cx+_.x11),pb(g.cy+g.y11,g.cx+g.x11),!v),c.arc(g.cx,g.cy,E,pb(g.y11,g.x11),pb(g.y01,g.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,y,m,!v)):c.moveTo(z,P),f>mb&&w>mb?k>mb?(_=hc(L,R,q,U,f,-k,v),g=hc(z,P,D,O,f,-k,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),k<N?c.arc(_.cx,_.cy,k,pb(_.y01,_.x01),pb(g.y01,g.x01),!v):(c.arc(_.cx,_.cy,k,pb(_.y01,_.x01),pb(_.y11,_.x11),!v),c.arc(0,0,f,pb(_.cy+_.y11,_.cx+_.x11),pb(g.cy+g.y11,g.cx+g.x11),v),c.arc(g.cx,g.cy,k,pb(g.y11,g.x11),pb(g.y01,g.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(L,R)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=uc,e=ac,r=lb(0),i=null,o=cc,u=sc,a=fc,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-xb/2;return[db(r)*t,gb(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:lb(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:lb(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:lb(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:lb(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:lb(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:lb(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:lb(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t};pc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Tb=function(t){return new pc(t)},Sb=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=qe())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=dc,e=vc,r=lb(!0),i=null,o=Tb,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:lb(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:lb(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:lb(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},Nb=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),g=new Array(d);for(null==a&&(s=c(p=qe())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],g[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),g[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):g[n]))}if(p)return s=null,p+""||null}function n(){return Sb().defined(u).curve(c).context(a)}var e=dc,r=null,i=lb(0),o=vc,u=lb(!0),a=null,c=Tb,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:lb(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:lb(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:lb(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:lb(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:lb(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:lb(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:lb(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},kb=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Eb=function(t){return t},Ab=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),g=Math.min(wb,Math.max(-wb,o.apply(this,arguments)-_)),y=Math.min(Math.abs(g)/h,u.apply(this,arguments)),m=y*(g<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(g-h*m)/p:0;a<h;++a,_=f)c=d[a],l=v[c],f=_+(l>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:y};return v}var n=Eb,e=kb,r=null,i=lb(0),o=lb(wb),u=lb(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:lb(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:lb(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:lb(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:lb(+n),t):u},t},Cb=gc(Tb);_c.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var zb=function(){return yc(Sb().curve(Cb))},Pb=function(){var t=Nb().curve(Cb),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return yc(e())},delete t.lineX0,t.lineEndAngle=function(){return yc(r())},delete t.lineX1,t.lineInnerRadius=function(){return yc(i())},delete t.lineY0,t.lineOuterRadius=function(){return yc(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(gc(t)):n()._curve},t},Lb={draw:function(t,n){var e=Math.sqrt(n/xb);t.moveTo(e,0),t.arc(0,0,e,0,wb)}},Rb={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},qb=Math.sqrt(1/3),Ub=2*qb,Db={draw:function(t,n){var e=Math.sqrt(n/Ub),r=e*qb;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Ob=Math.sin(xb/10)/Math.sin(7*xb/10),Fb=Math.sin(wb/10)*Ob,Ib=-Math.cos(wb/10)*Ob,Yb={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Fb*e,i=Ib*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=wb*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},Bb={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},jb=Math.sqrt(3),Hb={draw:function(t,n){var e=-Math.sqrt(n/(3*jb));t.moveTo(0,2*e),t.lineTo(-jb*e,-e),t.lineTo(jb*e,-e),t.closePath()}},Xb=-.5,Vb=Math.sqrt(3)/2,$b=1/Math.sqrt(12),Wb=3*($b/2+1),Zb={draw:function(t,n){var e=Math.sqrt(n/Wb),r=e/2,i=e*$b,o=r,u=e*$b+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Xb*r-Vb*i,Vb*r+Xb*i),t.lineTo(Xb*o-Vb*u,Vb*o+Xb*u),t.lineTo(Xb*a-Vb*c,Vb*a+Xb*c),t.lineTo(Xb*r+Vb*i,Xb*i-Vb*r),t.lineTo(Xb*o+Vb*u,Xb*u-Vb*o),t.lineTo(Xb*a+Vb*c,Xb*c-Vb*a),t.closePath()}},Gb=[Lb,Rb,Db,Bb,Yb,Hb,Zb],Jb=function(){function t(){var t;if(r||(r=t=qe()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=lb(Lb),e=lb(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:lb(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:lb(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},Qb=function(){};xc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:mc(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:mc(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var Kb=function(t){return new xc(t)};bc.prototype={areaStart:Qb,areaEnd:Qb,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:mc(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var tw=function(t){return new bc(t)};wc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:mc(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var nw=function(t){return new wc(t)};Mc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var ew=function t(n){function e(t){return 1===n?new xc(t):new Mc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);Sc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Tc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Tc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var rw=function t(n){function e(t){return new Sc(t,n)}return e.tension=function(n){return t(+n)},e}(0);Nc.prototype={areaStart:Qb,areaEnd:Qb,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Tc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var iw=function t(n){function e(t){return new Nc(t,n)}return e.tension=function(n){return t(+n)},e}(0);kc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Tc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ow=function t(n){function e(t){return new kc(t,n)}return e.tension=function(n){return t(+n)},e}(0);Ac.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,
-this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Ec(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var uw=function t(n){function e(t){return n?new Ac(t,n):new Sc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);Cc.prototype={areaStart:Qb,areaEnd:Qb,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Ec(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var aw=function t(n){function e(t){return n?new Cc(t,n):new Nc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);zc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Ec(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var cw=function t(n){function e(t){return n?new zc(t,n):new kc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);Pc.prototype={areaStart:Qb,areaEnd:Qb,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};var sw=function(t){return new Pc(t)};Dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:Uc(this,this._t0,qc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,Uc(this,qc(this,e=Rc(this,t,n)),e);break;default:Uc(this,this._t0,e=Rc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Oc.prototype=Object.create(Dc.prototype)).point=function(t,n){Dc.prototype.point.call(this,n,t)},Fc.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},Bc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=jc(t),i=jc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var fw=function(t){return new Bc(t)};Hc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var lw=function(t){return new Hc(t,.5)},hw=Array.prototype.slice,pw=function(t,n){if((r=t.length)>1)for(var e,r,i=1,o=t[n[0]],u=o.length;i<r;++i){e=o,o=t[n[i]];for(var a=0;a<u;++a)o[a][1]+=o[a][0]=isNaN(e[a][1])?e[a][0]:e[a][1]}},dw=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},vw=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=lb([]),e=dw,r=pw,i=$c;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:lb(hw.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:lb(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?dw:"function"==typeof n?n:lb(hw.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?pw:n,t):r},t},_w=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}pw(t,n)}},gw=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}pw(t,n)}},yw=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=f[u-1][1]||0,p=(l-h)/2,d=0;d<a;++d){var v=t[n[d]];p+=(v[u][1]||0)-(v[u-1][1]||0)}c+=l,s+=p*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,pw(t,n)}},mw=function(t){var n=t.map(Wc);return dw(t).sort(function(t,e){return n[t]-n[e]})},xw=function(t){return mw(t).reverse()},bw=function(t){var n,e,r=t.length,i=t.map(Wc),o=dw(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},ww=function(t){return dw(t).reverse()},Mw=function(t){return function(){return t}};Jc.prototype={constructor:Jc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=ns(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Kc(this,e),t=e,e=t.U),e.C=!1,r.C=!0,ts(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(ts(this,e),t=e,e=t.U),e.C=!1,r.C=!0,Kc(this,r))),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?ns(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r){if(t&&t.C)return void(t.C=!1);do{if(t===this._)break;if(t===i.L){if(n=i.R,n.C&&(n.C=!1,i.C=!0,Kc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,ts(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Kc(this,i),t=this._;break}}else if(n=i.L,n.C&&(n.C=!1,i.C=!0,ts(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Kc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,ts(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var Tw,Sw,Nw,kw,Ew,Aw=[],Cw=[],zw=1e-6,Pw=1e-12;Ns.prototype={constructor:Ns,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return fs(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,s=n[i[c]],f=s.left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Ts(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var Lw=function(){function t(t){return new Ns(t.map(function(r,i){var o=[Math.round(n(r,i,t)/zw)*zw,Math.round(e(r,i,t)/zw)*zw];return o.index=i,o.data=r,o}),r)}var n=Zc,e=Gc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:Mw(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:Mw(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},Rw=function(t){return function(){return t}};Es.prototype={constructor:Es,scale:function(t){return 1===t?this:new Es(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new Es(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var qw=new Es(1,0,0);As.prototype=Es.prototype;var Uw=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},Dw=function(){function n(t){}function e(t,n){return n=Math.max(x,Math.min(b,n)),n===t.k?t:new Es(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new Es(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-w,r=t.invertX(n[1][0])-M,i=t.invertY(n[0][1])-T,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=k(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new Es(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=E.length;r<i;++r)if((e=E[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){function n(){o.wheel=null,o.end()}if(y.apply(this,arguments)){var o=a(this,arguments),u=this.__zoom,c=Math.max(x,Math.min(b,u.k*Math.pow(2,-t.event.deltaY*(t.event.deltaMode?120:1)/500))),s=If(this);if(o.wheel)o.mouse[0][0]===s[0]&&o.mouse[0][1]===s[1]||(o.mouse[1]=u.invert(o.mouse[0]=s)),clearTimeout(o.wheel);else{if(u.k===c)return;o.mouse=[s,u.invert(s)],cp(this),o.start()}Uw(),o.wheel=setTimeout(n,P),o.zoom("mouse",i(r(e(u,c),o.mouse[0],o.mouse[1]),o.extent))}}function f(){function n(){Uw(),o.moved=!0,o.zoom("mouse",i(r(o.that.__zoom,o.mouse[0]=If(o.that),o.mouse[1]),o.extent))}function e(){u.on("mousemove.zoom mouseup.zoom",null),yt(t.event.view,o.moved),Uw(),o.end()}if(!g&&y.apply(this,arguments)){var o=a(this,arguments),u=wl(t.event.view).on("mousemove.zoom",n,!0).on("mouseup.zoom",e,!0),c=If(this);kl(t.event.view),Cs(),o.mouse=[c,this.__zoom.invert(c)],cp(this),o.start()}}function l(){if(y.apply(this,arguments)){var o=this.__zoom,a=If(this),c=o.invert(a),s=o.k*(t.event.shiftKey?.5:2),f=i(r(e(o,s),a,c),m.apply(this,arguments));Uw(),N>0?wl(this).transition().duration(N).call(u,f,a):wl(this).call(n.transform,f)}}function h(){if(y.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(Cs(),e=0;e<c;++e)r=u[e],i=Tl(this,u,r.identifier),i=[i,this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=wl(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},z),cp(this),o.start())}}function p(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(Uw(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=Tl(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],g=(g=d[0]-h[0])*g+(g=d[1]-h[1])*g,y=(y=v[0]-p[0])*y+(y=v[1]-p[1])*y;o=e(o,Math.sqrt(g/y)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function d(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(Cs(),g&&clearTimeout(g),g=setTimeout(function(){g=null},z),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,g,y=zs,m=Ps,x=0,b=1/0,w=-b,M=b,T=w,S=M,N=250,k=Lh,E=[],C=v("start","zoom","end"),z=500,P=150;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",Ls),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},c.prototype={start:function(){return 1==++this.active&&(this.index=E.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(E.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){A(new ks(n,t,this.that.__zoom),C.apply,C,[t,this.that,this.args])}},n.filter=function(t){return arguments.length?(y="function"==typeof t?t:Rw(!!t),n):y},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:Rw([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(x=+t[0],b=+t[1],n):[x,b]},n.translateExtent=function(t){return arguments.length?(w=+t[0][0],M=+t[1][0],T=+t[0][1],S=+t[1][1],n):[[w,T],[M,S]]},n.duration=function(t){return arguments.length?(N=+t,n):N},n.interpolate=function(t){return arguments.length?(k=t,n):k},n.on=function(){var t=C.on.apply(C,arguments);return t===C?n:t},n};t.version="4.8.0",t.bisect=Ds,t.bisectRight=Ds,t.bisectLeft=Os,t.ascending=Rs,t.bisector=qs,t.cross=Is,t.descending=Ys,t.deviation=Hs,t.extent=Xs,t.histogram=rf,t.thresholdFreedmanDiaconis=uf,t.thresholdScott=af,t.thresholdSturges=ef,t.max=cf,t.mean=sf,t.median=ff,t.merge=lf,t.min=hf,t.pairs=Fs,t.permute=pf,t.quantile=of,t.range=Js,t.scan=df,t.shuffle=vf,t.sum=_f,t.ticks=nf,t.tickIncrement=r,t.tickStep=i,t.transpose=gf,t.variance=js,t.zip=yf,t.axisTop=l,t.axisRight=h,t.axisBottom=p,t.axisLeft=d,t.brush=yd,t.brushX=Ce,t.brushY=ze,t.brushSelection=Ae,t.chord=Sd,t.ribbon=zd,t.nest=Pd,t.set=We,t.map=Be,t.keys=Rd,t.values=qd,t.entries=Ud,t.color=St,t.rgb=At,t.hsl=Lt,t.lab=Dt,t.hcl=Ht,t.cubehelix=$t,t.dispatch=v,t.drag=Al,t.dragDisable=kl,t.dragEnable=yt,t.dsvFormat=Dd,t.csvParse=Fd,t.csvParseRows=Id,t.csvFormat=Yd,t.csvFormatRows=Bd,t.tsvParse=Hd,t.tsvParseRows=Xd,t.tsvFormat=Vd,t.tsvFormatRows=$d,t.easeLinear=re,t.easeQuad=ue,t.easeQuadIn=ie,t.easeQuadOut=oe,t.easeQuadInOut=ue,t.easeCubic=se,t.easeCubicIn=ae,t.easeCubicOut=ce,t.easeCubicInOut=se,t.easePoly=Lp,t.easePolyIn=zp,t.easePolyOut=Pp,t.easePolyInOut=Lp,t.easeSin=he,t.easeSinIn=fe,t.easeSinOut=le,t.easeSinInOut=he,t.easeExp=ve,t.easeExpIn=pe,t.easeExpOut=de,t.easeExpInOut=ve,t.easeCircle=ye,t.easeCircleIn=_e,t.easeCircleOut=ge,t.easeCircleInOut=ye,t.easeBounce=xe,t.easeBounceIn=me,t.easeBounceOut=xe,t.easeBounceInOut=be,t.easeBack=Wp,t.easeBackIn=Vp,t.easeBackOut=$p,t.easeBackInOut=Wp,t.easeElastic=Jp,t.easeElasticIn=Gp,t.easeElasticOut=Jp,t.easeElasticInOut=Qp,t.forceCenter=Wd,t.forceCollide=hv,t.forceLink=pv,t.forceManyBody=gv,t.forceSimulation=_v,t.forceX=yv,t.forceY=mv,t.formatDefaultLocale=dr,t.formatLocale=Pv,t.formatSpecifier=hr,t.precisionFixed=Lv,t.precisionPrefix=Rv,t.precisionRound=qv,t.geoArea=I_,t.geoBounds=j_,t.geoCentroid=X_,t.geoCircle=ug,t.geoClipExtent=pg,t.geoContains=Tg,t.geoDistance=bg,t.geoGraticule=Mi,t.geoGraticule10=Ti,t.geoInterpolate=Sg,t.geoLength=yg,t.geoPath=Qg,t.geoAlbers=cy,t.geoAlbersUsa=sy,t.geoAzimuthalEqualArea=ly,t.geoAzimuthalEqualAreaRaw=fy,t.geoAzimuthalEquidistant=py,t.geoAzimuthalEquidistantRaw=hy,t.geoConicConformal=vy,t.geoConicConformalRaw=ho,t.geoConicEqualArea=ay,t.geoConicEqualAreaRaw=oo,t.geoConicEquidistant=gy,t.geoConicEquidistantRaw=vo,t.geoEquirectangular=_y,t.geoEquirectangularRaw=po,t.geoGnomonic=yy,t.geoGnomonicRaw=_o,t.geoIdentity=my,t.geoProjection=no,t.geoProjectionMutator=eo,t.geoMercator=dy,t.geoMercatorRaw=so,t.geoOrthographic=xy,t.geoOrthographicRaw=yo,t.geoStereographic=by,t.geoStereographicRaw=mo,t.geoTransverseMercator=wy,t.geoTransverseMercatorRaw=xo,t.geoRotation=og,t.geoStream=U_,t.geoTransform=ey,t.cluster=My,t.hierarchy=Co,t.pack=Fy,t.packSiblings=Dy,t.packEnclose=Uy,t.partition=By,t.stratify=Vy,t.tree=$y,t.treemap=Jy,t.treemapBinary=Qy,t.treemapDice=Yy,t.treemapSlice=Wy,t.treemapSliceDice=Ky,t.treemapSquarify=Gy,t.treemapResquarify=tm,t.interpolate=Sh,t.interpolateArray=yh,t.interpolateBasis=hh,t.interpolateBasisClosed=ph,t.interpolateDate=mh,t.interpolateNumber=xh,t.interpolateObject=bh,t.interpolateRound=Nh,t.interpolateString=Th,t.interpolateTransformCss=Ch,t.interpolateTransformSvg=zh,t.interpolateZoom=Lh,t.interpolateRgb=vh,t.interpolateRgbBasis=_h,t.interpolateRgbBasisClosed=gh,t.interpolateHsl=Rh,t.interpolateHslLong=qh,t.interpolateLab=hn,t.interpolateHcl=Uh,t.interpolateHclLong=Dh,t.interpolateCubehelix=Oh,t.interpolateCubehelixLong=Fh,t.quantize=Ih,t.path=qe,t.polygonArea=nm,t.polygonCentroid=em;t.polygonHull=im,t.polygonContains=om,t.polygonLength=um,t.quadtree=rr,t.queue=mu,t.randomUniform=sm,t.randomNormal=fm,t.randomLogNormal=lm,t.randomBates=pm,t.randomIrwinHall=hm,t.randomExponential=dm,t.request=vm,t.html=gm,t.json=ym,t.text=mm,t.xml=xm,t.csv=wm,t.tsv=Mm,t.scaleBand=Tu,t.scalePoint=Nu,t.scaleIdentity=Uu,t.scaleLinear=qu,t.scaleLog=ju,t.scaleOrdinal=Mu,t.scaleImplicit=km,t.scalePow=Xu,t.scaleSqrt=Vu,t.scaleQuantile=$u,t.scaleQuantize=Wu,t.scaleThreshold=Zu,t.scaleTime=Zx,t.scaleUtc=Gx,t.schemeCategory10=Qx,t.schemeCategory20b=Kx,t.schemeCategory20c=tb,t.schemeCategory20=nb,t.interpolateCubehelixDefault=eb,t.interpolateRainbow=ub,t.interpolateWarm=rb,t.interpolateCool=ib,t.interpolateViridis=ab,t.interpolateMagma=cb,t.interpolateInferno=sb,t.interpolatePlasma=fb,t.scaleSequential=rc,t.creator=Cf,t.local=w,t.matcher=qf,t.mouse=If,t.namespace=Af,t.namespaces=Ef,t.select=wl,t.selectAll=Ml,t.selection=_t,t.selector=Yf,t.selectorAll=jf,t.touch=Tl,t.touches=Sl,t.window=cl,t.customEvent=A,t.arc=Mb,t.area=Nb,t.line=Sb,t.pie=Ab,t.radialArea=Pb,t.radialLine=zb,t.symbol=Jb,t.symbols=Gb,t.symbolCircle=Lb,t.symbolCross=Rb,t.symbolDiamond=Db,t.symbolSquare=Bb,t.symbolStar=Yb,t.symbolTriangle=Hb,t.symbolWye=Zb,t.curveBasisClosed=tw,t.curveBasisOpen=nw,t.curveBasis=Kb,t.curveBundle=ew,t.curveCardinalClosed=iw,t.curveCardinalOpen=ow,t.curveCardinal=rw,t.curveCatmullRomClosed=aw,t.curveCatmullRomOpen=cw,t.curveCatmullRom=uw,t.curveLinearClosed=sw,t.curveLinear=Tb,t.curveMonotoneX=Ic,t.curveMonotoneY=Yc,t.curveNatural=fw,t.curveStep=lw,t.curveStepAfter=Vc,t.curveStepBefore=Xc,t.stack=vw,t.stackOffsetExpand=_w,t.stackOffsetNone=pw,t.stackOffsetSilhouette=gw,t.stackOffsetWiggle=yw,t.stackOrderAscending=mw,t.stackOrderDescending=xw,t.stackOrderInsideOut=bw,t.stackOrderNone=dw,t.stackOrderReverse=ww,t.timeInterval=Gu,t.timeMillisecond=qm,t.timeMilliseconds=Um,t.utcMillisecond=qm,t.utcMilliseconds=Um,t.timeSecond=Fm,t.timeSeconds=Im,t.utcSecond=Fm,t.utcSeconds=Im,t.timeMinute=Ym,t.timeMinutes=Bm,t.timeHour=jm,t.timeHours=Hm,t.timeDay=Xm,t.timeDays=Vm,t.timeWeek=$m,t.timeWeeks=tx,t.timeSunday=$m,t.timeSundays=tx,t.timeMonday=Wm,t.timeMondays=nx,t.timeTuesday=Zm,t.timeTuesdays=ex,t.timeWednesday=Gm,t.timeWednesdays=rx,t.timeThursday=Jm,t.timeThursdays=ix,t.timeFriday=Qm,t.timeFridays=ox,t.timeSaturday=Km,t.timeSaturdays=ux,t.timeMonth=ax,t.timeMonths=cx,t.timeYear=sx,t.timeYears=fx,t.utcMinute=lx,t.utcMinutes=hx,t.utcHour=px,t.utcHours=dx,t.utcDay=vx,t.utcDays=_x,t.utcWeek=gx,t.utcWeeks=Tx,t.utcSunday=gx,t.utcSundays=Tx,t.utcMonday=yx,t.utcMondays=Sx,t.utcTuesday=mx,t.utcTuesdays=Nx,t.utcWednesday=xx,t.utcWednesdays=kx,t.utcThursday=bx,t.utcThursdays=Ex,t.utcFriday=wx,t.utcFridays=Ax,t.utcSaturday=Mx,t.utcSaturdays=Cx,t.utcMonth=zx,t.utcMonths=Px,t.utcYear=Lx,t.utcYears=qx,t.timeFormatDefaultLocale=Ga,t.timeFormatLocale=ea,t.isoFormat=Ix,t.isoParse=Yx,t.now=vn,t.timer=yn,t.timerFlush=mn,t.timeout=Gh,t.interval=Jh,t.transition=ne,t.active=ed,t.interrupt=cp,t.voronoi=Lw,t.zoom=Dw,t.zoomTransform=As,t.zoomIdentity=qw,Object.defineProperty(t,"__esModule",{value:!0})});
-
-function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}();!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.dTree=t()}(this,function(){"use strict";var e=function(){function e(t,n,r){_classCallCheck(this,e),e.DEBUG_LEVEL=r.debug?1:0,this.root=t,this.siblings=n,this.opts=r,this.allNodes=this._flatten(this.root);var a=_.filter(this.allNodes,function(e){return!e.hidden});this.nodeSize=r.callbacks.nodeSize(a,r.nodeWidth,r.callbacks.textRenderer)}return _createClass(e,[{key:"create",value:function(){var e=this.opts,t=(this.allNodes,this.nodeSize),n=e.width+e.margin.left+e.margin.right,r=e.height+e.margin.top+e.margin.bottom,a=d3.zoom().scaleExtent([.1,10]).on("zoom",function(){i.attr("transform",d3.event.transform.translate(n/2,0))}),i=this.svg=d3.select(e.target).append("svg").attr("width",n).attr("height",r).call(a).append("g").attr("transform","translate("+n/2+",0)");this.tree=d3.tree().nodeSize([2*t[0],2.5*t[1]]),this.tree.separation(function(e,t){return e.data.hidden||t.data.hidden?.3:.6}),this._update(this.root)}},{key:"_update",value:function(e){var t=this.opts,n=(this.allNodes,this.nodeSize),r=this.tree(e),a=r.links();this.svg.selectAll(".link").data(a).enter().filter(function(e){return!e.target.data.noParent}).append("path").attr("class",t.styles.linage).attr("d",this._elbow);var i=this.svg.selectAll(".node").data(r.descendants()).enter();this._linkSiblings(),this.svg.selectAll(".sibling").data(this.siblings).enter().append("path").attr("class",t.styles.marriage).attr("d",_.bind(this._siblingLine,this)),i.append("foreignObject").filter(function(e){return!e.data.hidden}).attr("x",function(e){return e.x-e.cWidth/2+"px"}).attr("y",function(e){return e.y-e.cHeight/2+"px"}).attr("width",function(e){return e.cWidth+"px"}).attr("height",function(e){return e.cHeight+"px"}).attr("id",function(e){return e.id}).html(function(e){return t.callbacks.nodeRenderer(e.data.name,e.x,e.y,n[0],n[1],e.data.extra,e.data.id,e.data["class"],e.data.textClass,t.callbacks.textRenderer)}).on("click",function(e){e.data.hidden||t.callbacks.nodeClick(e.data.name,e.data.extra,e.data.id)})}},{key:"_flatten",value:function(e){function t(e){e.children&&e.children.forEach(t),e.id||(e.id=++r),n.push(e)}var n=[],r=0;return t(e),n}},{key:"_elbow",value:function(e,t){if(e.target.data.noParent)return"M0,0L0,0";var n=e.target.y+.5*(e.source.y-e.target.y),r=[{x:e.target.x,y:e.target.y},{x:e.target.x,y:n},{x:e.source.x,y:e.source.y}],a=d3.line().curve(d3.curveStepAfter).x(function(e){return e.x}).y(function(e){return e.y});return a(r)}},{key:"_linkSiblings",value:function(){var e=this.allNodes;_.forEach(this.siblings,function(t){var n=e.filter(function(e){return t.source.id==e.data.id}),r=e.filter(function(e){return t.target.id==e.data.id});t.source.x=n[0].x,t.source.y=n[0].y,t.target.x=r[0].x,t.target.y=r[0].y})}},{key:"_siblingLine",value:function(e,t){var n=e.target.y+.5*(e.source.y-e.target.y),r=this.nodeSize[0],a=this.nodeSize[1];e.number>0&&(n-=8*a/10);var i=[{x:e.source.x,y:e.source.y},{x:e.source.x+6*r/10,y:e.source.y},{x:e.source.x+6*r/10,y:n},{x:e.target.x-6*r/10,y:n},{x:e.target.x-6*r/10,y:e.target.y},{x:e.target.x,y:e.target.y}],s=d3.line().curve(d3.curveStepAfter).x(function(e){return e.x}).y(function(e){return e.y});return s(i)}}],[{key:"_nodeSize",value:function(e,t,n){var r=0,a=document.createElement("svg");return document.body.appendChild(a),_.map(e,function(e){var i=document.createElement("div");i.setAttribute("class",e.data["class"]),i.style.visibility="hidden",i.style.maxWidth=t+"px";var s=n(e.data.name,e.data.extra,e.data.textClass);i.innerHTML=s,a.appendChild(i);var o=16;a.removeChild(i),r=Math.max(r,o),e.cHeight=o,e.cWidth=t}),document.body.removeChild(a),[t,r]}},{key:"_nodeRenderer",value:function(e,t,n,r,a,i,s,o,d,c){var l="";return l+="<div ",l+='style="height:100%;width:100%;" ',l+='class="'+o+'" ',l+='id="node'+s+'">\n',l+=c(e,i,d),l+="</div>"}},{key:"_textRenderer",value:function(e,t,n){var r="";return r+="<p ",r+='align="center" ',r+='class="'+n+'">\n',r+=e,r+="</p>\n"}},{key:"_debug",value:function(t){e.DEBUG_LEVEL>0&&console.log(t)}}]),e}(),t={VERSION:"2.0.1",init:function(t){var n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],r=_.defaultsDeep(n||{},{target:"#graph",debug:!1,width:600,height:600,callbacks:{nodeClick:function(e,t,n){},nodeRenderer:function(t,n,r,a,i,s,o,d,c,l){return e._nodeRenderer(t,n,r,a,i,s,o,d,c,l)},nodeSize:function(t,n,r){return e._nodeSize(t,n,r)},nodeSorter:function(e,t,n,r){return 0},textRenderer:function(t,n,r){return e._textRenderer(t,n,r)}},margin:{top:0,right:0,bottom:0,left:0},nodeWidth:100,styles:{node:"node",linage:"linage",marriage:"marriage",text:"nodeText"}}),t=this._preprocess(t,r),a=new e(t.root,t.siblings,r);a.create()},_preprocess:function(e,n){var r=[],a=0,i={name:"",id:a++,hidden:!0,children:[]},s=function o(e,s){var d={name:e.name,id:a++,hidden:!1,children:[],extra:e.extra,textClass:e.textClass?e.textClass:n.styles.text,"class":e["class"]?e["class"]:n.styles.node};s==i&&(d.noParent=!0);for(var c=0;c<e.depthOffset;c++){var l={name:"",id:a++,hidden:!0,children:[],noParent:d.noParent};s.children.push(l),s=l}t._sortPersons(e.children,n),_.forEach(e.children,function(e){o(e,d)}),s.children.push(d),t._sortMarriages(e.marriages,n),_.forEach(e.marriages,function(e,i){var c={name:"",id:a++,hidden:!0,noParent:!0,children:[],extra:e.extra},l=e.spouse,u={name:l.name,id:a++,hidden:!1,noParent:!0,children:[],textClass:l.textClass?l.textClass:n.styles.text,"class":l["class"]?l["class"]:n.styles.node,extra:l.extra};s.children.push(c,u),t._sortPersons(e.children,n),_.forEach(e.children,function(e){o(e,c)}),r.push({source:{id:d.id},target:{id:u.id},number:i})})};return _.forEach(e,function(e){s(e,i)}),{root:d3.hierarchy(i),siblings:r}},_sortPersons:function(e,t){return void 0!=e&&e.sort(function(e,n){return t.callbacks.nodeSorter(e.name,e.extra,n.name,n.extra)}),e},_sortMarriages:function(e,t){return void 0!=e&&Array.isArray(e)&&e.sort(function(e,n){var r=e.spouse,a=n.spouse;return t.callbacks.nodeSorter(r.name,r.extra,a.name,a.extra)}),e}};return t});
-}).call(window,window)
diff --git a/src/js/economyJS.js b/src/js/economyJS.js
index 9911372e1d3310e7720356d22166c35dd3e3c2ff..83c63f68420bd956c02c5f32f401ec13724b3092 100644
--- a/src/js/economyJS.js
+++ b/src/js/economyJS.js
@@ -806,7 +806,8 @@ globalThis.calculateCosts = (function() {
 	}
 
 	function getPCFoodCosts() {
-		const foodCost = V.mods.food.cost;
+		const slimnessFoodMod = V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 && !canEatFood(V.PC) ? 1.15 : 1;
+		const foodCost = V.mods.food.cost * slimnessFoodMod;
 		let costs = 0;
 		// Well this ought to be a mess.
 		// Basic food costs
@@ -875,6 +876,7 @@ globalThis.calculateCosts = (function() {
 				costs += foodCost * V.PC.pregType;
 			}
 		}
+		costs = Math.trunc(costs);
 		if (V.PC.diet === 'XX' || V.PC.diet === 'XY') {
 			costs += 25;
 		} else if (V.PC.diet === 'fertility') {
@@ -1124,8 +1126,9 @@ globalThis.getSlaveCostArray = function(s) {
 	let cost = 0;
 	let retval = [];
 	let t = "";
+	const slimnessFoodMod = V.arcologies[0].FSSlimnessEnthusiastFoodLaw === 1 ? 1.15 : 1;
 	const rulesCost = V.rulesCost;
-	const foodCost = V.mods.food.cost;
+	const foodCost = V.mods.food.cost * slimnessFoodMod;
 	const drugsCost = V.drugsCost;
 
 	// Living expenses
@@ -1215,24 +1218,42 @@ globalThis.getSlaveCostArray = function(s) {
 	retval.push({text: "Living Expenses", value: cost});
 
 	// Food
-	retval.push({text: "Basic slave food cost", value: foodCost * 4});
+	retval.push({
+		text: "Basic slave food cost",
+		value: Math.trunc(foodCost * 4)
+	});
 
 	switch (s.diet) {
 		case 'fattening':
 		case 'muscle building':
-			retval.push({text: "Heavy diet", value: foodCost});
+			retval.push({
+				text: "Heavy diet",
+				value: Math.trunc(foodCost)
+			});
 			break;
 		case 'restricted':
 		case 'slimming':
-			retval.push({text: "Light diet, reduced by", value: -Math.abs(foodCost)});
+			retval.push({
+				text: "Light diet, reduced by",
+				value: -Math.abs(Math.trunc(foodCost))
+			});
 			break;
 	}
 	if (s.weight > 130) {
-		retval.push({text: "Heavy weight", value: foodCost * 2});
+		retval.push({
+			text: "Heavy weight",
+			value: Math.trunc(foodCost * 2)
+		});
 	} else if (s.weight > 50) {
-		retval.push({text: "High weight", value: foodCost});
+		retval.push({
+			text: "High weight",
+			value: Math.trunc(foodCost)
+		});
 	} else if (s.weight < -50) {
-		retval.push({text: "Light weight, reduced by", value: -Math.abs(foodCost)});
+		retval.push({
+			text: "Light weight, reduced by",
+			value: -Math.abs(Math.trunc(foodCost))
+		});
 	}
 	if (s.geneticQuirks.fertility === 2 && s.geneticQuirks.hyperFertility === 2 && s.preg === 0 && (s.ovaries === 1 || s.mpreg === 1)) {
 		if (V.geneticMappingUpgrade >= 1) {
@@ -1254,7 +1275,10 @@ globalThis.getSlaveCostArray = function(s) {
 				value: Math.trunc(foodCost * 0.2)
 			});
 		} else {
-			retval.push({text: "Adjustment for unusual dietary deficiencies", value: Math.trunc(foodCost * 0.2)});
+			retval.push({
+				text: "Adjustment for unusual dietary deficiencies",
+				value: Math.trunc(foodCost * 0.2)
+			});
 		}
 	}
 	if (s.geneticQuirks.macromastia === 2) {
@@ -1264,7 +1288,10 @@ globalThis.getSlaveCostArray = function(s) {
 				value: Math.trunc(foodCost * 0.2)
 			});
 		} else {
-			retval.push({text: "Adjustment for unusual dietary deficiencies", value: Math.trunc(foodCost * 0.2)});
+			retval.push({
+				text: "Adjustment for unusual dietary deficiencies",
+				value: Math.trunc(foodCost * 0.2)
+			});
 		}
 	}
 	if (s.geneticQuirks.gigantomastia === 2) {
@@ -1274,7 +1301,10 @@ globalThis.getSlaveCostArray = function(s) {
 				value: Math.trunc(foodCost * 0.2)
 			});
 		} else {
-			retval.push({text: "Adjustment for unusual dietary deficiencies", value: Math.trunc(foodCost * 0.2)});
+			retval.push({
+				text: "Adjustment for unusual dietary deficiencies",
+				value: Math.trunc(foodCost * 0.2)
+			});
 		}
 	}
 	if (s.geneticQuirks.mGain === 2 && s.geneticQuirks.mLoss !== 2) {
@@ -1284,7 +1314,10 @@ globalThis.getSlaveCostArray = function(s) {
 				value: Math.trunc(foodCost * 0.2)
 			});
 		} else {
-			retval.push({text: "Adjustment for unusual dietary deficiencies", value: Math.trunc(foodCost * 0.2)});
+			retval.push({
+				text: "Adjustment for unusual dietary deficiencies",
+				value: Math.trunc(foodCost * 0.2)
+			});
 		}
 	}
 	if (s.geneticQuirks.wGain === 2 && s.geneticQuirks.wLoss !== 2) {
@@ -1294,11 +1327,17 @@ globalThis.getSlaveCostArray = function(s) {
 				value: Math.trunc(foodCost * 0.2)
 			});
 		} else {
-			retval.push({text: "Adjustment for unusual dietary deficiencies", value: Math.trunc(foodCost * 0.2)});
+			retval.push({
+				text: "Adjustment for unusual dietary deficiencies",
+				value: Math.trunc(foodCost * 0.2)
+			});
 		}
 	}
 	if (s.drugs === 'appetite suppressors') {
-		retval.push({text: "Food saved via suppressed appetite", value: -Math.abs(foodCost)});
+		retval.push({
+			text: "Food saved via suppressed appetite",
+			value: -Math.abs(Math.trunc(foodCost))
+		});
 	}
 	if (s.lactation > 0) {
 		t = "Food to support ";
@@ -1315,13 +1354,19 @@ globalThis.getSlaveCostArray = function(s) {
 		} else {
 			t += "reasonable breasts";
 		}
-		retval.push({text: t, value: foodCost * s.lactation * (1 + Math.trunc(s.boobs / 10000))});
+		retval.push({
+			text: t,
+			value: Math.trunc(foodCost * s.lactation * (1 + (s.boobs / 10000)))
+		});
 	}
 	if (s.preg > s.pregData.normalBirth / 8) {
 		if (s.assignment === Job.DAIRY && V.dairyFeedersSetting > 0) {
 			// Extra feeding costs to support pregnancy are covered by dairy feeders.
 			// TODO: Include them here anyway?
-			retval.push({text: "Extra feeding costs to support pregnancy are covered by dairy feeders", value: 0});
+			retval.push({
+				text: "Extra feeding costs to support pregnancy are covered by dairy feeders",
+				value: 0
+			});
 		} else if ((s.assignment === Job.MASTERSUITE || s.assignment === Job.CONCUBINE) &&
 			V.masterSuiteUpgradePregnancy === 1) {
 			// Extra feeding costs to support pregnancy are covered by master suite luxuries.
@@ -1338,28 +1383,28 @@ globalThis.getSlaveCostArray = function(s) {
 			t += "pregnancy";
 			retval.push({
 				text: t,
-				value: foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1)
+				value: Math.trunc(foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1))
 			});
 
 			if (s.pregType >= 100) {
 				retval.push({
 					text: "Specialized dietary requirements and feeding methods to support absurd multiples",
-					value: foodCost * 5 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1)
+					value: Math.trunc(foodCost * 5 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1))
 				});
 			} else if (s.pregType >= 50) {
 				retval.push({
 					text: "Specialized dietary adjustments and concentrated, quick to digest food required to support absurd multiples",
-					value: foodCost * 3 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1)
+					value: Math.trunc(foodCost * 3 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1))
 				});
 			} else if (s.pregType >= 30) {
 				retval.push({
 					text: "Concentrated, quick to digest food blend to support extreme multiples",
-					value: foodCost * 2 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1)
+					value: Math.trunc(foodCost * 2 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1))
 				});
 			} else if (s.pregType >= 10) {
 				retval.push({
 					text: "Specialized food blend to support multiples",
-					value: foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1)
+					value: Math.trunc(foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1))
 				});
 			}
 		}
diff --git a/src/js/extendedFamilyModeJS.js b/src/js/extendedFamilyModeJS.js
index f4a851b37513bddf73a80c6c489225a4a7b5eac4..b2f901ccd85c3c13ad36160bcc4a912607486adf 100644
--- a/src/js/extendedFamilyModeJS.js
+++ b/src/js/extendedFamilyModeJS.js
@@ -8,9 +8,33 @@
  * @property {number} father
  * @property {number} actualAge
  * @property {number} birthWeek
+ * @property {string} slaveName
+ * @property {FC.Zeroable<string>} slaveSurname
  * @property {string} genes
  */
 
+/** Given an ID, gets a relative entry that represents that ID, from wherever it may be
+ * @param {number} ID
+ * @returns {Relative}
+ */
+globalThis.getRelative = function(ID) {
+	// PC
+	if (ID === -1) {
+		return V.PC;
+	}
+	// active slave, child, or tank baby
+	const slave = findFather(ID);
+	if (slave) {
+		return slave;
+	}
+	// ex-slave
+	const genePool = V.genePool.find(s => s.ID === ID);
+	if (genePool) {
+		return genePool;
+	}
+	return null;
+};
+
 /** Returns true if mother is the mother of daughter
  * @param {Relative} daughter
  * @param {Relative} mother
@@ -44,10 +68,10 @@ globalThis.isParentP = function(daughter, parent) {
  * @returns {boolean}
  */
 globalThis.isGrandmotherP = function(granddaughter, grandmother) {
-	let father;
-	let mother;
-	return ((mother = getSlave(granddaughter.mother)) && (mother.mother === grandmother.ID)) ||
-		((father = getSlave(granddaughter.father)) && (father.mother === grandmother.ID));
+	const father = getRelative(granddaughter.father);
+	const mother = getRelative(granddaughter.mother);
+	return (mother && (mother.mother === grandmother.ID)) ||
+		(father && (father.mother === grandmother.ID));
 };
 
 /** Returns true if grandfather is the grandfather of granddaughter
@@ -56,10 +80,10 @@ globalThis.isGrandmotherP = function(granddaughter, grandmother) {
  * @returns {boolean}
  */
 globalThis.isGrandfatherP = function(granddaughter, grandfather) {
-	let father;
-	let mother;
-	return ((mother = getSlave(granddaughter.mother)) && (mother.father === grandfather.ID)) ||
-		((father = getSlave(granddaughter.father)) && (father.father === grandfather.ID));
+	const father = getRelative(granddaughter.father);
+	const mother = getRelative(granddaughter.mother);
+	return (mother && (mother.father === grandfather.ID)) ||
+		(father && (father.father === grandfather.ID));
 };
 
 /** Returns true if grandparent is the either the grandmother or grandfather of granddaughter
@@ -138,11 +162,11 @@ globalThis.isAunt = function(niece, aunt) {
 	if (!niece || !aunt || (niece.ID === aunt.ID)) {
 		return false;
 	}
-	let father;
-	let mother;
-	if ((mother = getSlave(niece.mother)) && (mother.ID !== aunt.ID) && !sameTParent(mother, aunt) && sameMom(mother, aunt) && sameDad(mother, aunt)) {
+	const father = getRelative(niece.father);
+	const mother = getRelative(niece.mother);
+	if (mother && (mother.ID !== aunt.ID) && !sameTParent(mother, aunt) && sameMom(mother, aunt) && sameDad(mother, aunt)) {
 		return true;
-	} else if ((father = getSlave(niece.father)) && (father.ID !== aunt.ID) && !sameTParent(father, aunt) && sameMom(father, aunt) && sameDad(father, aunt)) {
+	} else if (father && (father.ID !== aunt.ID) && !sameTParent(father, aunt) && sameMom(father, aunt) && sameDad(father, aunt)) {
 		return true;
 	}
 
@@ -206,10 +230,10 @@ globalThis.areCousins = function(slave1, slave2) {
 		return false;
 	}
 
-	const slave1Mom = getSlave(slave1.mother);
-	const slave1Dad = getSlave(slave1.father);
-	const slave2Mom = getSlave(slave2.mother);
-	const slave2Dad = getSlave(slave2.father);
+	const slave1Mom = getRelative(slave1.mother);
+	const slave1Dad = getRelative(slave1.father);
+	const slave2Mom = getRelative(slave2.mother);
+	const slave2Dad = getRelative(slave2.father);
 
 	if (slave1Mom && slave2Mom && !sameTParent(slave1Mom, slave2Mom) && sameMom(slave1Mom, slave2Mom) && sameDad(slave1Mom, slave2Mom)) {
 		return true;
diff --git a/src/js/familyTreeJS.js b/src/js/familyTreeJS.js
index f01bb34522c3af4727172925efb67e5232a77928..6ad834b0aa74cbe9fce5f2d104df64703b0b46e8 100644
--- a/src/js/familyTreeJS.js
+++ b/src/js/familyTreeJS.js
@@ -1,5 +1,4 @@
 /* eslint-disable camelcase */
-/* eslint-disable no-console */
 
 /**
  * @param {FC.HumanState[]} slaves
@@ -41,13 +40,7 @@ globalThis.renderFamilyTree = function(slaves, filterID) {
 
 	function runFtreeSim(data) {
 		let simulation = d3.forceSimulation()
-			.force('link', d3.forceLink().id(function(d) {
-				return d.index.toString();
-			}))
-			// eslint-disable-next-line no-unused-vars
-			.force('collide', d3.forceCollide(function(d) {
-				return 60;
-			}).iterations(4))
+			.force('collide', d3.forceCollide(60).iterations(4))
 			.force('charge', d3.forceManyBody().strength(-200).distanceMin(100).distanceMax(1000))
 			.force('center', d3.forceCenter(ftreeWidth / 2, ftreeHeight / 2))
 			.force('y', d3.forceY(100))
@@ -82,7 +75,6 @@ globalThis.renderFamilyTree = function(slaves, filterID) {
 				.on('end', dragended));
 
 		node.append('circle')
-			.attr('r', function(d) { return d.r; })
 			.attr('stroke', function(d) {
 				if (d.ID === filterID) {
 					return '#ffff20';
@@ -140,22 +132,21 @@ globalThis.renderFamilyTree = function(slaves, filterID) {
 		simulation.nodes(data.nodes)
 			.on('tick', ticked);
 
-		simulation.force('link')
-			.links(data.links);
+		simulation.force('link', d3.forceLink().links(data.links));
 
-		function dragstarted(d) {
-			if (!d3.event.active) { simulation.alphaTarget(0.3).restart(); }
+		function dragstarted(event, d) {
+			if (!event.active) { simulation.alphaTarget(0.3).restart(); }
 			d.fx = d.x;
 			d.fy = d.y;
 		}
 
-		function dragged(d) {
-			d.fx = d3.event.x;
-			d.fy = d3.event.y;
+		function dragged(event, d) {
+			d.fx = event.x;
+			d.fy = event.y;
 		}
 
-		function dragended(d) {
-			if (!d3.event.active) { simulation.alphaTarget(0); }
+		function dragended(event, d) {
+			if (!event.active) { simulation.alphaTarget(0); }
 			d.fx = null;
 			d.fy = null;
 		}
@@ -177,7 +168,9 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 		'-6': 'Social Elite',
 		'-7': 'Gene lab'
 	};
+	/** @type {Record<string, Array<string>>} */
 	let outdads = {};
+	/** @type {Record<string, Array<string>>} */
 	let outmoms = {};
 	let kids = {};
 
@@ -218,34 +211,31 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 		}
 	}
 
+	const haveChar = (ID) => charList.includes(c => c.ID === ID);
 	for (const character of charList) {
 		if (character.mother === 0 && character.father === 0 && !kids[character.ID]) {
 			continue;
 		}
 		let mom = character.mother;
 		if (mom < -6) {
-			if (mom in V.missingTable && V.showMissingSlaves) {
-				if (typeof node_lookup[mom] === 'undefined') {
-					node_lookup[mom] = family_graph.nodes.length;
-					let missing = V.missingTable[mom];
-					charList.push({
-						ID: mom,
-						mother: missing.mother,
-						father: missing.father,
-						is_mother: true,
-						dick: missing.dick,
-						vagina: missing.vagina,
-						slaveName: missing.slaveName
-					});
-				}
+			if (mom in V.missingTable && V.showMissingSlaves && !haveChar(mom)) {
+				const missing = V.missingTable[mom];
+				charList.push({
+					ID: mom,
+					mother: missing.mother,
+					father: missing.father,
+					is_mother: true,
+					dick: missing.dick,
+					vagina: missing.vagina,
+					slaveName: missing.slaveName
+				});
 			} else {
 				if (typeof outmoms[mom] === 'undefined') {
 					outmoms[mom] = [];
 				}
 				outmoms[mom].push(character.slaveName);
 			}
-		} else if (mom < 0 && typeof node_lookup[mom] === 'undefined' && typeof preset_lookup[mom] !== 'undefined') {
-			node_lookup[mom] = family_graph.nodes.length;
+		} else if (mom < 0 && typeof preset_lookup[mom] !== 'undefined' && !haveChar(mom)) {
 			charList.push({
 				ID: mom,
 				mother: 0,
@@ -259,28 +249,24 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 
 		let dad = character.father;
 		if (dad < -6) {
-			if (dad in V.missingTable && V.showMissingSlaves) {
-				if (typeof node_lookup[dad] === 'undefined') {
-					node_lookup[dad] = family_graph.nodes.length;
-					let missing = V.missingTable[dad];
-					charList.push({
-						ID: dad,
-						mother: missing.mother,
-						father: missing.father,
-						is_father: true,
-						dick: missing.dick,
-						vagina: missing.vagina,
-						slaveName: missing.slaveName
-					});
-				}
+			if (dad in V.missingTable && V.showMissingSlaves && !haveChar(dad)) {
+				const missing = V.missingTable[dad];
+				charList.push({
+					ID: dad,
+					mother: missing.mother,
+					father: missing.father,
+					is_father: true,
+					dick: missing.dick,
+					vagina: missing.vagina,
+					slaveName: missing.slaveName
+				});
 			} else {
 				if (typeof outdads[dad] === 'undefined') {
 					outdads[dad] = [];
 				}
 				outdads[dad].push(character.slaveName);
 			}
-		} else if (dad < 0 && typeof node_lookup[dad] === 'undefined' && typeof preset_lookup[dad] !== 'undefined') {
-			node_lookup[dad] = family_graph.nodes.length;
+		} else if (dad < 0 && typeof preset_lookup[dad] !== 'undefined' && !haveChar(dad)) {
 			charList.push({
 				ID: dad,
 				mother: 0,
@@ -304,7 +290,6 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 			names[-1] = `and ${names[-1]}`;
 			name = names.join(', ');
 		}
-		node_lookup[key] = family_graph.nodes.length;
 		// Outside extant slaves set
 		charList.push({
 			ID: key,
@@ -329,7 +314,6 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 			names[-1] = `and ${names[-1]}`;
 			name = names.join(', ');
 		}
-		node_lookup[key] = family_graph.nodes.length;
 		// Outside extant slaves set
 		charList.push({
 			ID: key,
@@ -433,12 +417,6 @@ globalThis.buildFamilyTree = function(slaves, filterID) {
 			continue;
 		}
 		if (filterID && !related[char_id]) {
-			if (related[character.mother]) {
-				console.log('wtf, mom');
-			}
-			if (related[character.father]) {
-				console.log('wtf, dad');
-			}
 			continue;
 		}
 		if (typeof node_lookup[character.mother] !== 'undefined') {
diff --git a/src/js/findSlave.js b/src/js/findSlave.js
index 4c8c602e040dc360f2ad8ff94939697d3bffd6ee..0ea81486149205b3e8188af6a8579e3bf748d764 100644
--- a/src/js/findSlave.js
+++ b/src/js/findSlave.js
@@ -71,9 +71,8 @@ App.UI.findSlave = function() {
 	 * @param {DocumentFragment} frag
 	 */
 	function _appendResultList(ids, frag) {
-		if (ids.length === 0) {
-			App.UI.DOM.appendNewElement("p", frag, "No matching slaves.");
-		} else {
+		App.UI.DOM.appendNewElement("p", frag, `${ids.length} matching slave${ids.length === 1 ? `` : `s`}.`);
+		if (ids.length !== 0) {
 			frag.appendChild(App.UI.SlaveList.render(ids, [], App.UI.SlaveList.SlaveInteract.stdInteract));
 		}
 	}
diff --git a/src/js/ibcJS.js b/src/js/ibcJS.js
index 7006c2d3368f50f2c6be0d203cc286660a7625ee..e7dde696f7298466afb896af1a0883916ed344ae 100644
--- a/src/js/ibcJS.js
+++ b/src/js/ibcJS.js
@@ -12,7 +12,6 @@
 // TODO: replace snake_case with camelCase
 
 /* eslint-disable camelcase */
-/* eslint-disable eqeqeq */
 globalThis.ibc = (() => {
 	let realWorld =
 	{
diff --git a/src/js/porn.js b/src/js/porn.js
index 5c17c90ecf81acc52b6ed672ed46fe0d8790a529..00e8db6235784f07a084778fdc0fb36c64cfd639 100644
--- a/src/js/porn.js
+++ b/src/js/porn.js
@@ -1,34 +1,38 @@
-App.Porn = {};
 App.Porn.GenreType = {
 	paraphilia: {
 		focusedViewershipFactor: 1.5,
 		unfocusedViewershipFactor: 0.5,
 		viewershipSoakingFactor: 0.0,
-		bonusViewership: function(slave) { return slave.fetishStrength * 2.0; }
+		bonusViewership: function(slave) { return slave.fetishStrength * 2.0; },
+		name: "paraphilia"
 	},
 	fetish: {
 		focusedViewershipFactor: 2.0,
 		unfocusedViewershipFactor: 0.5,
 		viewershipSoakingFactor: 1.0,
-		bonusViewership: function(slave) { return slave.fetishStrength; }
+		bonusViewership: function(slave) { return slave.fetishStrength; },
+		name: "fetish"
 	},
 	general: {
 		focusedViewershipFactor: 4.0,
 		unfocusedViewershipFactor: 0.5,
 		viewershipSoakingFactor: 1.0,
-		bonusViewership: function(slave) { return 0.0; }
+		bonusViewership: function(slave) { return 0.0; },
+		name: "general"
 	},
 	quirk: {
 		focusedViewershipFactor: 6.0,
 		unfocusedViewershipFactor: 0.5,
 		viewershipSoakingFactor: 1.0,
-		bonusViewership: function(slave) { return 0.0; }
+		bonusViewership: function(slave) { return 0.0; },
+		name: "quirk"
 	},
 	generic: {
 		focusedViewershipFactor: 5.0,
 		unfocusedViewershipFactor: 1.0,
 		viewershipSoakingFactor: 0.0,
-		bonusViewership: function(slave) { return 0.0; }
+		bonusViewership: function(slave) { return 0.0; },
+		name: "generic"
 	}
 };
 
diff --git a/src/js/pregJS.js b/src/js/pregJS.js
index b8c224087ab87f600a1563a632570cd7cc2430d7..c9ba9a273cb11360f03750097a47acfe2b5d0403 100644
--- a/src/js/pregJS.js
+++ b/src/js/pregJS.js
@@ -452,7 +452,8 @@ globalThis.getNurseryReserved = function( /* slaves */ ) {
 	return FetusGlobalReserveCount("nursery");
 };
 
-/** Find a slave's father, if they are also one of your slaves, wherever they may be
+/** Find a slave's by ID, if they are also one of your slaves, wherever they may be
+ * Note: not specific to fathers, though that's the most common use.
  * @param {number} fatherID
  * @returns {FC.HumanState}
  */
diff --git a/src/js/reminder.js b/src/js/reminder.js
index 719581a6c7434f8bd0134a6c26d71c862349ad93..595923d3a6df429fb23bdf014ef99d61b21ca14f 100644
--- a/src/js/reminder.js
+++ b/src/js/reminder.js
@@ -1,6 +1,9 @@
 App.Reminders = (function() {
-	const displayDiv = document.createElement("div");
-	const addDiv = document.createElement("div");
+	/**
+	 *  @type {Array<function():void>}
+	 */
+	let activeViewRefreshers = [];
+
 	return {
 		add: add,
 		list: list,
@@ -8,6 +11,7 @@ App.Reminders = (function() {
 		slaveDisplay: slaveDisplay,
 		slaveLink: slaveLink,
 		dialog: dialog,
+		clear: clearActive,
 	};
 
 	/**
@@ -15,10 +19,11 @@ App.Reminders = (function() {
 	 * @param {number} week
 	 * @param {string} [category]
 	 * @param {number} [slaveID]
+	 * @returns {boolean} Whether a reminder was actually added or we aborted.
 	 */
 	function add(message, week, category = "manual", slaveID = 0) {
 		if (message === "" || message === null) {
-			return;
+			return false;
 		}
 		const entry = {message: message, week: week, category: category};
 		if (slaveID) {
@@ -32,6 +37,7 @@ App.Reminders = (function() {
 		} else {
 			V.reminders.splice(index, 0, entry);
 		}
+		return true;
 	}
 
 	/**
@@ -52,28 +58,23 @@ App.Reminders = (function() {
 
 		const outerSpan = document.createElement("span");
 
-		function replace() {
-			App.UI.DOM.replace(outerSpan, list({maxFuture, filter, link}));
-			App.Utils.scheduleSidebarRefresh();
-		}
-
 		/**
 		 * @param {FC.ReminderEntry} entry
 		 */
 		function clearEntry(entry) {
 			V.reminders.splice(V.reminders.indexOf(entry), 1);
-			replace();
+			refreshActive();
 		}
 
 		// We only want to remove visible entries
 		function clearOverdue() {
 			V.reminders = V.reminders.filter(e => e.week >= V.week || e.week > V.week + maxFuture || !filter(e));
-			replace();
+			refreshActive();
 		}
 
 		function clearAll() {
 			V.reminders = V.reminders.filter(e => e.week > V.week + maxFuture || !filter(e));
-			replace();
+			refreshActive();
 		}
 
 		let overdue = 0;
@@ -126,25 +127,27 @@ App.Reminders = (function() {
 	}
 
 	/**
-	 * @param {function():void} refresh
 	 * @param {string} [category]
 	 * @param {number} [slaveID]
 	 * @returns {HTMLDivElement}
 	 */
-	function addField(refresh, category, slaveID) {
-		jQuery(addDiv).empty();
+	function addField(category, slaveID) {
+		const addDiv = document.createElement("div");
 
 		let entry = "";
 		let week = 0;
 
 		addDiv.append(
-			App.UI.DOM.makeTextBox("", v => { entry = v; }),
-			" in ", App.UI.DOM.makeTextBox(0, v => { week = v; }, true), " weeks.",
+			App.UI.DOM.makeTextBox("", v => {
+				entry = v;
+			}),
+			" in ", App.UI.DOM.makeTextBox(0, v => {
+				week = v;
+			}, true), " weeks.",
 			" ", App.UI.DOM.link("Add", () => {
-				add(entry, V.week + week, category, slaveID);
-				refresh();
-				App.Utils.scheduleSidebarRefresh();
-				jQuery(addDiv).append(addField(refresh, category, slaveID));
+				if (add(entry, V.week + week, category, slaveID)) {
+					refreshActive();
+				}
 			})
 		);
 
@@ -153,10 +156,22 @@ App.Reminders = (function() {
 
 	/**
 	 * @param {boolean} [link=false] show passage links
+	 * @param {HTMLElement} [displayDiv] Only to be used by the refresh functionality
 	 * @returns {HTMLElement}
 	 */
-	function fullDisplay(link) {
-		jQuery(displayDiv).empty();
+	function fullDisplay(link, displayDiv) {
+		if (displayDiv) {
+			// If displayDiv is given, it either is currently being shown or the tree it belonged to was removed from
+			// the page. In that case we don't need to refresh it ever again.
+			if (!displayDiv.isConnected) {
+				return null;
+			}
+			jQuery(displayDiv).empty();
+		} else {
+			displayDiv = document.createElement("div");
+		}
+		activeViewRefreshers.push(() => fullDisplay(link, displayDiv));
+
 		displayDiv.append(App.UI.DOM.makeElement("h2", "Reminders"));
 
 		const listEl = list({link});
@@ -165,17 +180,27 @@ App.Reminders = (function() {
 		}
 
 		displayDiv.append(App.UI.DOM.makeElement("h3", "Add new"));
-		displayDiv.append(App.UI.DOM.makeElement("p", addField(() => fullDisplay(link))));
+		displayDiv.append(App.UI.DOM.makeElement("p", addField()));
 
 		return displayDiv;
 	}
 
 	/**
 	 * @param {number} slaveID
+	 * @param {HTMLElement} [displayDiv] Only to be used by the refresh functionality
 	 * @returns {HTMLElement}
 	 */
-	function slaveDisplay(slaveID) {
-		jQuery(displayDiv).empty();
+	function slaveDisplay(slaveID, displayDiv) {
+		if (displayDiv) {
+			if (!displayDiv.isConnected) {
+				return null;
+			}
+			jQuery(displayDiv).empty();
+		} else {
+			displayDiv = document.createElement("div");
+		}
+		activeViewRefreshers.push(() => slaveDisplay(slaveID, displayDiv));
+
 		displayDiv.append(App.UI.DOM.makeElement("h2", `Reminders for ${SlaveFullName(getSlave(slaveID))}`));
 
 		const listEl = list({filter: e => e.slaveID === slaveID});
@@ -184,7 +209,7 @@ App.Reminders = (function() {
 		}
 
 		displayDiv.append(App.UI.DOM.makeElement("h3", "Add new"));
-		displayDiv.append(App.UI.DOM.makeElement("p", addField(() => slaveDisplay(slaveID), "slave", slaveID)));
+		displayDiv.append(App.UI.DOM.makeElement("p", addField("slave", slaveID)));
 
 		return displayDiv;
 	}
@@ -211,4 +236,18 @@ App.Reminders = (function() {
 		$(Dialog.body()).empty().append(slaveID ? slaveDisplay(slaveID) : fullDisplay(showLinks));
 		Dialog.open();
 	}
+
+	function refreshActive() {
+		console.log(activeViewRefreshers.length);
+		const ars = activeViewRefreshers;
+		activeViewRefreshers = [];
+		for (const refresher of ars) {
+			refresher();
+		}
+		App.Utils.scheduleSidebarRefresh();
+	}
+
+	function clearActive() {
+		activeViewRefreshers = [];
+	}
 })();
diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index 418306d23c7d3c34f6bd07c918b3e0b5309e05e1..29e230629bde8a2ff769e3ebd18f746b502fe6a6 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -179,7 +179,7 @@ App.RA.newRule = function() {
 	function emptyConditions() {
 		return {
 			activation: ["devotion", 20, "gt", 1, "and"],
-			advancedMode: false,
+			advancedMode: V.raDefaultMode === 1,
 			selectedSlaves: [],
 			excludedSlaves: [],
 			applyRuleOnce: false,
diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js
index ebc47642f3788a91202122c1cd5244b7f69d6fca..261fe8c59d0676310191a168179182bc4cecb745 100644
--- a/src/js/rulesAssistantOptions.js
+++ b/src/js/rulesAssistantOptions.js
@@ -87,11 +87,22 @@ App.RA.options = (function() {
 	}
 
 	function changeName(name) {
-		if (name === current_rule.name) { return; }
+		if (name === current_rule.name) {
+			return;
+		}
 		current_rule.name = name;
 		reload();
 	}
 
+	function duplicate() {
+		const clonedRule = _.cloneDeep(current_rule);
+		clonedRule.ID = generateNewID();
+		clonedRule.name = `Copy of ${clonedRule.name}`;
+		V.currentRule = clonedRule.ID;
+		V.defaultRules.push(clonedRule);
+		reload();
+	}
+
 	// reload the passage
 	function reload() {
 		saveSettings();
@@ -105,7 +116,9 @@ App.RA.options = (function() {
 	 * Save the settings for this rule.
 	 */
 	function saveSettings() {
-		App.RA.Activation.Editor.save(current_rule.condition);
+		if (current_rule) {
+			App.RA.Activation.Editor.save(current_rule.condition);
+		}
 	}
 
 	const parse = {
@@ -1157,9 +1170,11 @@ App.RA.options = (function() {
 				const rule = JSON.parse(text);
 				if (Array.isArray(rule)) {
 					rule.forEach(r => {
+						r.ID = generateNewID();
 						V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(r));
 					});
 				} else {
+					rule.ID = generateNewID();
 					V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(rule));
 				}
 				reload();
@@ -1240,6 +1255,7 @@ App.RA.options = (function() {
 			this.appendChild(new OptionsItem("Lower Priority", lowerPriority));
 			this.appendChild(new OptionsItem("Higher Priority", higherPriority));
 			this.appendChild(new OptionsItem("Rename", rename(this)));
+			this.appendChild(new OptionsItem("Duplicate", duplicate));
 			this.appendChild(new OptionsItem("Export this rule", () => this.appendChild(new ExportField(current_rule))));
 			this.appendChild(new OptionsItem("Export all rules", () => this.appendChild(new ExportField(...V.defaultRules))));
 			this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField())));
diff --git a/src/js/slaveCostJS.js b/src/js/slaveCostJS.js
index 1089677ef83d603dce14b49177b53408cbabb516..41f0b0c3f6c213ad205744d231876d85b08b1dfd 100644
--- a/src/js/slaveCostJS.js
+++ b/src/js/slaveCostJS.js
@@ -2208,7 +2208,7 @@ globalThis.FResult = function(s, forSale = 0) {
 /** Show an itemized breakdown of the sexual value (FResult) of the slave
  * @param {App.Entity.SlaveState} slave
  * @param {number} [forSale=0] set to 1 to ignore co-assignment and other temporary factors
- * @returns {Node}
+ * @returns {HTMLElement}
  */
 globalThis.FResultTooltip = function(slave, forSale = 0) {
 	// Make a link. Text should be slave's FResult. Clicking the link will display detailed info about that FResult over the top of the page (tooltip-style)
diff --git a/src/js/slaveListing.js b/src/js/slaveListing.js
index 5a55eda35ff251ba7f1cb22eb9b8e424051080b9..2b9f0d6edbf69f7f6a48c216663d8d3ece669e7d 100644
--- a/src/js/slaveListing.js
+++ b/src/js/slaveListing.js
@@ -179,6 +179,9 @@ App.UI.SlaveList.render = function() {
 			if (slave.health.shortDamage >= 10) {
 				list.push(`injuries`);
 			}
+			if (slave.health.illness > 0) {
+				list.push(`illness`);
+			}
 			if (S.Nurse) {
 				if ((slave.chem > 15) && (V.clinicUpgradeFilters === 1)) {
 					list.push(`unhealthy chemicals`);
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index f3c182311cd883239f53ab569cef37587c75e1e4..9553289f1a2717bf223c1545a7cfc8961656d7e2 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -923,6 +923,8 @@ globalThis.isHindered = function(slave) {
 			return true;
 		} else if (slave.physicalImpairment !== 0) {
 			return true;
+		// } else if (slave.energy > 95 || slave.need > 0) {
+		//	return true;
 		}
 	}
 	return false;
@@ -1065,11 +1067,11 @@ globalThis.tooBigBalls = function(slave) {
 globalThis.tooBigDick = function(slave) {
 	if (!slave) {
 		return null;
-	} else if (slave.dick >= 20 + (slave.muscles * 0.1) && slave.physicalAge <= 3 && slave.dick !== 0) {
+	} else if (slave.dick >= 20 + (slave.muscles * 0.1) && slave.physicalAge <= 3 && slave.dick !== 0) { // 10 - 30
 		return true;
-	} else if (slave.dick >= 45 + (slave.muscles * 0.3) && slave.physicalAge <= 12) {
+	} else if (slave.dick >= 45 + (slave.muscles * 0.3) && slave.physicalAge <= 12) { // 15 - 75
 		return true;
-	} else if (slave.dick >= 68 + (slave.muscles * 0.4)) {
+	} else if (slave.dick >= 68 + (slave.muscles * 0.4)) { // 28 - 108
 		return true;
 	}
 	return false;
@@ -1086,6 +1088,8 @@ globalThis.tooBigButt = function(slave) {
 		return true;
 	} else if (slave.butt > 14 && slave.physicalAge <= 12) {
 		return true;
+	} else if (slave.butt > 22) {
+		return true;
 	}
 	return false;
 };
@@ -1156,7 +1160,7 @@ globalThis.milkFlavor = function(slave) {
 	if (slave.milkFlavor === "none") {
 		return ``;
 	}
-	return `${slave.milkFlavor} flavored `;
+	return `${slave.milkFlavor}-flavored `;
 };
 
 globalThis.canBeDeflowered = function(slave) {
diff --git a/src/js/utilsPC.js b/src/js/utilsPC.js
index 8b07f63737a90bf554d3a1b3899b87b9d9ebfba2..66bbead3a8e4a104e7fe0b30bfe1a139a9f7e9e9 100644
--- a/src/js/utilsPC.js
+++ b/src/js/utilsPC.js
@@ -629,7 +629,7 @@ globalThis.onBedRest = function(actor, workingFromBed = false) {
 	// consider player injuries in the future!
 	if (!actor) {
 		return null;
-	} else if (actor.health.shortDamage >= 50) {
+	} else if (actor.majorInjury > 0) {
 		return true;
 	} else if (actor.health.condition < -90) {
 		return true;
@@ -637,7 +637,7 @@ globalThis.onBedRest = function(actor, workingFromBed = false) {
 		return true;
 	} else if (isTrapped(actor) && !workingFromBed) {
 		return true;
-	} else if (actor.preg > actor.pregData.normalBirth / 1.05) { // consider birth delayers and how they play into this
+	} else if (actor.preg > actor.pregData.normalBirth / 1.05 && actor.pregControl !== "labor suppressors") { // consider if the player should be able to ignore contractions
 		return true;
 	} else if (actor.womb.find((ft) => ft.genetics.geneticQuirks.polyhydramnios === 2 && ft.age >= 20) && !workingFromBed) {
 		return true;
@@ -651,21 +651,277 @@ globalThis.onBedRest = function(actor, workingFromBed = false) {
 
 /** Returns if the player is able to move via wheelchair.
  * Consider moving this to encompass slaves in the future.
+ * Ridiculously far future proofing.
  * @param {App.Entity.PlayerState} actor
  * @returns {boolean}
  */
 globalThis.isMovable = function(actor) {
+	if (!actor) {
+		return null;
+	} else if (canMove(actor)) {
+		return true;
+	} else if (actor.boobs >= 1500000) {
+		return false;
+	} else if (actor.balls >= 160) {
+		return false;
+	} else if (actor.belly >= 1100000) {
+		return false;
+	} else if (actor.weight >= 300) {
+		return false;
+	}
 	return true;
 };
 
 /** Returns if the player has grown so large they no longer can leave their bedroom.
+ * Slaves can force their way. (add health drop for this!)
  * @param {App.Entity.PlayerState} actor
  * @returns {boolean}
  */
 globalThis.isTrapped = function(actor) {
+	if (!actor) {
+		return null;
+	} else if (V.buttAccessibility === 1 || V.pregAccessibility === 1 || V.ballsAccessibility === 1 || V.boobAccessibility === 1) {
+		return false;
+	} else if (actor.boobsImplant >= 600000 || actor.boobs >= 1000000) {
+		return true;
+	} else if (actor.belly >= 800000) {
+		return true;
+	} else if (actor.dick >= 100) {
+		return true;
+	} else if (actor.balls >= 100) {
+		return true;
+	} else if (actor.buttImplant >= 30) {
+		return true;
+	}
 	return false;
 };
 
+/** How badly hindered is the player? Stacks from various sources up until a 75% reduction in your ability to do business.
+ * You have to seriously try to fuck yourself up that badly; just stacking basic hindrances will only get you to 50%.
+ * This probably still needs more adjustments.
+ * @param {FC.HumanState} actor
+ * @param {boolean} sexyTime
+ * @returns {number}
+ */
+globalThis.isHinderedDegree = function(actor, sexyTime = false) {
+	let mult = 1;
+	const averageHeight = Height.mean(actor);
+	const estimatedSackSag = ballsToCM(actor.balls) * .8 * (1 + ((actor.scrotum - actor.balls) * .5));
+	// player exclusives
+	actor = asPlayer(actor);
+	if (!actor) {
+		return mult;
+	}
+	// PC on bedrest plans to work from home.
+	if (onBedRest(actor)) {
+		return .5;
+	} else if (actor.physicalImpairment !== 0) {
+		mult -= .3;
+	// } else if (actor.energy > 95 || actor.need > 0) {
+	//	return true;
+	}
+	// not really worrying about this for now
+	if (!isQuadrupedal(actor) && hasAnyQuadrupedLegs(actor)) {
+		mult -= .2;
+	} else if (hasBothQuadrupedLegs(actor) && !hasBothQuadrupedArms(actor)) {
+		mult -= .1;
+	} else if (!hasBothQuadrupedLegs(actor) && hasAnyQuadrupedLegs(actor) && !hasBothQuadrupedArms(actor) && hasAnyQuadrupedArms(actor)) {
+		mult -= .3;
+	}
+	// Not having to walk drastically affects how much assets are a hindrance
+	if (!canWalk(actor)) {
+		mult -= .1; // Of course, not being able to walk is also a hindrance
+		if (actor.belly >= 60000 || actor.belly >= 60000 / (1 + Math.pow(Math.E, -0.4 * (actor.physicalAge - 14))) || actor.belly >= Math.max(10000, ((12500 / 19) * actor.height) - (1172500 / 19))) {
+			mult -= .1;
+		}
+		if (V.pregAccessibility === 1) {
+			if (actor.belly >= 1000000) {
+				mult -= .1;
+			} else if (actor.belly >= 500000) {
+				mult -= .05;
+			}
+		} else {
+			if (actor.belly >= 1000000) {
+				mult -= .25;
+			} else if (actor.belly >= 750000) {
+				mult -= .2;
+			} else if (actor.belly >= 500000) {
+				mult -= .15;
+			} else if (actor.belly >= 250000) {
+				mult -= .1;
+			} else if (actor.belly >= 100000) {
+				mult -= .05;
+			}
+		}
+		// Assets do not hinder prostitutes
+		if (!sexyTime) {
+			if (actor.muscles > 95 && actor.height <= (averageHeight + 10)) {
+				mult -= .05;
+			} else if (actor.muscles < -95) {
+				mult -= .3;
+			} else if (actor.muscles < -60) {
+				mult -= .1;
+			} else if (actor.muscles < -30) {
+				mult -= .05;
+			}
+			if (actor.weight >= 190) {
+				mult -= .05;
+			}
+			if (actor.boobs > 5000) {
+				mult -= .1;
+			}
+			if (V.boobAccessibility === 1) {
+				if (actor.boobs > 75000) {
+					mult -= .1;
+				}
+			} else {
+				if (actor.boobs > 75000) {
+					mult -= .2;
+				} else if (actor.boobs > 50000) {
+					mult -= .15;
+				} else if (actor.boobs > 25000) {
+					mult -= .1;
+				}
+			}
+			if (actor.balls >= 14) {
+				mult -= .1;
+			}
+			if (V.ballsAccessibility === 1) {
+				if (estimatedSackSag > (actor.height / 2)) {
+					mult -= .05;
+				}
+			} else {
+				if (estimatedSackSag > (actor.height / 2)) {
+					mult -= .1;
+				}
+			}
+			if (actor.hips > 2) {
+				mult -= .1;
+			}
+			if (actor.butt > 6) {
+				mult -= .1;
+			}
+			if (V.buttAccessibility === 1) {
+				if (actor.butt > 15) {
+					mult -= .05;
+				}
+			} else {
+				if (actor.butt > 15) {
+					mult -= .1;
+				}
+			}
+		}
+	} else {
+		if (actor.belly >= 60000 || actor.belly >= 60000 / (1 + Math.pow(Math.E, -0.4 * (actor.physicalAge - 14))) || actor.belly >= Math.max(10000, ((12500 / 19) * actor.height) - (1172500 / 19))) {
+			mult -= .1;
+		}
+		if (V.pregAccessibility === 1) {
+			if (actor.belly >= 1000000) {
+				mult -= .2;
+			} else if (actor.belly >= 500000) {
+				mult -= .1;
+			}
+		} else {
+			if (actor.belly >= 1000000) {
+				mult -= .5;
+			} else if (actor.belly >= 750000) {
+				mult -= .4;
+			} else if (actor.belly >= 500000) {
+				mult -= .3;
+			} else if (actor.belly >= 250000) {
+				mult -= .2;
+			} else if (actor.belly >= 100000) {
+				mult -= .1;
+			}
+		}
+		// Assets do not hinder prostitutes
+		if (!sexyTime) {
+			if (actor.muscles > 95 && actor.height <= (averageHeight + 10)) {
+				mult -= .1;
+			} else if (actor.muscles < -95) {
+				mult -= .7;
+			} else if (actor.muscles < -60) {
+				mult -= .5;
+			} else if (actor.muscles < -30) {
+				mult -= .2;
+			}
+			if (actor.weight >= 130 || (actor.weight >= 95 + ((actor.physicalAge - 9) * 5))) {
+				mult -= .1;
+			}
+			if (actor.boobs > 5000) {
+				mult -= .1;
+			}
+			if (V.boobAccessibility === 1) {
+				if (actor.boobs > 75000) {
+					mult -= .15;
+				} else if (actor.boobs > 50000) {
+					mult -= .1;
+				}
+			} else {
+				if (actor.boobs > 75000) {
+					mult -= .6;
+				} else if (actor.boobs > 50000) {
+					mult -= .4;
+				} else if (actor.boobs > 25000) {
+					mult -= .2;
+				} else if (actor.boobs > 10000) {
+					mult -= .1;
+				}
+			}
+			if (actor.balls >= 14) {
+				mult -= .1;
+			}
+			if (V.ballsAccessibility === 1) {
+				if (estimatedSackSag > (actor.height / 2)) {
+					mult -= .15;
+				} else if (estimatedSackSag >= (actor.height / 2) - 10) {
+					mult -= .1;
+				} else if (estimatedSackSag >= (actor.height / 4)) {
+					mult -= .05;
+				}
+			} else {
+				if (estimatedSackSag > (actor.height / 2)) {
+					mult -= .2;
+				} else if (estimatedSackSag >= (actor.height / 2) - 10) {
+					mult -= .15;
+				} else if (estimatedSackSag >= (actor.height / 4)) {
+					mult -= .1;
+				}
+			}
+			if (actor.hips > 2) {
+				mult -= .1;
+			}
+			if (actor.butt > 6) {
+				mult -= .1;
+			}
+			if (V.buttAccessibility === 1) {
+				if (actor.butt > 15) {
+					mult -= .1;
+				}
+			} else {
+				if (actor.butt > 15) {
+					mult -= .2;
+				} else if (actor.butt > 10) {
+					mult -= .1;
+				}
+			}
+		}
+	}
+	if (sexyTime) { // But they do get tired
+		if (actor.muscles < -95) {
+			mult -= .7;
+		} else if (actor.muscles < -60) {
+			mult -= .3;
+		} else if (actor.muscles < -30) {
+			mult -= .1;
+		}
+		if (actor.weight >= 130 || (actor.weight >= 95 + ((actor.physicalAge - 9) * 5))) {
+			mult -= .2;
+		}
+	}
+	return Math.max(.25, mult);
+};
+
 /** Returns if the player can eat solid food.
  * Consider moving this to encompass slaves in the future.
  * @param {App.Entity.PlayerState} actor
@@ -684,6 +940,26 @@ globalThis.canEatFood = function(actor) {
 	return true;
 };
 
+/**
+ * A consolidated function for checking if the player is currently aroused.
+ * @param {App.Entity.PlayerState} actor
+ * @returns {boolean}
+ */
+globalThis.isPlayerHorny = function(actor) {
+	return ((actor.prostate > 0 && actor.preg > 0 && actor.preg > actor.pregData.normalBirth * .75) ||
+		(actor.preg > 0 && actor.preg > actor.pregData.normalBirth * .66 && actor.pregMood === 2) ||
+		(actor.geneticQuirks.uterineHypersensitivity === 2 &&
+			(actor.bellyPreg >= 10000) ||
+			(actor.belly > (actor.pregAdaptation * 1000)) ||
+			(actor.wombImplant === "restraint" && actor.belly >= 400000)
+		) ||
+		(actor.need > 0) ||
+		(actor.energy > 95) ||
+		(actor.aphrodisiacs > 0) ||
+		(actor.inflationType === "aphrodisiac") ||
+		(actor.drugs === "priapism agents"));
+};
+
 /**
  * Param takes "classic" PC careers, and then function checks data to see if PC has that classic career or a 4.0 equivalent.
  * @param {"wealth"|"escort"|"servant"|"gang"|"BlackHat"|"capitalist"|"mercenary"|"engineer"|"medicine"|"slaver"|"celebrity"|"arcology owner"} category
diff --git a/src/js/utilsSC.js b/src/js/utilsSC.js
index f739adf7f10abd022dccb65d289ed3052e195f97..50d065794dd5d51479e8c8617f2edff5019e251f 100644
--- a/src/js/utilsSC.js
+++ b/src/js/utilsSC.js
@@ -253,7 +253,8 @@ App.UI.DOM.referenceSlaveWithPreview = function(slave, text) {
 			App.UI.DOM.slaveDescriptionDialog(slave, "Pop-up", {noArt: true}),
 			App.UI.SlaveList.SlaveInteract.stdInteract(slave, "Go to")
 		]),
-		interactive: true
+		interactive: true,
+		appendTo: document.getElementById("story")
 	});
 	return res;
 };
diff --git a/src/neighbor/neighborInteract.js b/src/neighbor/neighborInteract.js
index 1e0d86eab240e66dde8168991abcb937358a81c3..c5d724a3c4f3e88304149f8efa2097f7e750a096 100644
--- a/src/neighbor/neighborInteract.js
+++ b/src/neighbor/neighborInteract.js
@@ -208,7 +208,7 @@ App.Neighbor.Interact = function() {
 					}
 					const div = App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.generateLinksStrip(links));
 					if (links.length > 1) {
-						App.UI.DOM.appendNewElement("span", div, " Transaction costs will only be paid once.", "detail");
+						App.UI.DOM.appendNewElement("span", div, " Transaction costs will only be paid once.", ["detail"]);
 					}
 				}
 
@@ -426,7 +426,7 @@ App.Neighbor.Interact = function() {
 								replaceDetails(arcID);
 							});
 							const div = App.UI.DOM.appendNewElement("div", container, link);
-							App.UI.DOM.appendNewElement("span", div, `Will cost ${cashFormat(itemPrice)}`, "detail");
+							App.UI.DOM.appendNewElement("span", div, `Will cost ${cashFormat(itemPrice)}`, ["detail"]);
 						}
 					} else {
 						App.UI.DOM.appendNewElement("div", container, `You already have enough ${itemDisplay}.`);
diff --git a/src/npc/children/longChildDescription.js b/src/npc/children/longChildDescription.js
index f2b5251aad2f4f932f7c8ae6a02ab0c65be160c7..424b9917ece1c237196580e2075c81c84b721aca 100644
--- a/src/npc/children/longChildDescription.js
+++ b/src/npc/children/longChildDescription.js
@@ -7227,7 +7227,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 	r += App.Desc.brand(child, "ear");
 	r += App.Desc.brand(child, "neck");
 
-	r += App.Desc.family(child) + " ";
+	// r += App.Desc.family(child) + " "; TODO Assemble DOM instead of string to make this work again
 
 	if (child.relationship >= 3 && totalRelatives(child) > 0) {
 		const lover = getSlave(child.relationshipTarget);
diff --git a/src/npc/descriptions/belly/belly.js b/src/npc/descriptions/belly/belly.js
index 7c92fa5bdfe002cdc17d44fe8acc30934c27c216..17f1623facbdd379c77f6c68e9438e36258d9e7a 100644
--- a/src/npc/descriptions/belly/belly.js
+++ b/src/npc/descriptions/belly/belly.js
@@ -10474,7 +10474,7 @@ App.Desc.belly = function(slave, descType = DescType.NORMAL) {
 						} else if (slave.bellyImplant > 0) {
 							r.push(`${slave.slaveName}'s implant-filled belly is so titanic that most of ${his} string bikini is completely eclipsed by its immense bulk.`);
 						} else {
-							r.push(`${slave.slaveName}'s pregnant belly is so titanic that most of ${his} string bikini is completely eclipsed by the life stuffed mass.`);
+							r.push(`${slave.slaveName}'s pregnant belly is so titanic that most of ${his} string bikini is completely eclipsed by the life-stuffed mass.`);
 						}
 					} else if (slave.belly >= 450000) {
 						if (isBellyFluidLargest) {
@@ -10482,7 +10482,7 @@ App.Desc.belly = function(slave, descType = DescType.NORMAL) {
 						} else if (slave.bellyImplant > 0) {
 							r.push(`${slave.slaveName}'s implant-filled belly is so gigantic that most of ${his} string bikini is completely eclipsed by its bulk.`);
 						} else {
-							r.push(`${slave.slaveName}'s pregnant belly is so gigantic that most of ${his} string bikini is completely eclipsed by the life filled mass.`);
+							r.push(`${slave.slaveName}'s pregnant belly is so gigantic that most of ${his} string bikini is completely eclipsed by the life-filled mass.`);
 						}
 					} else if (slave.belly >= 300000) {
 						if (isBellyFluidLargest) {
diff --git a/src/npc/descriptions/boobs/boobs.js b/src/npc/descriptions/boobs/boobs.js
index 9273af614183a4524cee43674afd624fd45b9967..d3bfd0c6ae49629f7fab64667bf9c606fda71fa7 100644
--- a/src/npc/descriptions/boobs/boobs.js
+++ b/src/npc/descriptions/boobs/boobs.js
@@ -1688,7 +1688,7 @@ App.Desc.nipples = function(slave, descType) {
 					}
 					break;
 				case "fuckable":
-					r += `swollen shut and leaking ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk.`;
+					r += `swollen shut and leaking ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk.`;
 					break;
 				default:
 					r += 'stiffly erect.';
@@ -1784,19 +1784,19 @@ App.Desc.nipples = function(slave, descType) {
 
 	if (slave.lactation > 0) {
 		if ((slave.assignment === App.Data.Facilities.dairy.jobs.cow.assignment) && (V.dairyRestraintsSetting > 1)) {
-			r += ` The transparent lines coming off the cups attached to each of ${his} nipples are white with a constant stream of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk.`;
+			r += ` The transparent lines coming off the cups attached to each of ${his} nipples are white with a constant stream of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk.`;
 		} else if (slave.lactation === 1) {
 			if (slave.boobs > 300) {
 				if (slave.boobsMilk > 0) {
-					r += ` ${His} breasts are painfully engorged with ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk.`;
+					r += ` ${His} breasts are painfully engorged with ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk.`;
 				} else {
-					r += ` ${His} motherly breasts are full of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk.`;
+					r += ` ${His} motherly breasts are full of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk.`;
 				}
 			} else {
 				if (slave.boobsMilk > 0) {
 					r += ` ${His} chest is painfully engorged with ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} `}milk and leaks with the slightest provocation.`;
 				} else {
-					r += ` ${His} sensitive chest is swollen with ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk.`;
+					r += ` ${His} sensitive chest is swollen with ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk.`;
 				}
 			}
 		} else if (slave.fuckdoll > 0) {
@@ -1807,9 +1807,9 @@ App.Desc.nipples = function(slave, descType) {
 			} else if (slave.nipples === "inverted") {
 				r += ` ${His} inverted nipples prevent ${him} from releasing milk spontaneously. The lactation drugs are so powerful that if ${he} hasn't been milked in the past hour or so, the built-up pressure leaves ${him} ${!canTalk(slave) ? 'weeping' : 'whining'} piteously.`;
 			} else if (slave.energy > 95) {
-				r += ` The powerful lactation drugs keep ${his} breasts so full of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor} flavored `}milk that when ${he} orgasms ${slave.balls > 0 ? `${he} releases three jets of white fluid: a stream of milk from each nipple and a squirt of cum from ${his} dickhead` : `${he} cums milk out of ${his} nipples`}.`;
+				r += ` The powerful lactation drugs keep ${his} breasts so full of ${slave.milkFlavor === "none" ? `` : `${slave.milkFlavor}-flavored `}milk that when ${he} orgasms ${slave.balls > 0 ? `${he} releases three jets of white fluid: a stream of milk from each nipple and a squirt of cum from ${his} dickhead` : `${he} cums milk out of ${his} nipples`}.`;
 			} else {
-				r += ` The lactation drugs are so powerful that if ${he} hasn't been milked in the past hour or so, ${he} leaves ${slave.milkFlavor === "none" ? `a milky mess` : `a mess of ${slave.milkFlavor} flavored milk`} wherever ${he} goes.`;
+				r += ` The lactation drugs are so powerful that if ${he} hasn't been milked in the past hour or so, ${he} leaves ${slave.milkFlavor === "none" ? `a milky mess` : `a mess of ${slave.milkFlavor}-flavored milk`} wherever ${he} goes.`;
 			}
 		}
 		if (slave.lactationAdaptation > 10) {
diff --git a/src/npc/descriptions/career.js b/src/npc/descriptions/career.js
index 10bad3191c3110ff96f8f46fd2de91b5c5409db4..3a5484431ba439d27586c2671d1f6fbaed1c4c68 100644
--- a/src/npc/descriptions/career.js
+++ b/src/npc/descriptions/career.js
@@ -109,7 +109,7 @@ App.Desc.career = function(slave) {
 			} else if (App.Data.Careers.General.grateful.includes(slave.career)) {
 				r.push(`${career}, so ${he} can remember what it's like`);
 				if (slave.career === "prisoner") {
-					r.push(`no one looking out for you.`);
+					r.push(`with no one looking out for you.`);
 				} else {
 					r.push(`to have the freedom to starve.`);
 				}
diff --git a/src/npc/descriptions/descriptionWidgets.js b/src/npc/descriptions/descriptionWidgets.js
index f137577b74691cd35006d4a6d480a4caee0f3398..fcd40ab23a3d350b22136f3a35ed843ad86a04db 100644
--- a/src/npc/descriptions/descriptionWidgets.js
+++ b/src/npc/descriptions/descriptionWidgets.js
@@ -587,7 +587,7 @@ App.Desc.ageAndHealth = function(slave) {
 		}
 
 		if (slave.actualAge !== slave.physicalAge) {
-			r += ` However, ${he} has the body of a ${num(slave.physicalAge)}-year-old; `;
+			r += ` However, ${he} has the body of a person ${num(slave.physicalAge)} years old; `;
 			if (slave.geneticQuirks.progeria === 2 && slave.physicalAge > slave.actualAge && (V.geneticMappingUpgrade >= 1 || (slave.physicalAge >= slave.actualAge + 20 && slave.tankBaby === 0))) {
 				if (V.geneticMappingUpgrade >= 1) {
 					r += `not at all surprising, given ${his} genetic condition. `;
@@ -1610,7 +1610,7 @@ App.Desc.geneticQuirkAssessment = function(slave) {
 			} else if (slave.dick > 0) {
 				r.push(`${He} is predisposed to having an enormous dick, though it is unlikely to naturally grow any larger than it currently is.`);
 			} else {
-				r.push(`${He} is predisposed to having an enormous dick, or would, if ${he} had one.`);
+				r.push(`${He} is predisposed to having an enormous dick, or would be, if ${he} had one.`);
 			}
 		} else if (slave.geneticQuirks.wellHung === 1 && V.geneticMappingUpgrade >= 2) {
 			r.push(`${He} is a carrier of a gene that causes enhanced penile development.`);
diff --git a/src/npc/descriptions/limbs.js b/src/npc/descriptions/limbs.js
index 7b38f1e61c4ca34a1dcdc8a0ccfa3ab6762062d6..e35ec86d77acd0f2d91d6babdfd350a15218edef 100644
--- a/src/npc/descriptions/limbs.js
+++ b/src/npc/descriptions/limbs.js
@@ -40,10 +40,10 @@ App.Medicine.Limbs.currentLimbs = function(slave) {
 App.Medicine.Limbs.selector = function(slave, oldLimbs) {
 	const {her} = getPronouns(slave);
 	if (hasAllNaturalLimbs(slave)) {
-		return App.UI.DOM.makeElement("span", `You must amputate ${her} limbs before you can attach prosthetics.`, "detail");
+		return App.UI.DOM.makeElement("span", `You must amputate ${her} limbs before you can attach prosthetics.`, ["detail"]);
 	}
 	if (slave.PLimb < 1) {
-		return App.UI.DOM.makeElement("span", `You must surgically install a prosthetic interface before you can attach prosthetics.`, "detail");
+		return App.UI.DOM.makeElement("span", `You must surgically install a prosthetic interface before you can attach prosthetics.`, ["detail"]);
 	}
 
 	const {his} = getPronouns(slave);
diff --git a/src/npc/descriptions/longSlave.js b/src/npc/descriptions/longSlave.js
index 54a21173c5b1e7afe485d512a7dcee9bd5ff9197..0c63788f5b2ddc79743bad0a8ced3b49f525cc57 100644
--- a/src/npc/descriptions/longSlave.js
+++ b/src/npc/descriptions/longSlave.js
@@ -3,15 +3,13 @@
  * @param {FC.Desc.LongSlaveOptions} params
  * @returns {DocumentFragment}
  */
-App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} = {}) {
+App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt, links} = {}) {
 	const {
 		He, His, him, he, his
 	} = getPronouns(slave);
 	let el = new DocumentFragment();
 	let span;
-	let frag;
-	let p;
-	let r;
+	let r = new SpacedTextAccumulator();
 	SlaveStatClamp(slave);
 
 	descType = descType || (market ? DescType.MARKET : DescType.NORMAL);
@@ -22,127 +20,111 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	p = document.createElement("p");
 
 	// Name
-	App.UI.DOM.appendNewElement(
-		"span",	p,
-		`${SlaveFullName(slave)} `,
-		["slave", "name", "simple"]
-	);
+	r.push(App.UI.DOM.makeElement("span", `${SlaveFullName(slave)}`, ["slave", "name", "simple"]));
 
 	// Label
 	if (slave.custom.label) {
-		p.append("(", App.UI.DOM.makeElement('span', slave.custom.label, "custom-label"), ") ");
+		r.push(App.UI.DOM.combineNodes("(",
+			App.UI.DOM.makeElement('span', slave.custom.label, "custom-label"),
+			")"));
 	}
 
 	if (market && market !== "starting") {
 		if (applyLawCheck(market)) {
-			p.append(`has passed inspection to be sold in your arcology. `);
+			r.push(`has passed inspection to be sold in your arcology.`);
 		} else {
-			p.append(`is for sale and is available to inspect. `);
+			r.push(`is for sale and is available to inspect.`);
 		}
 		if (marketText) {
-			$(p).append(marketText, ` `);
+			r.push(marketText);
 		}
-		$(p).append(reportGingering(slave));
-		el.appendChild(p);
+		r.push(reportGingering(slave));
+		r.toParagraph();
 
-		p = document.createElement("p");
-		p.className = "indent";
-		p.appendChild(
-			App.UI.DOM.makeElement(
-				"span",
-				`${slave.slaveName} `,
-				"name"
-			)
-		);
+		r.push(App.UI.DOM.makeElement("span", `${slave.slaveName}`, "name"));
 	}
 
-	p.append(`is `);
+	r.push(`is`);
 	// Devotion
-	frag = new DocumentFragment();
 	span = document.createElement('span');
 
 	if (slave.devotion < -95) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion hateful";
-		span.textContent = "hate-filled, ";
+		span.textContent = "hate-filled,";
 	} else if (slave.devotion < -50) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion hateful";
-		span.textContent = "hateful, ";
+		span.textContent = "hateful,";
 	} else if (slave.devotion < -20) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion resistant";
-		span.textContent = "reluctant, ";
+		span.textContent = "reluctant,";
 	} else if (slave.devotion <= 20) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion ambivalent";
-		span.textContent = "hesitant, ";
+		span.textContent = "hesitant,";
 	} else if (slave.devotion <= 50) {
-		frag.append("an ");
+		r.push("an");
 		span.className = "devotion accept";
-		span.textContent = "accepting, ";
+		span.textContent = "accepting,";
 	} else if (slave.devotion <= 95) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion devoted";
-		span.textContent = "devoted, ";
+		span.textContent = "devoted,";
 	} else {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion worship";
-		span.textContent = "worshipful, ";
+		span.textContent = "worshipful,";
 	}
-
-	frag.appendChild(span);
-	p.appendChild(frag);
+	r.push(span);
 
 	// Trust
 	span = document.createElement('span');
 	if (slave.trust < -95) {
 		span.className = "trust terrified";
-		span.textContent = "abjectly terrified ";
+		span.textContent = "abjectly terrified";
 	} else if (slave.trust < -50) {
 		span.className = "trust terrified";
-		span.textContent = "terrified ";
+		span.textContent = "terrified";
 	} else if (slave.trust < -20) {
 		span.className = "trust frightened";
-		span.textContent = "frightened ";
+		span.textContent = "frightened";
 	} else if (slave.trust < 20) {
 		span.className = "trust fearful";
-		span.textContent = "fearful ";
+		span.textContent = "fearful";
 	} else if (slave.trust <= 50) {
 		if (slave.devotion < -20) {
 			span.className = "defiant careful";
-			span.textContent = "careful ";
+			span.textContent = "careful";
 		} else {
 			span.className = "trust careful";
-			span.textContent = "careful ";
+			span.textContent = "careful";
 		}
 	} else if (slave.trust < 95) {
 		if (slave.devotion < -20) {
 			span.className = "defiant bold";
-			span.textContent = "bold ";
+			span.textContent = "bold";
 		} else {
 			span.className = "trust trusting";
-			span.textContent = "trusting ";
+			span.textContent = "trusting";
 		}
 	} else {
 		if (slave.devotion < -20) {
 			span.className = "defiant full";
-			span.textContent = "defiant ";
+			span.textContent = "defiant";
 		} else {
 			span.className = "trust prof-trusting";
-			span.textContent = "profoundly trusting ";
+			span.textContent = "profoundly trusting";
 		}
 	}
-	p.appendChild(span);
+	r.push(span);
 
-	// Slave's Title, ex: "pregnant big bottomed busty milky hourglass broodmother"
-	span = App.UI.DOM.appendNewElement("span", p, `${SlaveTitle(slave)}. `, "coral");
-	span.style.fontWeight = "bold";
+	// Slave's Title, ex:"pregnant big bottomed busty milky hourglass broodmother"
+	r.push(App.UI.DOM.makeElement("span", `${SlaveTitle(slave)}.`, ["si-slave-title"]));
 
-	r = [];
 	// Indenture
 	if (slave.indenture > -1) {
 		r.push(`${His}`);
@@ -163,20 +145,18 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	r.push(App.Desc.sceneIntro(slave, descType));
+	r.push(...App.Desc.sceneIntro(slave, descType, links));
 	r.push(App.Desc.name(slave));
 	r.push(App.Desc.ageAndHealth(slave));
-	$(p).append(r.join(" "));
 
-	r = [];
 	const clinicNameCaps = capFirstChar(V.clinicName);
 	if (descType !== DescType.MARKET) {
 		if (V.clinic !== 0 && V.clinicUpgradeScanner === 1) {
 			if (slave.chem > 15) {
-				p.append(`${clinicNameCaps}'s scanners score long term carcinogenic buildup in ${his} body at `,
-					App.UI.DOM.makeElement("span", `${Math.ceil(slave.chem / 10)}. `, "cyan"));
+				r.push(`${clinicNameCaps}'s scanners score long term carcinogenic buildup in ${his} body at`,
+					App.UI.DOM.makeElement("span", `${Math.ceil(slave.chem / 10)}.`, "cyan"));
 			} else {
-				p.append(`${clinicNameCaps}'s scanners confirm that ${he} has good prospects for long term health. `);
+				r.push(`${clinicNameCaps}'s scanners confirm that ${he} has good prospects for long term health.`);
 			}
 		}
 
@@ -201,9 +181,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	r.push(App.Desc.family(slave));
+	r.push(App.Desc.family(slave, links));
 
-	r.push(App.Desc.relationRival(slave));
+	r.push(...App.Desc.relationRival(slave, links));
 
 	if (slave.bodySwap > 0) {
 		if (slave.origBodyOwner !== "") {
@@ -212,16 +192,15 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		if (slave.fetish !== Fetish.MINDBROKEN && slave.fuckdoll === 0 && slave.origBodyOwnerID > 0) {
 			const owner = getSlave(slave.origBodyOwnerID);
 			if (owner !== undefined) {
-				r.push(`${He} is fully aware that ${SlaveFullName(owner)} is in ${his} old body.`);
+				r.push(`${He} is fully aware that`,
+					links ? App.UI.DOM.referenceSlaveWithPreview(owner, SlaveFullName(owner)) : SlaveFullName(owner), `
+					is in ${his} old body.`);
 			}
 		}
 	}
-	$(p).append(r.join(` `));
-	el.appendChild(p);
 
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
+
 	if (descType !== DescType.MARKET || market === "starting") {
 		let origin = slave.origin;
 		if (origin === "$auto") {
@@ -290,9 +269,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	/* Needs contemplation. Slightly redundant with descriptionsWidgets.
 	if(slave.visualAge === V.idealAge) {
 		if(slave.actualAge === V.idealAge) {
-			r.push(`${He} is ${slave.actualAge}, `);
+			r.push(`${He} is ${slave.actualAge},`);
 		} else {
-			r.push(`${He} appears to be ${slave.visualAge}, `);
+			r.push(`${He} appears to be ${slave.visualAge},`);
 		}
 		if(V.idealAge === 18) {
 			r.push(`and many still find this age especially attractive due to old world tradition.`);
@@ -303,9 +282,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		r.push(`${He} appears to be ${slave.visualAge}, which is nearly the ideal, but as ${he} is actually ${slave.actualAge}, this can sometimes be cause for confusion regarding the appropriate level of enthusiasm society should have for ${him}.`);
 	} else if(slave.visualAge === V.idealAge - 1) {
 		if(slave.actualAge === V.idealAge - 1) {
-			r.push(`${He} is ${slave.actualAge}, `);
+			r.push(`${He} is ${slave.actualAge},`);
 		} else {
-			r.push(`${He} appears to be ${slave.visualAge}, `);
+			r.push(`${He} appears to be ${slave.visualAge},`);
 		}
 		if(V.idealAge === 18) {
 			r.push(`and many are already looking forward to ${his} birthday with great anticipation due to old world tradition.`);
@@ -313,34 +292,29 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 			r.push(`and many in the arcology are already looking forward to ${his} birthday with great anticipation.`);
 		}
 	} else if(slave.actualAge === V.idealAge && slave.visualAge !== V.idealAge) {
-		r.push(`${He} is ${slave.actualAge}, a fact that many in the arcology find appealing `);
+		r.push(`${He} is ${slave.actualAge}, a fact that many in the arcology find appealing`);
 		if(V.idealAge === 18) {
-			r.push(`because of old world tradition, `);
+			r.push(`because of old world tradition,`);
 		}
 		r.push(`but due to ${his} appearing to be ${slave.visualAge}, there is less enthusiasm for ${him} than there might otherwise be.`);
 	}
 	*/
 
-	$(p).append(r.join(" "));
-
 	if (V.showScores !== 0) {
-		p.append(` Currently, ${he} has an `);
+		r.push(`Currently, ${he} has an`);
 
 		// Beauty
-		App.UI.DOM.appendNewElement("span", p, `attractiveness score `, ["pink", "bold"]);
-		App.UI.DOM.appendNewElement("span", p, `of `, ["pink"]);
-		p.append(BeautyTooltip(slave), ` and a `);
+		r.push(App.UI.DOM.makeElement("span", `attractiveness score`, ["pink", "bold"]));
+		r.push(App.UI.DOM.makeElement("span", `of`, ["pink"]));
+		r.push(BeautyTooltip(slave), `and a`);
 
 		// Fresult
-		App.UI.DOM.appendNewElement("span", p, `sexual score `, ["lightcoral", "bold"]);
-		App.UI.DOM.appendNewElement("span", p, `of `, ["lightcoral"]);
-		p.append(FResultTooltip(slave), App.UI.DOM.makeElement("span", `.`, ["lightcoral"]));
+		r.push(App.UI.DOM.makeElement("span", `sexual score`, ["lightcoral", "bold"]));
+		r.push(App.UI.DOM.makeElement("span", `of`, ["lightcoral"]));
+		r.push(App.UI.DOM.combineNodes(FResultTooltip(slave), App.UI.DOM.makeElement("span", `.`, ["lightcoral"])));
 	}
 
-	el.appendChild(p);
-	p = document.createElement('p');
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 
 	r.push(App.Desc.limbs(slave));
 
@@ -369,10 +343,10 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 			if (losses > 0) {
 				r.push(`with ${numberWithPluralOne(wins, "win")} and ${numberWithPluralOne(losses, "loss", "losses")}.`);
 			} else {
-				r.push(`${wins > 2 ? `all of ` : `both of `}which ${he} won.`);
+				r.push(`${wins > 2 ? `all of` : `both of`} which ${he} won.`);
 			}
 		} else {
-			r.push(`${losses > 2 ? `all of ` : `both of `}which ${he} lost.`);
+			r.push(`${losses > 2 ? `all of` : `both of`} which ${he} lost.`);
 		}
 	}
 
@@ -395,7 +369,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	}
 
 	let scarCounter = 0;
-	const scars = App.Medicine.Modification.scarRecord(slave)
+	const scars = App.Medicine.Modification.scarRecord(slave);
 	for (let scarName in scars) {
 		if (slave.ID === V.BodyguardID && scarCounter > 1) {
 			r.push(`${His} scars make ${him} look even more menacing than ${he} actually is.`);
@@ -523,27 +497,22 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	$(p).append(r.join(` `));
-	p.append(` `);
-
 	if (slave.voice === 0) {
-		p.append(`${He} is `, App.UI.DOM.makeElement('span', "completely silent,", "pink"));
-		p.append(` which is understandable, since ${he}'s `, App.UI.DOM.makeElement("span", "mute. ", "red"));
+		r.push(`${He} is`, App.UI.DOM.makeElement('span', "completely silent,", "pink"));
+		r.push(`which is understandable, since ${he}'s`, App.UI.DOM.makeElement("span", "mute.", "red"));
 	} else if (slave.lips > 95) {
-		p.append(`${He} is `, App.UI.DOM.makeElement('span', "effectively mute,", "pink"));
-		p.append(` since ${his} lips are so large that ${he} can no longer speak intelligibly. ${He} can still `);
+		r.push(`${He} is`, App.UI.DOM.makeElement('span', "effectively mute,", "pink"));
+		r.push(`since ${his} lips are so large that ${he} can no longer speak intelligibly. ${He} can still`);
 		if (slave.devotion > 50) {
-			p.append(`moan `);
+			r.push(`moan`);
 		} else if (slave.devotion > 20) {
-			p.append(`whimper `);
+			r.push(`whimper`);
 		} else {
-			p.append(`scream `);
+			r.push(`scream`);
 		}
-		p.append(`through them, though. `);
+		r.push(`through them, though.`);
 	}
 
-	r = [];
-
 	if (V.showBodyMods === 1) {
 		if (slave.fuckdoll > 0) {
 			if (slave.piercing.ear.weight + slave.piercing.eyebrow.weight + slave.piercing.nose.weight > 0) {
@@ -608,67 +577,61 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "hand"));
 	r.push(App.Desc.mods(slave, "wrist"));
 
-	$(p).append(r.join(` `));
-	p.append(` `);
-
 	if (slave.fuckdoll === 0) {
 		if (slave.minorInjury !== 0) {
 			if (slave.minorInjury !== "sore ass") {
-				p.append(`${He} is sporting a `);
+				r.push(`${He} is sporting a`);
 				span = document.createElement('span');
 				span.className = "red";
-				span.textContent = `${slave.minorInjury}, `;
-				p.appendChild(span);
-				p.append(` covered by makeup. `);
+				span.textContent = `${slave.minorInjury},`;
+				r.push(span);
+				r.push(`covered by makeup.`);
 			}
 		}
 	}
 	if (slave.health.illness > 0) {
 		if (slave.fuckdoll === 0) {
-			p.append(`${He} `);
+			r.push(`${He}`);
 		} else {
-			p.append(`${His} suit reports that ${he} `);
+			r.push(`${His} suit reports that ${he}`);
 		}
 		span = document.createElement('span');
 		if (slave.health.illness === 1) {
 			if (slave.fuckdoll === 0) {
-				p.append(`is `);
+				r.push(`is`);
 				span.className = "red";
-				span.textContent = `feeling under the weather. `;
-				p.appendChild(span);
+				span.textContent = `feeling under the weather.`;
+				r.push(span);
 			} else {
-				p.append(`has `);
+				r.push(`has`);
 				span.className = "red";
-				span.textContent = `fallen ill. `;
-				p.appendChild(span);
+				span.textContent = `fallen ill.`;
+				r.push(span);
 			}
 		} else if (slave.health.illness === 2) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `somewhat ill. `;
-			p.appendChild(span);
+			span.textContent = `somewhat ill.`;
+			r.push(span);
 		} else if (slave.health.illness === 3) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `sick. `;
-			p.appendChild(span);
+			span.textContent = `sick.`;
+			r.push(span);
 		} else if (slave.health.illness === 4) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `very sick. `;
-			p.appendChild(span);
+			span.textContent = `very sick.`;
+			r.push(span);
 		} else if (slave.health.illness === 5) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `terribly ill. `;
-			p.appendChild(span);
+			span.textContent = `terribly ill.`;
+			r.push(span);
 		}
 	}
 
-	el.appendChild(p);
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 	// Calling all boob widgets
 	r.push(App.Desc.boobs(slave, descType));
 	r.push(App.Desc.boobsShape(slave));
@@ -676,7 +639,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "chest"));
 	r.push(App.Desc.mods(slave, "breast"));
 	r.push(App.Desc.shoulders(slave));
-	if (slave.appendages !== "none" || slave.wingsShape !== "none"){
+	if (slave.appendages !== "none" || slave.wingsShape !== "none") {
 		r.push(App.Desc.upperBack(slave));
 	}
 	r.push(App.Desc.nipples(slave, descType));
@@ -687,28 +650,22 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "belly"));
 	r.push(App.Desc.butt(slave, descType));
 
-	$(p).append(r.join(` `));
-	el.appendChild(p);
-
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 
 	r.push(App.Desc.crotch(slave, descType));
 	r.push(App.Desc.dick(slave, descType));
 	r.push(App.Desc.vagina(slave));
 	r.push(App.Desc.anus(slave, descType));
 
-	$(p).append(r.join(` `));
-	el.appendChild(p);
+	r.toParagraph();
 
 	if (slave.fuckdoll === 0) {
-		p = document.createElement("p");
-		p.className = "indent";
-		$(p).append(App.Desc.drugs(slave));
-		el.appendChild(p);
+		r.push(App.Desc.drugs(slave));
+		r.toParagraph();
 	}
 
+	el.append(r.container());
+
 	// clear sale and law flags, if set
 
 	return el;
diff --git a/src/npc/descriptions/relationRival.js b/src/npc/descriptions/relationRival.js
index 68650051dd28a3ea874131233ae4f977416fff9c..bfda67478e96cd0bd38b21d9274eb4ee2433f87f 100644
--- a/src/npc/descriptions/relationRival.js
+++ b/src/npc/descriptions/relationRival.js
@@ -1,45 +1,71 @@
 /**
  * @param {App.Entity.SlaveState} slave
- * @returns {string}
+ * @param {boolean} links
+ * @returns {Array<string|HTMLElement|DocumentFragment>}
  */
-App.Desc.relationRival = function(slave) {
+App.Desc.relationRival = function(slave, links) {
 	const r = [];
 	const {
 		his, He
 	} = getPronouns(slave);
 
-	r.push(relative());
-	r.push(rival());
+	r.push(...relative());
+	r.push(...rival());
 
-	return r.join(" ");
+	return r;
 
+	/**
+	 * @returns {Array<string|HTMLElement>}
+	 */
 	function relative() {
 		if (slave.relationship >= 3 && totalRelatives(slave) > 0) {
 			const lover = getSlave(slave.relationshipTarget);
 			if (lover) {
 				if (relativeTerm(slave, lover) !== null) {
-					return `${He} is in an <span class="lightgreen">incestuous relationship with ${his} ${relativeTerm(slave, lover)}, ${SlaveFullName(lover)}.</span>`;
+					const s = [];
+					s.push(`${He} is in an`);
+					const span = App.UI.DOM.makeElement("span", `incestuous relationship with ${his} ${relativeTerm(slave, lover)}, `, ["si-family"]);
+					span.append(slaveReference(lover), ".");
+					s.push(span);
+					return s;
 				}
 			}
 		} else if (slave.relationship <= -2) {
 			if (relativeTerm(slave, V.PC) !== null) {
-				return `${He} is in an <span class="lightgreen">incestuous relationship with ${his} ${relativeTerm(slave, V.PC)}, you.</span>`;
+				return [`${He} is in an <span class="si-family">incestuous relationship with ${his} ${relativeTerm(slave, V.PC)}, you.</span>`];
 			}
 		}
+		return [];
 	}
 
+	/**
+	 * @returns {Array<string|HTMLElement|DocumentFragment>}
+	 */
 	function rival() {
 		if (slave.rivalry !== 0) {
 			if (getSlave(slave.rivalryTarget)) {
 				if (slave.rivalry <= 1) {
-					return `${He} <span class="lightsalmon">dislikes</span> ${SlaveFullName(getSlave(slave.rivalryTarget))}.`;
+					return [`${He} <span class="si-rival">dislikes</span>`, App.UI.DOM.combineNodes(slaveReference(getSlave(slave.rivalryTarget)), `.`)];
 				} else if (slave.rivalry <= 2) {
-					return `${He} is ${SlaveFullName(getSlave(slave.rivalryTarget))}'s <span class="lightsalmon">rival.</span>`;
+					return [`${He} is`, App.UI.DOM.combineNodes(slaveReference(getSlave(slave.rivalryTarget)), `'s`), `<span class="si-rival">rival.</span>`];
 				} else {
-					return `${He} <span class="lightsalmon">bitterly hates</span> ${SlaveFullName(getSlave(slave.rivalryTarget))}.`;
+					return [`${He} <span class="si-rival">bitterly hates</span>`, App.UI.DOM.combineNodes(slaveReference(getSlave(slave.rivalryTarget)), `.`)];
 				}
 			}
 		}
+		return [];
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string|HTMLSpanElement}
+	 */
+	function slaveReference(slave) {
+		if (links) {
+			return App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave));
+		} else {
+			return SlaveFullName(slave);
+		}
 	}
 };
 
diff --git a/src/npc/descriptions/sceneIntro.js b/src/npc/descriptions/sceneIntro.js
index 211c60c4e2e5f5707d41fba8c61249a1538e0a23..3783ed6beff816f70d402a82dde8477b87079ca2 100644
--- a/src/npc/descriptions/sceneIntro.js
+++ b/src/npc/descriptions/sceneIntro.js
@@ -1,20 +1,23 @@
 /**
  * @param {App.Entity.SlaveState} slave
  * @param {DescType} descType
- * @returns {string}
+ * @param {boolean} links
+ * @returns {Array<string|HTMLElement>}
  */
-App.Desc.sceneIntro = function(slave, descType) {
+App.Desc.sceneIntro = function(slave, descType, links) {
+	/** @type {Array<string|HTMLElement>} */
 	const r = [];
 	const {
 		he, him, his, He, His, himself, wife
 	} = getPronouns(slave);
+	const relTarget = slave.relationship > 0 ? getSlave(slave.relationshipTarget) : null;
 
 	if (descType === DescType.EVENT) {
 		r.push(`${He} is currently involved in an event, but is assigned to ${slave.assignment}.`);
 		if (slave.assignment === Job.SUBORDINATE) {
 			let lsd = getSlave(slave.subTarget);
 			if (lsd) {
-				r.push(`${He} has been ordered to serve <span class="slave name simple">${SlaveFullName(lsd)}</span> specifically.`);
+				r.push(`${He} has been ordered to serve`, App.UI.DOM.makeElement("span", slaveReference(lsd), ["slave", "name", "simple"]), `specifically.`);
 			}
 		}
 	} else if (descType !== DescType.MARKET) {
@@ -27,12 +30,12 @@ App.Desc.sceneIntro = function(slave, descType) {
 				r.push(voice());
 			}
 		}
-		r.push(relationship());
+		r.push(...relationship());
 		if (slave.fuckdoll === 0) {
 			r.push(sleepLoc());
 		}
 	}
-	return r.join(" ");
+	return r;
 
 	function inspectionIntro() {
 		const r = [];
@@ -193,7 +196,9 @@ App.Desc.sceneIntro = function(slave, descType) {
 	}
 
 	function relationship() {
+		/** @type {Array<string|HTMLElement>} */
 		const r = [];
+
 		if (slave.relationship === -3) {
 			if (slave.fetish === Fetish.MINDBROKEN) {
 				r.push(`${He} is <span class="relationship">married to you,</span> not that it matters to ${his} broken mind; to ${him}, ${he} is a slave, nothing more.`);
@@ -210,52 +215,49 @@ App.Desc.sceneIntro = function(slave, descType) {
 			r.push(`${He} is an <span class="relationship">emotional slut,</span> happy to remain officially single and free to treat everyone equally.`);
 		} else if (slave.relationship === -2) {
 			r.push(`${He} is <span class="relationship">emotionally bound to you;</span> ${his} feelings for you are comparable to those in a healthy, loving relationship.`);
-		} else if (slave.relationship !== 0) {
-			let lsd = getSlave(slave.relationshipTarget);
-			if (lsd) {
-				r.push(`${He} is`);
-				// TODO: update this with the new relationship rules
-				if (slave.relationship <= 1) {
-					r.push(`<span style="font-weight:bold" class="relationship">friends with ${SlaveFullName(lsd)};</span> the rules`);
-					if (slave.rules.relationship !== "restrictive") {
-						r.push(`encourage`);
-					} else {
-						r.push(`discourage`);
-					}
-					r.push(`their relationship.`);
-				} else if (slave.relationship <= 2) {
-					r.push(`<span style="font-weight:bold" class="relationship">best friends with ${SlaveFullName(lsd)};</span> the rules`);
-					if (slave.rules.relationship !== "restrictive") {
-						r.push(`encourage`);
-					} else {
-						r.push(`discourage`);
-					}
-					r.push(`their close relationship.`);
-				} else if (slave.relationship <= 3) {
-					r.push(`<span style="font-weight:bold" class="relationship">${SlaveFullName(lsd)}'s friend with benefits;</span> the rules`);
-					if (slave.rules.relationship === "permissive") {
-						r.push(`encourage`);
-					} else {
-						r.push(`discourage`);
-					}
-					r.push(`their sexual relationship.`);
-				} else if (slave.relationship <= 4) {
-					r.push(`<span style="font-weight:bold" class="relationship">${SlaveFullName(lsd)}'s lover;</span> the rules`);
-					if (slave.rules.relationship === "permissive") {
-						r.push(`encourage`);
-					} else {
-						r.push(`discourage`);
-					}
-					r.push(`their passionate relationship.`);
-				} else if (slave.relationship > 4) {
-					r.push(`<span style="font-weight:bold" class="relationship">${SlaveFullName(lsd)}'s slave ${wife};</span> the rules`);
-					if (slave.rules.relationship === "permissive") {
-						r.push(`encourage`);
-					} else {
-						r.push(`discourage`);
-					}
-					r.push(`marital bliss.`);
+		} else if (slave.relationship !== 0 && relTarget) {
+			r.push(`${He} is`);
+			// TODO: update this with the new relationship rules
+			if (slave.relationship <= 1) {
+				r.push(slaveRelationshipSpan(`friends with `, slaveReference(relTarget), `;`), `the rules`);
+				if (slave.rules.relationship !== "restrictive") {
+					r.push(`encourage`);
+				} else {
+					r.push(`discourage`);
 				}
+				r.push(`their relationship.`);
+			} else if (slave.relationship <= 2) {
+				r.push(slaveRelationshipSpan(`best friends with `, slaveReference(relTarget), `;`), `the rules`);
+				if (slave.rules.relationship !== "restrictive") {
+					r.push(`encourage`);
+				} else {
+					r.push(`discourage`);
+				}
+				r.push(`their close relationship.`);
+			} else if (slave.relationship <= 3) {
+				r.push(slaveRelationshipSpan(slaveReference(relTarget), `'s friend with benefits;`), `the rules`);
+				if (slave.rules.relationship === "permissive") {
+					r.push(`encourage`);
+				} else {
+					r.push(`discourage`);
+				}
+				r.push(`their sexual relationship.`);
+			} else if (slave.relationship <= 4) {
+				r.push(slaveRelationshipSpan(slaveReference(relTarget), `'s lover;`), `the rules`);
+				if (slave.rules.relationship === "permissive") {
+					r.push(`encourage`);
+				} else {
+					r.push(`discourage`);
+				}
+				r.push(`their passionate relationship.`);
+			} else if (slave.relationship > 4) {
+				r.push(slaveRelationshipSpan(slaveReference(relTarget), `'s slave ${wife};`), `the rules`);
+				if (slave.rules.relationship === "permissive") {
+					r.push(`encourage`);
+				} else {
+					r.push(`discourage`);
+				}
+				r.push(`marital bliss.`);
 			}
 		} else if (slave.fuckdoll === 0) {
 			if (slave.rules.relationship === "restrictive") {
@@ -269,7 +271,18 @@ App.Desc.sceneIntro = function(slave, descType) {
 			}
 		}
 
-		return r.join(" ");
+		return r;
+	}
+
+	/**
+	 * @param {Array<string|HTMLElement>} parts
+	 * @returns {HTMLSpanElement}
+	 */
+	function slaveRelationshipSpan(...parts) {
+		const span = document.createElement("span");
+		span.classList.add("si-relationship");
+		span.append(...parts);
+		return span;
 	}
 
 	function sleepLoc() {
@@ -287,12 +300,13 @@ App.Desc.sceneIntro = function(slave, descType) {
 			r.push(`${He} sleeps on a bedroll,`);
 		} else if (slave.rules.living === "normal") {
 			r.push(`${He} sleeps on a cot,`);
-		} else if (slave.relationship >= 4) {
+		} else if (slave.relationship >= 4 && relTarget) {
+			const {wife2, girl2} = getPronouns(relTarget).appendSuffix('2');
 			r.push(`${He} has ${his} own room, which ${he} shares with ${his}`);
 			if (slave.relationship === 5) {
-				r.push(wife);
+				r.push(wife2);
 			} else {
-				r.push(`${getPronouns(slave).girl}friend`);
+				r.push(`${girl2}friend`);
 			}
 			r.push(`whenever they can manage it,`);
 		} else {
@@ -302,4 +316,16 @@ App.Desc.sceneIntro = function(slave, descType) {
 
 		return r.join(" ");
 	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string|HTMLSpanElement}
+	 */
+	function slaveReference(slave) {
+		if (links) {
+			return App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave));
+		} else {
+			return SlaveFullName(slave);
+		}
+	}
 };
diff --git a/src/npc/descriptions/style/hairClothing.js b/src/npc/descriptions/style/hairClothing.js
index b99b8a5b518f9c583e6138b88b65871fa2e90aca..1e49e206b15c4780ab2eef6446c2cd2977c45438 100644
--- a/src/npc/descriptions/style/hairClothing.js
+++ b/src/npc/descriptions/style/hairClothing.js
@@ -3880,7 +3880,7 @@ App.Desc.hairClothing = function(slave) {
 								r.push(`is permed, and back in a big, long ponytail tied with a scrunchy in noxious 80's pastel colors.`);
 								break;
 							case "a slutty qipao":
-								r.push(`is back in short ponytail secured by jade rings etched with images of`);
+								r.push(`is back in a short ponytail secured by jade rings etched with images of`);
 								r.push(App.Desc.image(slave));
 								break;
 							case "spats and a tank top":
@@ -3890,14 +3890,14 @@ App.Desc.hairClothing = function(slave) {
 								r.push(`is tied into a small ponytail, that leaves ${his} short hair to wave in the wind.`);
 								break;
 							case "a kimono":
-								r.push(`is in short ponytail secured by ivory combs carved with images of`);
+								r.push(`is in a short ponytail secured by ivory combs carved with images of`);
 								r.push(App.Desc.image(slave));
 								break;
 							case "uncomfortable straps":
-								r.push(`is back in short ponytail secured by leather ties.`);
+								r.push(`is back in a short ponytail secured by leather ties.`);
 								break;
 							case "shibari ropes":
-								r.push(`is back in short ponytail secured with rope.`);
+								r.push(`is back in a short ponytail secured with rope.`);
 								break;
 							case "restrictive latex":
 								r.push(`sticks out of a hole in the back of ${his} latex hood.`);
diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js
index 03f67a5fbfa2e1d8c6a7ff55dbc2206f47f2cb84..d65d6fba7d85ee9aa073510a67d63467474ad4d7 100644
--- a/src/npc/generate/generateGenetics.js
+++ b/src/npc/generate/generateGenetics.js
@@ -66,22 +66,10 @@ globalThis.generateGenetics = (function() {
 		}
 		if (actor2 > 0) {
 			father = V.genePool.find(s => s.ID === actor2);
-			activeFather = getSlave(actor2);
+			activeFather = findFather(actor2);
 			if (father === undefined) {
 				father = activeFather;
 			}
-			if (father === undefined) {
-				if (V.incubator.capacity > 0) {
-					father = V.incubator.tanks.find(s => s.ID === actor2);
-					activeFather = 0; // activeFather = father?
-				}
-			}
-			if (father === undefined) {
-				if (V.nursery > 0) {
-					father = V.cribs.find(s => s.ID === actor2);
-					activeFather = 0; // activeFather = father?
-				}
-			}
 			if (father === undefined) {
 				father = 0;
 				activeFather = 0;
@@ -1312,33 +1300,14 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 function regenerateSurname(child) {
 	// clone case - copy surname from genetic origin
 	if (child.clone) {
-		if (child.cloneID === -1) {
-			child.slaveSurname = V.PC.slaveSurname;
-		} else {
-			const cloneSeed = getSlave(child.cloneID);
-			if (cloneSeed !== undefined) {
-				if (cloneSeed.slaveSurname !== 0 && cloneSeed.slaveSurname !== "") {
-					child.slaveSurname = cloneSeed.slaveSurname;
-				}
-			}
+		const cloneSeed = getRelative(child.cloneID);
+		if (cloneSeed && nameOrNull(cloneSeed.slaveSurname)) {
+			child.slaveSurname = cloneSeed.slaveSurname;
 		}
 		return;
 	}
 
 	// non-clone case - build surname from parent surnames according to the arcology's universal rules
-	function getMother() {
-		if (child.mother === -1) {
-			return V.PC;
-		}
-		return getSlave(child.mother);
-	}
-
-	function getFather() {
-		if (child.father === -1) {
-			return V.PC;
-		}
-		return getSlave(child.father);
-	}
 
 	/** @param {FC.Zeroable<string>} name */
 	function nameOrNull(name) {
@@ -1365,8 +1334,8 @@ function regenerateSurname(child) {
 		}
 	}
 
-	const father = getFather();
-	const mother = getMother();
+	const father = getRelative(child.father);
+	const mother = getRelative(child.mother);
 	const fatherName = father ? nameOrNull(father.slaveName) : null;
 	const motherName = mother ? nameOrNull(mother.slaveName) : null;
 
diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js
index 9ec8bff8de516325ff443e803fb412d9ecac77fd..6d3999f1704146e03b4105437750c4e061cb6642 100644
--- a/src/npc/generate/generateMarketSlave.js
+++ b/src/npc/generate/generateMarketSlave.js
@@ -1321,7 +1321,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 		case "hunters": {
 			slave = GenerateNewSlave(null, SGProp);
 			slave.origin = "You bought $him from the runaway hunters' slave market after they recaptured $him and $his original owner did not pay their fee.";
-			slave.devotion = -20;
+			slave.devotion = jsRandom(-60, -30);
 			slave.trust = jsRandom(-15, 15);
 			slave.intelligence = Intelligence.random({limitIntelligence: [0, 100]});
 			slave.intelligenceImplant = 15;
@@ -1446,8 +1446,8 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			SGProp.maxAge = 42;
 			slave = GenerateNewSlave(null, SGProp);
 			slave.origin = "You bought $him from the trainers' slave market after they put $him through basic training.";
-			slave.devotion += 40;
-			slave.trust += 40;
+			slave.devotion = jsRandom(-45, 15);
+			slave.trust = jsRandom(-35, 15);
 			setHealth(slave, jsRandom(-20, 80), Math.max(normalRandInt(0, 2), 0), undefined, Math.max(normalRandInt(0, 0.4), jsRandom(10, 40)));
 			if (slave.vagina !== -1) {
 				slave.skill.vaginal += 15;
diff --git a/src/npc/generate/newChildIntro.js b/src/npc/generate/newChildIntro.js
index c068fee3d93b85857b5328cc4949deafc42a1e1a..6c688df9711bf13638e1733cb0907ce1277a767a 100644
--- a/src/npc/generate/newChildIntro.js
+++ b/src/npc/generate/newChildIntro.js
@@ -253,7 +253,7 @@ App.UI.newChildIntro = function(slave) {
 			}
 		)
 	);
-	if (getSlave(slave.mother) || getSlave(slave.father) || slave.mother === -1 || slave.father === -1) {
+	if (getRelative(slave.mother) || getRelative(slave.father)) {
 		App.UI.DOM.appendNewElement(
 			"div",
 			surnaming,
@@ -861,7 +861,7 @@ App.UI.newChildIntro = function(slave) {
 	}
 	if (V.arcologies[0].FSRepopulationFocus >= 50) {
 		if (slave.readyOva > 0) {
-			r.push(`${He} notices all the rounded bellies in your arcology and <span class="trust inc">instinctively feels at home with ${his} egg filled womb.</span>`);
+			r.push(`${He} notices all the rounded bellies in your arcology and <span class="trust inc">instinctively feels at home with ${his} egg-filled womb.</span>`);
 			slave.trust += 2;
 		}
 	}
diff --git a/src/npc/generate/newSlaveIntro.js b/src/npc/generate/newSlaveIntro.js
index cb61d80b68ba73147596a1e5ddecd648998a2a90..331c809ee791ecfad3e663df2ee71cd82da78d0b 100644
--- a/src/npc/generate/newSlaveIntro.js
+++ b/src/npc/generate/newSlaveIntro.js
@@ -309,7 +309,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 		}
 
 		if ((slave.attrXY > 50 || slave.energy > 95) && slave.behavioralFlaw !== "hates men" && slave.trust >= -20) {
-			if (PC.dick === 0 && PC.boobs < 300) {
+			if (PC.dick !== 0 && PC.boobs < 300) {
 				r.push(`${He} seems to think you're handsome, and is more willing to <span class="hotpink">try for your approval</span> than ${he} would otherwise be. ${He} glances at your crotch when ${he} thinks you're not looking.`);
 				slave.devotion += 4;
 			}
@@ -3654,27 +3654,27 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 										if (PC.boobsImplant > 0) {
 											r.push(`fake,`);
 										}
-										r.push(`milk laden breasts.`);
+										r.push(`milk-laden breasts.`);
 									} else if (PC.boobs >= 1200) {
 										r.push(`huge,`);
 										if (PC.boobsImplant > 0) {
 											r.push(`fake,`);
 										}
-										r.push(`milk laden breasts.`);
+										r.push(`milk-laden breasts.`);
 									} else if (PC.boobs >= 1000) {
 										r.push(`large,`);
 										if (PC.boobsImplant > 0) {
 											r.push(`fake,`);
 										}
-										r.push(`milk laden breasts.`);
+										r.push(`milk-laden breasts.`);
 									} else if (PC.boobs >= 800) {
-										r.push(`big, milk laden breasts.`);
+										r.push(`big, milk-laden breasts.`);
 									} else if (PC.boobs >= 650) {
-										r.push(`milk laden breasts.`);
+										r.push(`milk-laden breasts.`);
 									} else if (PC.boobs >= 500) {
-										r.push(`small, milk laden breasts.`);
+										r.push(`small, milk-laden breasts.`);
 									} else if (PC.boobs >= 300) {
-										r.push(`tiny, milk laden breasts.`);
+										r.push(`tiny, milk-laden breasts.`);
 									} else {
 										r.push(`milk swollen chest.`);
 									}
@@ -4543,7 +4543,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 									} else {
 										r.push(`${His} belly steadily swells from a few months of apparent pregnancy, to "spent too much time at the buffet", until it finally stops wobbling, grows taut and forces ${his} belly button into an outie. Your cow groans not only with the weight and mounting pressure, but with guilt as well. Before long, ${he} reaches a quivering orgasm.`);
 									}
-									r.push(`You stroke ${his} gurgling stomach slowly, before turning off the valve, unfastening ${his} binds and leaving your <span class="hotpink">very pleased</span> cum balloon to savor ${his} meal. You'll make sure to set aside enough cum from your cumslaves for ${him} to drink ${himself} stupid with, and, glancing over your shoulder, find ${him} eagerly masturbating to ${his} cum filled gut. ${He}'ll probably intend to keep ${himself} filled to the brim, which is fine by you.`);
+									r.push(`You stroke ${his} gurgling stomach slowly, before turning off the valve, unfastening ${his} binds and leaving your <span class="hotpink">very pleased</span> cum balloon to savor ${his} meal. You'll make sure to set aside enough cum from your cumslaves for ${him} to drink ${himself} stupid with, and, glancing over your shoulder, find ${him} eagerly masturbating to ${his} cum-filled gut. ${He}'ll probably intend to keep ${himself} filled to the brim, which is fine by you.`);
 									slave.devotion += 5;
 								} else {
 									if (!hasBothEyes(slave)) {
@@ -4551,7 +4551,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 									} else {
 										r.push(`${His} eyes swell`);
 									}
-									r.push(`with horror, but ${he} does not flinch or make a sound. ${His} belly also swells, from a few months of apparent pregnancy, to 'spent too much time at the buffet', till it finally stops wobbling, grows taut and forces ${his} belly button into an outie. Satisfied, you shut off the valve, deciding to leave ${him} to consider ${his} cum filled middle. Time passes. ${His}`);
+									r.push(`with horror, but ${he} does not flinch or make a sound. ${His} belly also swells, from a few months of apparent pregnancy, to 'spent too much time at the buffet', till it finally stops wobbling, grows taut and forces ${his} belly button into an outie. Satisfied, you shut off the valve, deciding to leave ${him} to consider ${his} cum-filled middle. Time passes. ${His}`);
 									if (canSee(slave)) {
 										r.push(`eyes are glazed over,`);
 									} else {
@@ -4629,7 +4629,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								} else {
 									r.push(`${His} eyes swell`);
 								}
-								r.push(`with horror, but ${he} does not flinch or make a sound. ${His} belly also swells, from a few months of apparent pregnancy, to "spent too much time at the buffet", till it finally stops wobbling, grows taut and forces ${his} belly button into an outie. Satisfied, you shut off the valve, deciding to leave ${him} to consider ${his} milk filled middle. Time passes. ${His}`);
+								r.push(`with horror, but ${he} does not flinch or make a sound. ${His} belly also swells, from a few months of apparent pregnancy, to "spent too much time at the buffet", till it finally stops wobbling, grows taut and forces ${his} belly button into an outie. Satisfied, you shut off the valve, deciding to leave ${him} to consider ${his} milk-filled middle. Time passes. ${His}`);
 								if (canSee(slave)) {
 									r.push(`eyes are glazed over,`);
 								} else {
diff --git a/src/npc/importSlave.js b/src/npc/importSlave.js
index 857a98725c745601d9b322bef5626ed2904c1a6d..675d24968595a78d4dbcee11a0a569c9f692778e 100644
--- a/src/npc/importSlave.js
+++ b/src/npc/importSlave.js
@@ -26,6 +26,6 @@ App.UI.SlaveInteract.importSlave = function() {
 App.UI.SlaveInteract.exportSlave = function(slave) {
 	const el = new DocumentFragment();
 	App.UI.DOM.appendNewElement("p", el, `Copy the following block of code for importing: `, "note");
-	App.UI.DOM.appendNewElement("code", el, toJson(slave));
+	App.UI.DOM.appendNewElement("textarea", el, toJson(slave), ["export-field"]);
 	return el;
 };
diff --git a/src/npc/infants/longInfantDescription.js b/src/npc/infants/longInfantDescription.js
index 9e3f39f648597252dc9de4eca105f73d3fd4a9e2..40657d5fa00706ea619ef63ef7990cfcb7a6271b 100644
--- a/src/npc/infants/longInfantDescription.js
+++ b/src/npc/infants/longInfantDescription.js
@@ -221,7 +221,7 @@ App.Facilities.Nursery.LongInfantDescription = function(child, {market = 0, even
 		r += `. `;
 	}
 
-	r += App.Desc.family(child) + ' ';
+	// r += App.Desc.family(child) + ' '; TODO Assemble DOM instead of string to make this work again
 
 	if (father && fatherPC) {
 		if (child.eyeColor === PC.eye.origColor) {
diff --git a/src/npc/interaction/fBellyFuck.js b/src/npc/interaction/fBellyFuck.js
index 5f999e3d31a7f2b6fc8595b34b48eb6cdfd3a767..67bc4eadc2d5121a0ac4acc152ae50aaec636cae 100644
--- a/src/npc/interaction/fBellyFuck.js
+++ b/src/npc/interaction/fBellyFuck.js
@@ -133,7 +133,7 @@ App.Interact.fBellyFuck = function(slave) {
 		} else if (slave.butt > 5) {
 			text.push(`huge ass,`);
 		} else if (Math.floor(slave.buttImplant/slave.butt) > .60) {
-			text.push(`jiggly, saline filled ass,`);
+			text.push(`jiggly, saline-filled ass,`);
 		} else if (slave.butt > 2) {
 			text.push(`thick ass,`);
 		} else {
diff --git a/src/npc/interaction/fButt.js b/src/npc/interaction/fButt.js
index 002e71087893db40252c575a46967d26c549e6e3..894f714e077ad283e406122d32400ad295f1f104 100644
--- a/src/npc/interaction/fButt.js
+++ b/src/npc/interaction/fButt.js
@@ -345,7 +345,7 @@ App.Interact.fButt = function(slave) {
 		if (slave.bellyPreg >= 1500) {
 			text.push(`The poor ${girl}'s pregnant belly makes taking a rough fuck in both ${his} holes uncomfortable for ${him}.`);
 		} else if (slave.bellyImplant >= 1500) {
-			text.push(`The poor ${girl}'s implant filled belly makes taking a rough fuck in both ${his} holes uncomfortable for ${him}.`);
+			text.push(`The poor ${girl}'s implant-filled belly makes taking a rough fuck in both ${his} holes uncomfortable for ${him}.`);
 		} else if (slave.bellyFluid >= 1500) {
 			text.push(`The poor ${girl}'s sloshing belly makes taking a rough fuck in both ${his} holes uncomfortable for ${him}, though the lewd jiggling the pounding sends through it is quite a sight.`);
 		}
diff --git a/src/npc/interaction/fFeelings.js b/src/npc/interaction/fFeelings.js
index b00a24cee9f70d50813eb9295517ee5aa77f5934..f1430f55a87a3d1ca73de5ee778377986abf812e 100644
--- a/src/npc/interaction/fFeelings.js
+++ b/src/npc/interaction/fFeelings.js
@@ -274,7 +274,7 @@ App.Interact.fFeelings = function(slave) {
 					text.push(`${Master}, my body is full...`);
 
 					if (slave.geneticQuirks.uterineHypersensitivity === 2) {
-						text.push(`I can't fit anymore... So than why does every near rupture feel so fucking good?`);
+						text.push(`I can't fit any more... So than why does every near rupture feel so fucking good?`);
 					} else if (slave.sexualFlaw === "self hating") {
 						text.push(`I surely couldn't even`);
 
diff --git a/src/npc/interaction/fRelation.js b/src/npc/interaction/fRelation.js
index 52162e42907e5f7cb5354819ca392863b0a4d1d7..c67a6f6994d95cf21c0856f4aea96a9c563ca2c2 100644
--- a/src/npc/interaction/fRelation.js
+++ b/src/npc/interaction/fRelation.js
@@ -167,9 +167,9 @@ App.Interact.fRelation = function(slave, partner) {
 		}
 		r.push(`and ${slave.slaveName}'s mouth tour ${his2} body. When you finish in ${his2}`);
 		if (partner.dick > 0) {
-			r.push(`asshole, ${his2} ${daughter} hastens to lavish attention on ${his} ${partnerRel}'s well fucked, cum filled butt.`);
+			r.push(`asshole, ${his2} ${daughter} hastens to lavish attention on ${his} ${partnerRel}'s well fucked, cum-filled butt.`);
 		} else {
-			r.push(`pussy, ${his2} ${daughter} hastens to lavish attention on ${his} ${partnerRel}'s well fucked, cum filled cunt.`);
+			r.push(`pussy, ${his2} ${daughter} hastens to lavish attention on ${his} ${partnerRel}'s well fucked, cum-filled cunt.`);
 		}
 		seX(slave, "oral", partner, "oral", 2);
 		r.push(VCheck.Partner(partner, 1));
diff --git a/src/npc/interaction/fVagina.js b/src/npc/interaction/fVagina.js
index 8227869119d9065a39959aeedf4ec73faddc45be..37643c4725f1d346b1f3c7cee4aa94ea6cc28f48 100644
--- a/src/npc/interaction/fVagina.js
+++ b/src/npc/interaction/fVagina.js
@@ -1105,7 +1105,7 @@ App.Interact.fVagina = function(slave) {
 	if (slave.bellyPreg >= 1500) {
 		r.push(`The poor slave's belly gets in the way, but the added perversion of fucking a pregnant hole makes the inconvenience worthwhile.`);
 	} else if (slave.bellyImplant >= 1500) {
-		r.push(`The poor slave's implant filled belly gets in the way, but the added perversion of fucking a ${girl} with such a round stomach makes the inconvenience worthwhile.`);
+		r.push(`The poor slave's implant-filled belly gets in the way, but the added perversion of fucking a ${girl} with such a round stomach makes the inconvenience worthwhile.`);
 	} else if (slave.bellyFluid >= 1500) {
 		r.push(`The poor slave's sloshing belly gets in the way, but the added perversion of seeing it jiggle makes the inconvenience worthwhile.`);
 	}
diff --git a/src/npc/interaction/fondleDick.js b/src/npc/interaction/fondleDick.js
index e4de255d79341ce6b386429094f4855aa8f8b1b2..8f9723da8bd6ed4653505afbbc1e65dd0b0b9059 100644
--- a/src/npc/interaction/fondleDick.js
+++ b/src/npc/interaction/fondleDick.js
@@ -138,7 +138,7 @@ App.Interact.fondleDick = function(slave) {
 		}
 		r.push(`moving to match your hand movements. ${He} moans and shudders, leaking ${his} cockmilk as ${he} orgasms in your hands. ${He} dutifully looks at you as you stop moving your hands and get cleaned up.`);
 	} else {
-		r.push(`${He} devotedly comes over and gives you an impassioned kiss. ${He} smiles and points ${his} dick towards you. You gently trace your fingers along ${his} ${dickDesc()} before taking it gently in one hand and tenderly stroking your hand along its shaft`);
+		r.push(`${He} devotedly comes over and gives you an impassioned kiss. ${He} smiles and points ${his} dick towards you. You gently trace your fingers along ${his} ${dickDesc()} before taking it gently in one hand and tenderly stroking your hand along its`);
 		strokeAndSqueeze();
 		standardStiffy();
 		r.push(`${He} begs you not to stop. Soon, ${he} moans and ${his} movements indicate that ${he} is about to orgasm. ${He} shudders and leaks ${his} cockmilk as ${he} orgasms in your hands. ${He} looks at you passionately as you stop moving your hands and get cleaned up.`);
diff --git a/src/npc/interaction/killSlave.js b/src/npc/interaction/killSlave.js
index 97e2e6b5f04d214be5675d45358871ef61432d2f..5858b31f730ead66bbd093cdda74fc120f1766f3 100644
--- a/src/npc/interaction/killSlave.js
+++ b/src/npc/interaction/killSlave.js
@@ -439,19 +439,12 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 					} else {
 						const subDiv = document.createElement("div");
 
-						const daughters = [];
 						const mother = getPronouns(slave).mother;
 
-						if (arr.length > 2) {
-							daughters.push(toSentence(arr));
-						} else {
-							daughters.push(`${getSlave(arr[0]).slaveName} and ${getSlave(arr[1]).slaveName}`);
-						}
-
 						arr.forEach(i => getSlave(i).devotion -= 25);
 
 						App.Events.addParagraph(subDiv, [
-							`${His} children, ${daughters}, are <span class="devotion dec">horrified</span> that you would take their ${mother} from them.`
+							`${His} children, ${toSentence(arr.map(i => getSlave(i).slaveName))}, are <span class="devotion dec">horrified</span> that you would take their ${mother} from them.`
 						]);
 
 						return subDiv;
@@ -475,29 +468,12 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 						return subDiv;
 					} else {
 						const subDiv = document.createElement("div");
-
-						const twins = [];
-
 						const sister = getPronouns(slave).sister;
 
-						if (arr.length > 2) {
-							let lastTwin = arr.pop();
-
-							for (const twin of arr) {
-								twins.push(`${getSlave(twin).slaveName},`);
-
-								getSlave(twin).devotion -= 30;
-							}
-
-							twins.push(`and ${getSlave(lastTwin).slaveName}`);
-						} else {
-							twins.push(`${getSlave(arr[0]).slaveName} and ${getSlave(arr[1]).slaveName}`);
-						}
-
 						arr.forEach(i => getSlave(i).devotion -= 30);
 
 						App.Events.addParagraph(subDiv, [
-							`${His} twins, ${twins.join(' ')} are <span class="devotion dec">devastated</span> that you would take their ${sister} from them.`
+							`${His} twins, ${toSentence(arr.map(i => getSlave(i).slaveName))} are <span class="devotion dec">devastated</span> that you would take their ${sister} from them.`
 						]);
 
 						return subDiv;
@@ -522,26 +498,12 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 					} else {
 						const subDiv = document.createElement("div");
 
-						const sisters = [];
-
 						const sister = getPronouns(slave).sister;
 
-						if (arr.length > 2) {
-							let lastSister = arr.pop();
-
-							for (const sister of arr) {
-								sisters.push(`${getSlave(sister).slaveName},`);
-							}
-
-							sisters.push(`and ${getSlave(lastSister).slaveName}`);
-						} else {
-							sisters.push(`${getSlave(arr[0]).slaveName} and ${getSlave(arr[1]).slaveName}`);
-						}
-
 						arr.forEach(i => getSlave(i).devotion -= 25);
 
 						App.Events.addParagraph(subDiv, [
-							`${His} sister, ${sisters.join(' ')} are <span class="devotion dec">grief-stricken</span> that you would take their ${sister} from them.`
+							`${His} sisters, ${toSentence(arr.map(i => getSlave(i).slaveName))} are <span class="devotion dec">grief-stricken</span> that you would take their ${sister} from them.`
 						]);
 
 						return subDiv;
@@ -566,26 +528,12 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 					} else {
 						const subDiv = document.createElement("div");
 
-						const halfSisters = [];
-
 						const sister = getPronouns(slave).sister;
 
-						if (arr.length > 2) {
-							let lastHalfSister = arr.pop();
-
-							for (const sister of arr) {
-								halfSisters.push(`${getSlave(sister).slaveName},`);
-							}
-
-							halfSisters.push(`and ${getSlave(lastHalfSister).slaveName}`);
-						} else {
-							halfSisters.push(`${getSlave(arr[0]).slaveName} and ${getSlave(arr[1]).slaveName}`);
-						}
-
 						arr.forEach(i => getSlave(i).devotion -= 20);
 
 						App.Events.addParagraph(subDiv, [
-							`${His} half-sisters, ${halfSisters.join(' ')}, are <span class="devotion dec">saddened</span> that you would take their ${sister} from them.`
+							`${His} half-sisters, ${toSentence(arr.map(i => getSlave(i).slaveName))}, are <span class="devotion dec">saddened</span> that you would take their ${sister} from them.`
 						]);
 
 						return subDiv;
@@ -593,11 +541,10 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 				}
 
 				function getRelationshipEffects(ID) {
-					if (getSlave(ID).fetish !== Fetish.MINDBROKEN) {
+					const target = getSlave(ID);
+					if (target.fetish !== Fetish.MINDBROKEN) {
 						const subDiv = document.createElement("div");
 
-						const target = getSlave(ID);
-
 						App.Events.addParagraph(subDiv, [
 							`${target.slaveName} is <span class="devotion dec">grief-stricken</span> that you have killed ${getPronouns(target).his} best source of comfort and companionship in a life of bondage.`
 						]);
diff --git a/src/npc/interaction/passage/fSlaveImpreg.js b/src/npc/interaction/passage/fSlaveImpreg.js
index 9e72ba66d6d732f9d477e42776b665cf24d797d7..6698ba0af5b3883fc6ad0daf1494b5f5cf704689 100644
--- a/src/npc/interaction/passage/fSlaveImpreg.js
+++ b/src/npc/interaction/passage/fSlaveImpreg.js
@@ -54,7 +54,9 @@ App.Interact.fSlaveImpreg = function(slave, impregnatrix) {
 		himP
 	} = getPronouns(V.PC).appendSuffix("P");
 
-	r.push(`The first necessary step is to prepare the donatrix.`);
+	const donatrix = (impregnatrix.pronoun === App.Data.Pronouns.Kind.female || V.diversePronouns === 0) ? `donatrix` : `donor`;
+
+	r.push(`The first necessary step is to prepare the ${donatrix}.`);
 	const belly = bellyAdjective(slave);
 	const superfetation = (slave.geneticQuirks.superfetation === 2 && slave.pregKnown === 1) ? 1 : 0;
 	const penCountBonus = random(6, 20);
@@ -212,7 +214,7 @@ App.Interact.fSlaveImpreg = function(slave, impregnatrix) {
 			impregnatrix.anus = 1;
 		}
 	} else if (impregnatrix.devotion < -20) {
-		r.push(`Since your semen donatrix is restrained, you order ${slave.slaveName} to present ${himself} on the couch, and then maneuver ${impregnatrix.slaveName}'s dick into place. ${slave.slaveName} does ${his} best to hump ${himself} against the unwilling cock until you deal ${impregnatrix.slaveName} a terrific swat across the ass and promise to give ${him2} more of the same until ${he2} gets going. After watching ${him2} mechanically fuck for a while, you stop ${him2}, push an electrostimulator up ${his2} butt, and administer a shock to ${his2} ${prostate} that forces ${him2} to empty ${his2} nuts into ${slave.slaveName}. ${He} <span class="mediumorchid">resents</span> what you made ${him2} do and <span class="gold">fears you</span> as a result. Though ${slave.slaveName} accepts the situation, ${he} looks into ${impregnatrix.slaveName}'s eyes with obvious apology.`);
+		r.push(`Since your semen ${donatrix} is restrained, you order ${slave.slaveName} to present ${himself} on the couch, and then maneuver ${impregnatrix.slaveName}'s dick into place. ${slave.slaveName} does ${his} best to hump ${himself} against the unwilling cock until you deal ${impregnatrix.slaveName} a terrific swat across the ass and promise to give ${him2} more of the same until ${he2} gets going. After watching ${him2} mechanically fuck for a while, you stop ${him2}, push an electrostimulator up ${his2} butt, and administer a shock to ${his2} ${prostate} that forces ${him2} to empty ${his2} nuts into ${slave.slaveName}. ${He} <span class="mediumorchid">resents</span> what you made ${him2} do and <span class="gold">fears you</span> as a result. Though ${slave.slaveName} accepts the situation, ${he} looks into ${impregnatrix.slaveName}'s eyes with obvious apology.`);
 		impregnatrix.devotion -= 5;
 		impregnatrix.trust -= 5;
 		seX(impregnatrix, "anal", V.PC);
diff --git a/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js b/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
index 5d5d9be724b4423d0632c8c940c8b0db9cfc0297..4e51a38af062e0bae8469631b8e34c805c59ef22 100644
--- a/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
+++ b/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
@@ -101,7 +101,7 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 			}
 		} else if (milkTap.mother === slave.ID) {
 			if (incestGive) {
-				r.push(`This is easy enough, as ${milkTap.slaveName} is aroused at the lewdity of breast feeding ${his2} own mother.`);
+				r.push(`This is easy enough, as ${milkTap.slaveName} is aroused at the lewdness of breast feeding ${his2} own mother.`);
 				if (milkTap.lactation > 1) {
 					r.push(`${He2} is practically gushing milk with excitement.`);
 				} else {
@@ -1109,7 +1109,7 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 			}
 		} else if (slave.father === milkTap.ID) {
 			if (incestGive) {
-				r.push(`This is easy enough, as ${milkTap.slaveName} cherishes the sheer lewdity of having ${his2} dick sucked by ${his2} ${relative}.`);
+				r.push(`This is easy enough, as ${milkTap.slaveName} cherishes the sheer lewdness of having ${his2} dick sucked by ${his2} ${relative}.`);
 			} else {
 				r.push(`This is tough, as ${milkTap.slaveName} is rather uncomfortable having ${his2} dick sucked by ${his2} ${relative}, but ${he2} can't really complain about getting ${his2} overfilled nuts drained.`);
 			}
@@ -1121,7 +1121,7 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 			}
 		} else if (milkTap.father === slave.ID) {
 			if (incestGive) {
-				r.push(`This is easy enough, as ${milkTap.slaveName} cherishes the sheer lewdity of having ${his2} dick sucked by ${his2} own father.`);
+				r.push(`This is easy enough, as ${milkTap.slaveName} cherishes the sheer lewdness of having ${his2} dick sucked by ${his2} own father.`);
 			} else {
 				r.push(`This is tough, as ${milkTap.slaveName} is very uncomfortable having ${his2} dick sucked by ${his2} own father, but ${he2} can't really complain about getting ${his2} overfilled nuts drained.`);
 			}
@@ -1966,7 +1966,7 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 				}
 				r.push(`against ${him} while ${he} deepthroats ${milkTap.slaveName}. With every thrust against the moaning slave, both you and ${milkTap.slaveName} come closer to climax.`);
 			}
-			r.push(`You wrap an arm around ${slave.slaveName}'s middle so you may feel ${his} stomach swell with ejaculate and place your other hand to ${milkTap.slaveName}'s breasts to prevent ${him2} from feeling left out from your attention.`);
+			r.push(`You wrap an arm around ${slave.slaveName}'s middle so you may feel ${his} stomach swell with ejaculate and place your other hand to one of ${milkTap.slaveName}'s nipples to prevent ${him2} from feeling left out from your attention.`);
 
 			if (slave.inflation === 3) {
 				r.push(`You cum multiple times as you feel ${his} belly slowly round with cum, transform into a jiggling mass, and finally grow taut under your molesting fingers.`);
@@ -1982,7 +1982,7 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 				r.push(`${slave.slaveName}`);
 				r.push(`got off quite strongly from the growing pressure within ${him}, <span class="hotpink">cementing</span> ${his} <span class="lime">first fucking</span> as something special.`);
 				slave.devotion += 4;
-				slave.anus = 1;
+				slave.vagina = 1;
 			} else if (canDoAnal(slave) && (slave.anus === 0)) {
 				r.push(`${slave.slaveName}`);
 				r.push(`got off quite strongly from the growing pressure within ${him}, <span class="hotpink">cementing</span> ${his} <span class="lime">first anal</span> as something special.`);
diff --git a/src/npc/surgery/organFarm.js b/src/npc/surgery/organFarm.js
index 469de81f6f7660d63cac96a572278c5165b6c55c..aaa889265c91e8d4f9c24f15c7a59d3e0641250c 100644
--- a/src/npc/surgery/organFarm.js
+++ b/src/npc/surgery/organFarm.js
@@ -43,7 +43,7 @@ App.Medicine.OrganFarm.growActions = function(slave) {
 				})));
 
 				const tooltip = typeof organ.tooltip === "string" ? organ.tooltip : organ.tooltip(slave);
-				array.push(App.UI.DOM.makeElement("div", `Costs ${cashFormat(organ.cost)}${tooltip !== "" ? ` and ${tooltip}` : ""}.`, "detail"));
+				array.push(App.UI.DOM.makeElement("div", `Costs ${cashFormat(organ.cost)}${tooltip !== "" ? ` and ${tooltip}` : ""}.`, ["detail"]));
 
 				if (organ.implantActions.some((o) => {
 					return o.canImplant(slave);
@@ -377,7 +377,7 @@ App.Medicine.OrganFarm.currentlyGrowing = function() {
 	}
 
 	if (growLines.length === 0 && finishLines.length === 0) {
-		App.UI.DOM.appendNewElement("div", frag, "Organs must be genetically matched to their host slave. To begin growing organs for a slave, take them to the Remote Surgery.", "detail");
+		App.UI.DOM.appendNewElement("div", frag, "Organs must be genetically matched to their host slave. To begin growing organs for a slave, take them to the Remote Surgery.", ["detail"]);
 	}
 
 	return frag;
diff --git a/src/npc/surgery/surgery.js b/src/npc/surgery/surgery.js
index b2039237b0bfdddc5bd6549cf70a0a9f800f62ca..c5a8364d22a3721c79b291dbdb2e15bf396322ab 100644
--- a/src/npc/surgery/surgery.js
+++ b/src/npc/surgery/surgery.js
@@ -289,7 +289,7 @@ App.Medicine.Surgery.sizingProcedures = function() {
 		};
 
 		const distanceDecreased = (newValue) => {
-			return distanceToRangeDecreased(currentDistance, distanceToRange(newValue, options.targetSize), options.targetSize);
+			return distanceToRangeDecreased(Math.abs(currentDistance), Math.abs(distanceToRange(newValue, options.targetSize)), options.targetSize);
 		};
 
 		/**
diff --git a/src/npc/surgery/surrogacyWorkaround.js b/src/npc/surgery/surrogacyWorkaround.js
index a8a87151950327ad8d152325edaa12450c234fc1..5c028eaf38478fa74e604c7da24648a09f124725 100644
--- a/src/npc/surgery/surrogacyWorkaround.js
+++ b/src/npc/surgery/surrogacyWorkaround.js
@@ -57,8 +57,9 @@ App.UI.surrogacyWorkaround = function() {
 
 	for (const slave of V.slaves) {
 		if (slave.balls > 0 && slave.pubertyXY === 1 && isSlaveAvailable(slave) && canBreed(donatrix, slave)) {
-			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				SlaveFullName(slave),
+			const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave)));
+			div.append(" ", App.UI.DOM.link(
+				"Select",
 				() => {
 					V.impregnatrix = slave;
 					App.UI.reload();
@@ -114,8 +115,9 @@ App.UI.surrogacyWorkaround = function() {
 
 	for (const slave of V.slaves) {
 		if (canBeReceptrix(slave)) {
-			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				SlaveFullName(slave),
+			const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave)));
+			div.append(" ", App.UI.DOM.link(
+				"Select",
 				() => {
 					V.receptrix = slave;
 					App.UI.reload();
diff --git a/src/player/desc/pLongBelly.js b/src/player/desc/pLongBelly.js
index 9d2b9d67494956b48909ed7d1b9cd1180aee73c4..aac178a8266578f5d3fcbc2ceeaccb8b6ab5e10c 100644
--- a/src/player/desc/pLongBelly.js
+++ b/src/player/desc/pLongBelly.js
@@ -1453,8 +1453,15 @@ App.Desc.Player.belly = function(PC = V.PC) {
 		if (PC.belly >= 300000) {
 			if (V.pregAccessibility === 1) {
 				r.push(`Fortunately, you've had the penthouse remodeled to support ${girlP}s with such motherly figures, so fitting through the doors, using furniture and reaching things isn't a concern.`);
+			} else if (V.buttAccessibility === 1 || V.ballsAccessibility === 1 || V.boobAccessibility === 1) {
+				r.push(`The halls and doors of the penthouse have already been remodeled to accommodate other enormous assets, so a ${girlP} with a figure as motherly as yours can still get around. Now if only you could use the rest of it without your belly getting in the way.`);
 			} else {
 				r.push(`Even worse, the penthouse was not designed to handle ${girlP}s with a figure as motherly as yours; you crowd the halls, get stuck in doors and on furniture, and can never reach anything without your belly bumping into something.`);
+				 if (PC.belly >= 800000) {
+					r.push(`Well you did, right up until you outgrew the bedroom door and became <span class="red">stuck inside it.</span>`);
+				} else if (PC.belly >= 775000) {
+					r.push(`Your bedroom door is especially bad... A little bit bigger and you may be stuck in here.`);
+				}
 			}
 		}
 
@@ -1480,11 +1487,17 @@ App.Desc.Player.belly = function(PC = V.PC) {
 			} else {
 				r.push(`You're so bulbous and heavy that`);
 			}
-			r.push(`you can no longer realistically move yourself are now confined to your bedroom.`);
-			if (PC.bellyPreg > 0) {
-				r.push(`You'll never be lonely though, not with all the lives pinning you down.`);
+			r.push(`you can no longer realistically move yourself are now confined to`);
+			if (isMovable(PC)) {
+				r.push(`a wheelchair.`);
+				r.push(bellyAccessibility());
 			} else {
-				r.push(`It's so wide that even lying down is uncomfortable without a mountain of pillows to support your body with.`);
+				r.push(`your bedroom.`);
+				if (PC.bellyPreg > 0) {
+					r.push(`You'll never be lonely though, not with all the lives pinning you down.`);
+				} else {
+					r.push(`It's so wide that even lying down is uncomfortable without a mountain of pillows to support your body with.`);
+				}
 			}
 		} else if (isBellyHeavy) {
 			r.push(`You're so bulbous and heavy that it makes getting around a challenge.`);
diff --git a/src/player/desc/pLongBoobs.js b/src/player/desc/pLongBoobs.js
index 7bcda31cf2391aa2a8908c213a3d0f5c2845c1be..1653f90696ebe9a1b613c16d8af60a7cc3161450 100644
--- a/src/player/desc/pLongBoobs.js
+++ b/src/player/desc/pLongBoobs.js
@@ -183,7 +183,7 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 	function nipples() {
 		const r = [];
 
-		if (PC.aphrodisiacs > 0 || PC.inflationType === "aphrodisiac" || PC.energy > 95 || PC.need > 0) {
+		if (isPlayerHorny(PC)) {
 			switch (PC.nipples) {
 				case "tiny":
 					r.push(`You have stiff little nubs ${areolae()}.`);
@@ -196,7 +196,7 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 					break;
 				case "partially inverted":
 				case "inverted":
-					r.push(`Your nipples are stiffly erect and ${areolae()}. They'd be inverted if you weren't so horny right now.`);
+					r.push(`Your nipples are stiffly erect and ${areolae()} They'd be inverted if you weren't so horny right now.`);
 					break;
 				case "huge":
 					if (PC.boobs - PC.boobsImplant > 7500) {
@@ -210,7 +210,7 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 					} else {
 						r.push(`Your nipples are enormously erect and`);
 					}
-					r.push(`areolae()`);
+					r.push(areolae());
 					break;
 				case "fuckable":
 					r.push(`Your nipples are swollen shut and ${areolae()}`);
@@ -370,8 +370,19 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 		if (PC.boobs >= 25000) {
 			if (V.boobAccessibility === 1) {
 				r.push(`On the bright side, you've had the penthouse remodeled for ${girlP}s with such substantial bosoms already, so fitting through doors and using furniture isn't a concern.`);
+			} else if (V.pregAccessibility === 1 || V.ballsAccessibility === 1 || V.buttAccessibility === 1) {
+				r.push(`Still, the halls and doors of the penthouse have been remodeled to accommodate other enormous assets, so there's plenty of room for your substantial busom. Too bad everything is still at the perfect height to jab you in the tits.`);
 			} else {
 				r.push(`Even worse, the penthouse was not designed to handle ${girlP}s with bosoms as substantial as yours; you crowd whichever halls or doors you use and find an uncomfortable number of objects poking and prodding your tits.`);
+				if (PC.boobsImplant >= 600000) {
+					r.push(`But with implants wider than a standard doorway, you aren't keen on trying to force them through, <span class="red">leaving you trapped inside your room.</span>`);
+				} else if (PC.boobs >= 1000000) {
+					r.push(`In fact, you're so busty that any efforts to cram your tits through your doorway result in them plugging the doorway, effectively <span class="red">sealing you inside your room.</span>`);
+				} else if (PC.boobsImplant >= 599000) {
+					r.push(`The only way to get in and out of your bedroom is to do so one tit at a time; unless you wanted to be trapped in your own home, it might not be the best idea to size up your implants much more.`);
+				} else if (PC.boobs >= 995000) {
+					r.push(`It's become really difficult to feed the entirety of your breastflesh through the doorway when you need to pass through; you are at risk of plugging it should you grow much more.`);
+				}
 			}
 		}
 		return r.join(" ");
@@ -383,7 +394,13 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 		if ((PC.physicalAge <= 12 && PC.boobs > 100000 + (PC.muscles * 50)) ||
 			(PC.physicalAge < 18 && PC.boobs > 250000 + (PC.muscles * 100)) ||
 			(PC.physicalAge >= 18 && PC.boobs > 500000 + (PC.muscles * 200))) {
-			r.push(`Your tits are so enormous you've lost the ability to lift them and are now stuck in bed. You'll never be without pillows, however.`);
+			r.push(`Your tits are so enormous you've lost the ability to lift them and`);
+			if (isMovable(PC)) {
+				r.push(`must use a wheelchair to cart yourself around.`);
+				r.push(boobAccessibility());
+			} else {
+				r.push(`are now stuck in bed. You'll never be without pillows, however.`);
+			}
 		} else if (PC.boobs > sizeLimit) {
 			r.push(`Your tits are so heavy that it makes moving around difficult.`);
 			if (canWalk(PC)) {
@@ -570,6 +587,11 @@ App.Desc.Player.boobs = function(PC = V.PC) {
 	} else {
 		r.push(`you have nothing in the breast department. You're <span class="orange">completely flat.</span>`);
 	}
+	// temp
+	if (PC.boobs >= 1600) {
+		r.push(boobShape());
+		r.push(boobVolume());
+	}
 	r.push(
 		boobFreckles(),
 		nipples()
diff --git a/src/player/desc/pLongButt.js b/src/player/desc/pLongButt.js
index 952eba1f010a2b31bb076ea8051d1e2cc6ab3413..3e97350ec3291ccebfcb674e1cee37343b5179ac 100644
--- a/src/player/desc/pLongButt.js
+++ b/src/player/desc/pLongButt.js
@@ -204,8 +204,15 @@ App.Desc.Player.butt = function(PC = V.PC) {
 		if (PC.butt > 15) {
 			if (V.buttAccessibility === 1) {
 				r.push(`It's a good thing you've had the penthouse remodeled for ${girlP}s with such ponderous bottoms already, so you can at least live comfortably at home.`);
+			} else if (V.pregAccessibility === 1 || V.ballsAccessibility === 1 || V.boobAccessibility === 1) {
+				r.push(`The halls and doors of the penthouse have already been remodeled to accommodate other enormous assets, so a ${girlP} with a ponderous bottom like yours can still get around.`);
 			} else {
 				r.push(`Even worse, the penthouse was not designed to handle ${girlP}s with bottoms as ponderous as yours; the narrow halls and doors give unbroken slaves an easy means to elude you.`);
+				if (PC.buttImplant >= 30) {
+					r.push(`Not that it matters when your ass implants are so huge they no longer fit through your bedroom door, <span class="red">leaving you trapped inside.</span>`);
+				} else if (PC.buttImplant >= 28) {
+					r.push(`And your bedroom door... Was it always this narrow?`);
+				}
 			}
 		}
 		return r.join(" ");
@@ -214,8 +221,12 @@ App.Desc.Player.butt = function(PC = V.PC) {
 	function weight() {
 		const r = [];
 
-		if (PC.physicalAge <= 12 && PC.butt > 14) {
-			r.push(`Your ass weighs so much you can no longer drag it off your bed. It makes a comfy cushion, at least.`);
+		if ((PC.physicalAge <= 12 && PC.butt > 14) || PC.butt > 22) {
+			r.push(`Your ass weighs so much you can no longer stand up on your own, and dragging it off your bed just ends with you on the floor. It makes a comfy cushion, at least.`);
+			if (isMovable(PC)) {
+				r.push(`When you do decide to go somewhere, you're reliant on an extra-wide wheelchair to get you there.`);
+				r.push(buttAccessibility());
+			}
 		} else if ((PC.physicalAge <= 12 && PC.butt >= 12) || (PC.physicalAge > 12 && PC.butt > 17)) {
 			r.push(`Your ass is so unwieldy and heavy that it makes moving around difficult.`);
 			if (canWalk(PC)) {
@@ -230,10 +241,13 @@ App.Desc.Player.butt = function(PC = V.PC) {
 				} else  {
 					r.push(`It takes a lot of effort to not be forced into a sitting position with it, so you're most comfortable just letting it rest on something when you have the chance.`);
 				}
-			} else {
+				r.push(buttAccessibility());
+			} else if (isMovable(PC)) {
 				r.push(`But that's to be expected since you require an extra-wide wheelchair to get anywhere.`);
+				r.push(buttAccessibility());
+			} else {
+				r.push(`But you couldn't do that anyway, so it's not a concern.`);
 			}
-			r.push(buttAccessibility());
 		} else if (PC.butt > 6 && canWalk(PC)) {
 			r.push(`Your ass is heavy enough to`);
 			if (hasBothProstheticLegs(PC)) {
diff --git a/src/player/desc/pLongCrotch.js b/src/player/desc/pLongCrotch.js
index 46dfb72f7dcb2fd5f27531dae8673380099321a2..68928031e4a529c5dbfcfb71b324a1abeb10e66d 100644
--- a/src/player/desc/pLongCrotch.js
+++ b/src/player/desc/pLongCrotch.js
@@ -3,18 +3,7 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 	const {girlP} = getPronouns(PC).appendSuffix('P');
 	const legs = hasBothLegs(PC) ? "legs" : "leg";
 	const hands = hasBothArms(PC) ? "hands" : "hand";
-	const isAroused = ((PC.prostate > 0 && PC.preg > 0 && PC.preg > PC.pregData.normalBirth * .75) ||
-		(PC.preg > 0 && PC.preg > PC.pregData.normalBirth * .66 && PC.pregMood === 2) ||
-		(PC.geneticQuirks.uterineHypersensitivity === 2 &&
-			(PC.bellyPreg >= 10000) ||
-			(PC.belly > (PC.pregAdaptation * 1000)) ||
-			(PC.wombImplant === "restraint" && PC.belly >= 400000)
-		) ||
-		(PC.need > 0) ||
-		(PC.energy > 95) ||
-		(PC.aphrodisiacs > 0) ||
-		(PC.inflationType === "aphrodisiac") ||
-		(PC.drugs === "priapism agents"));
+	const isAroused = isPlayerHorny(PC);
 	const isVirile = (PC.balls > 0 && PC.pubertyXY === 1 && PC.vasectomy === 0 && PC.ballType !== "sterile");
 	const cumTotal = (cumAmount(PC) / 70) || 0;
 	const foreskinRatio = (PC.foreskin - PC.dick);
@@ -42,7 +31,7 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 					r.push(`your wispy pubic hair`);
 				} else if (PC.physicalAge < pubertyAge) {
 					r.push(`your small patch of ${PC.pubicHColor} pubic hair`);
-				} else if (PC.pubicHStyle === "in a strip") {
+				} else if (PC.pubicHStyle === "shaved") {
 					r.push(`your ${PC.pubicHColor} stubble`);
 				} else if (PC.pubicHStyle === "in a strip") {
 					r.push(`your strip of ${PC.pubicHColor} pubic hair`);
@@ -451,8 +440,9 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 			(PC.dick >= 68 + (PC.muscles * 0.4))
 		) {
 			r.push(`Your cock is a monolith of soft flesh and weighty enough that you can no longer realistically carry it without assistance.`);
-			if (canStand(PC)) {
-				r.push(`You could drag it along behind you, but that would be painful, at the very least.`);
+			if (isMovable(PC)) {
+				r.push(`You could drag it along behind you, but that would be painful, at the very least, so you have to resort to using a specialized cart pushed by a motorized wheelchair instead.`);
+				r.push(dickAccessibility());
 			}
 		} else if (PC.dick >= 30) {
 			r.push(`Your cock is so massive that it is difficult to live with. That's not really surprising, seeing as you have to`);
@@ -491,10 +481,26 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 	function dickAccessibility() {
 		const r = [];
 
-		if (V.dickAccessibility === 1) {
-			r.push(`It's a good thing you've had the penthouse remodeled for ${girlP}s with enormous dongs, now at least you can relieve yourself without worry.`);
-		} else {
-			r.push(`Even worse, the penthouse was not designed to handle ${girlP}s with dongs as extensive as yours; it's best not to think about the troubles you have when nature calls.`);
+		if (PC.dick >= 10) {
+			if (V.dickAccessibility === 1) {
+				r.push(`It's a good thing you've had the penthouse remodeled for ${girlP}s with enormous dongs, now at least you can relieve yourself without worry.`);
+				if (PC.dick >= 100) {
+					if (V.pregAccessibility === 1 || V.ballsAccessibility === 1 || V.boobAccessibility === 1 || V.buttAccessibility === 1) {
+						r.push(`You didn't think it was possible, but odds are that, without the penthouse remodeling, you wouldn't be able to drag your dick out of your bedroom.`);
+					} else {
+						r.push(`Or it would be, if the remodel had included doorway and hall expansions at all. You are <span class="red">currently trapped in your bedroom</span> due to the inability to feed the entire mass of your dick out of it.`);
+					}
+				}
+			} else {
+				r.push(`Even worse, the penthouse was not designed to handle ${girlP}s with dongs as extensive as yours; it's best not to think about the troubles you have when nature calls.`);
+				if (PC.dick >= 100) {
+					if (V.pregAccessibility === 1 || V.ballsAccessibility === 1 || V.boobAccessibility === 1 || V.buttAccessibility === 1) {
+						r.push(`At the very least, you don't have to worry about getting stuck in your room with it due to the penthouse remodels.`);
+					} else {
+						r.push(`You didn't think it possible, but your dick is so massive you can no longer push it through the doorway and out into the hall, <span class="red">leaving you trapped in your room.</span>`);
+					}
+				}
+			}
 		}
 
 		return r.join(" ");
@@ -580,7 +586,9 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 				r.push(`your relentless use of growth hormones has`);
 			}
 			r.push(`forced them to grow;`);
-			if (V.ballsAccessibility === 1) {
+			if (PC.balls >= 160) {
+				r.push(`they're so heavy you've lost the ability to move them without an industrial crane. But it gives you plenty of time to focus on the joys of having oversized nuts, like`);
+			} else if (V.ballsAccessibility === 1) {
 				r.push(`they'd complicate your life if your penthouse hadn't already been redesigned with oversized balls in mind, allowing you to focus on the joys of having oversized nuts, like`);
 			} else {
 				r.push(`even one is enough to make life complicated in a world designed around normal body proportions, and you're packing two of them in your sack. At least there's a certain pleasure to be derived from`);
@@ -588,7 +596,7 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 			if (cumTotal >= 1) {
 				r.push(`feeling a slave's belly steadily swell from all the cum you're pumping into them.`);
 			} else {
-				r.push(`watching a new slave panic when you lumber in and mount them for the first time, terrified of just how much cum is about to be pumped into their body.`);
+				r.push(`watching a new slave panic when you ${canMove(PC) ? "lumber over and " : ""}mount them for the first time, terrified of just how much cum is about to be pumped into their body.`);
 			}
 		} else if (PC.balls >= 50) {
 			r.push(`They're about the size of ${PC.balls >= 100 ? "large" : ""} beachballs thanks to`);
@@ -597,11 +605,10 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 			} else {
 				r.push(`your relentless use of growth hormones;`);
 			}
-			r.push(`it's impossible to find a position where they aren't in the way`);
-			if (hasAnyLegs(PC)) {
-				r.push(`of your ${legs},`);
+			if (canWalk(PC)) {
+				r.push(`it's impossible to find a position where they aren't in the way of your ${legs},`);
 			} else {
-				r.push(`when you have to be moved,`);
+				r.push(`pulling them along in a cart attached to a wheelchair is a nuisance,`);
 			}
 			r.push(`your clothing has to be custom tailored around them, and it's hard to not just be the "${girlP} with the balls", but there's a certain pleasure in`);
 			if (cumTotal >= 1) {
@@ -610,11 +617,20 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 				r.push(`watching a new slave panic when you're about to cum.`);
 			}
 			r.push(`They make life far more interesting despite the`);
-			if (V.PC.balls > 90) {
+			if (PC.balls > 90 && isMovable(PC)) {
 				if (V.ballsAccessibility === 1) {
 					r.push(`inconveniences outside the penthouse, which you've had redesigned to accommodate such proportions.`);
 				} else {
 					r.push(`inconveniences, even as they begin to really add up.`);
+					if (PC.balls > 95) {
+						if (V.buttAccessibility === 1 || V.pregAccessibility === 1 || V.boobAccessibility === 1) {
+							r.push(`Fortunately, you've had the penthouse redesigned to accommodate other enormous assets, so you can at least move around without much issue.`);
+						} else if (PC.balls >= 100) {
+							r.push(`Like not being able to force your balls through your bedroom doors without agonizing pain, for instance. Until you come up with a solution, <span class="red">you're stuck.</span>`);
+						} else {
+							r.push(`It's starting to become rather painful to get in and out of your bedroom; you might not be able to if you get any bigger.`);
+						}
+					}
 				}
 			} else {
 				r.push(`inconveniences.`);
@@ -834,7 +850,7 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 			} else {
 				r.push(`You don't get wet at all, even when aroused,`);
 				if (PC.vagina > 0) {
-					r.push(`so penetration is unpleasant at best.`);
+					r.push(`so penetration is unpleasant without the use of artificial lubricants.`);
 				} else if (PC.trueVirgin) {
 					r.push(`so sex doesn't seem like it would be that fun for you.`);
 				} else {
diff --git a/src/player/desc/pLongHealth.js b/src/player/desc/pLongHealth.js
index ea370c81db8fad8efcbf090de8f2cee36b01a55a..a603da072ba606568d8c83826ca16cfecd9b8e1d 100644
--- a/src/player/desc/pLongHealth.js
+++ b/src/player/desc/pLongHealth.js
@@ -18,17 +18,19 @@ App.Desc.Player.health = function(PC = V.PC) {
 		r.push(`You've <span class="green">never felt better.</span>`);
 	}
 
-	if (PCH.condition < -20) {
-		if (PCH.shortDamage >= 50) {
-			r.push(`Your body agrees, leaving you <span class="red">incapacitated by your worsening injuries.</span>`);
-		} else if (PCH.shortDamage >= 20) {
-			r.push(`To make it worse, a <span class="red">feeling of malaise</span> looms over you.`);
-		}
-	} else {
-		if (PCH.shortDamage >= 50) {
-			r.push(`Your body, however, has a different opinion; it <span class="red">refuses to function properly</span> until it is given time to heal.`);
-		} else if (PCH.shortDamage >= 20) {
-			r.push(`A <span class="red">feeling of malaise</span> hangs over you, however.`);
+	if (PCH.shortDamage >= 20) {
+		if (PCH.condition < -20) {
+			if (PCH.shortDamage >= 200) {
+				r.push(`Your body agrees, leaving you <span class="red">increasingly vulnerable to further injuries.</span>`);
+			} else {
+				r.push(`To make it worse, a <span class="red">feeling of malaise</span> looms over you.`);
+			}
+		} else {
+			if (PCH.shortDamage >= 200) {
+				r.push(`Your body, however, has a different opinion; it is <span class="red">susceptible to further injury</span> unless given time to heal.`);
+			} else {
+				r.push(`A <span class="red">feeling of malaise</span> hangs over you, however.`);
+			}
 		}
 	}
 
diff --git a/src/player/doctorConsultation.js b/src/player/doctorConsultation.js
index 81df831c40339f120eebdbd1c12309e423cef5eb..fa77acef0818062373450a3981cfc730f56b791a 100644
--- a/src/player/doctorConsultation.js
+++ b/src/player/doctorConsultation.js
@@ -21,16 +21,16 @@ App.UI.doctorConsultation = function() {
 
 	if (V.doctor.state > 1) {
 		App.Events.addParagraph(frag, [
-			`You head to the private clinic to meet with your doctor for another medical examination. After a short wait, and a payment of <span class="cash">${cashFormat(price)},</span> you're directed to your doctor's exam room for your appointment. "Back again so soon? We're happy to keep giving you drugs and advice if you keep giving us money; the owner wants to buy a new organ farm after all. Have to say I am a bit jealous of our neighbor's expensive new toy, I mean can you blame me? The only toys we find here are usually lodged someplace${V.PC.actualAge < V.minimumSlaveAge ? "—Ah! Nevermind! Someone your age shouldn't be hearing things like that, and no, I don't want to know what you get up to up there in the penthouse." : "they shouldn't be, if you catch my drift. You can only take so much of that before you start to question your career decisions, oh, and good luck ever looking at them the same way again"}."`
+			`You head to the private clinic to meet with your doctor for another medical examination. After a short wait, and a payment of <span class="cash">${cashFormat(price)},</span> you're directed to your doctor's exam room for your appointment. "Back again so soon? We're happy to keep giving you drugs and advice if you keep giving us money; the owner wants to buy a new organ farm, after all. Have to say I am a bit jealous of our neighbor's expensive new toy — I mean, can you blame me? The only toys we find here are usually lodged someplace${V.PC.actualAge < V.minimumSlaveAge ? "— Ah! Never mind! Someone your age shouldn't be hearing things like that, and no, I don't want to know what you get up to up there in the penthouse" : " they shouldn't be, if you catch my drift. You can only take so much of that before you start to question your career decisions. Oh, and good luck ever looking at them the same way again"}."`
 		]);
 	} else if (V.doctor.state > 0) {
 		App.Events.addParagraph(frag, [
-			`You head to the private clinic to meet with your doctor for a medical examination. After a short wait, and a payment of <span class="cash">${cashFormat(price)},</span> you're directed to your doctor's exam room for your appointment. "${V.PC.health.condition < 20 || V.PC.health.illness > 1 || V.PC.addict > 10 ? "Well you've seen better days, haven't you? Came to the right place to put back in order, though." : "You seem to be doing well, but let's see what the tests have to say about that"}. Hop up on the scale and we'll get this over with."`
+			`You head to the private clinic to meet with your doctor for a medical examination. After a short wait, and a payment of <span class="cash">${cashFormat(price)},</span> you're directed to your doctor's exam room for your appointment. "${V.PC.health.condition < 20 || V.PC.health.illness > 1 || V.PC.addict > 10 ? "Well, you've seen better days, haven't you? Came to the right place to be put back in order, though" : "You seem to be doing well, but let's see what the tests have to say about that"}. Hop up on the scale and we'll get this over with."`
 		]);
 		V.doctor.state = 2;
 	} else {
 		App.Events.addParagraph(frag, [
-			`You make your way to ${arcology.name}'s main medical pavilion, which houses the largest private clinic in the arcology, intent on finding a primary physician to keep an eye on your health. ${arcology.FSHedonisticDecadence !== "unset" ? "There is a substantial wait before you're seen, owing to the increasingly eccentric people that make up your citizenry, so you have plenty of time to deal with registering and enjoy a little people-watching, after" : "The clinic operates like a well-oiled machine, and you barely get through registering yourself"} before your name is called. As you enter the exam room, you're greeted by an imposing, rather harried looking ${womanU}, "Welcome ${PlayerName()}.${V.PC.actualAge < V.minimumSlaveAge ? `" ${HeU} gives you a momentary dirty look before realizing what ${heU} did. "Apologies, I just thought you'd be a little older... Nevermind.` : ""} I will be serving as your doctor from here on, and while the first visit is free, future ones will run you <span class="noteworthy">${cashFormat(price)},</span> so do try to remember that. To start, would you please step onto this scale so we may begin this examination?"`
+			`You make your way to ${arcology.name}'s main medical pavilion, which houses the largest private clinic in the arcology, intent on finding a primary physician to keep an eye on your health. ${arcology.FSHedonisticDecadence !== "unset" ? "There is a substantial wait before you're seen, owing to the increasingly eccentric people that make up your citizenry, so you have plenty of time to deal with registering and enjoy a little people-watching" : "The clinic operates like a well-oiled machine, and you barely get through registering yourself"} before your name is called. As you enter the exam room, you're greeted by an imposing, rather harried-looking ${womanU}, "Welcome, ${PlayerName()}.${V.PC.actualAge < V.minimumSlaveAge ? `" ${HeU} gives you a momentary dirty look before realizing what ${heU} did. "Apologies, I just thought you'd be a little older... never mind.` : ""} I will be serving as your doctor from here on, and while the first visit is free, future ones will run you <span class="noteworthy">${cashFormat(price)},</span> so do try to remember that. To start, would you please step onto this scale so we may begin this examination?"`
 		]);
 		V.doctor.state = 1;
 	}
@@ -53,7 +53,7 @@ App.UI.doctorConsultation = function() {
 
 		r.push(`"With all the tests completed, let's see how you did.`);
 		if (PCH.condition < -90) {
-			r.push(`<span class="red">Good lord you are very unwell.</span> We can stabilize you, but after that, go home and rest. Eat well, keep your spirits up, and maybe pray a little. If you feel you are dying, call us at once.`);
+			r.push(`<span class="red">Good lord, you are very unwell.</span> We can stabilize you, but after that, go home and rest. Eat well, keep your spirits up, and maybe pray a little. If you feel you are dying, call us at once.`);
 		} else if (PCH.condition < -50) {
 			r.push(`<span class="red">You're very unhealthy.</span> After I treat you, go home and rest. Eat well, keep your spirits up, and get some rest. If it persists, come back at once.`);
 		} else if (PCH.condition < -20) {
@@ -63,9 +63,9 @@ App.UI.doctorConsultation = function() {
 		} else if (PCH.condition <= 50) {
 			r.push(`<span class="green">Your health is good,</span> but not great. Nothing to worry about, as long as it doesn't start dipping.`);
 		} else if (PCH.condition <= 90) {
-			r.push(`<span class="green">Your health is great,</span> keep doing whatever it is you're doing.`);
+			r.push(`<span class="green">Your health is great;</span> keep doing whatever it is you're doing.`);
 		} else {
-			r.push(`<span class="green">Your health is pretty much the ideal,</span> it can't possibly get any better.`);
+			r.push(`<span class="green">Your health is pretty much the ideal;</span> it can't possibly get any better.`);
 		}
 
 		if (PCH.illness > 1) {
@@ -133,7 +133,7 @@ App.UI.doctorConsultation = function() {
 			if (V.PC.actualAge <= 12 && V.PC.actualAge < V.minimumSlaveAge) {
 				if (V.PC.pregKnown) {
 					if (isInduced(V.PC)) {
-						r.push(r.pop() + `" ${HeU} seems to be trying ${hisU} hardest to avoid looking at you, "You're fully dilated, but at your age, odds aren't in your favor for a successful natural birth. If you'd consent, I'll have you prepped for a cesarean at once.`); 
+						r.push(r.pop() + `" ${HeU} seems to be trying ${hisU} hardest to avoid looking at you, "You're fully dilated, but at your age, odds aren't in your favor for a successful natural birth. If you'd consent, I'll have you prepped for a cesarean at once.`);
 					} else if (V.dangerousPregnancy === 1) {
 						if ((V.PC.belly > (V.PC.pregAdaptation * 3200)) || V.PC.bellyPreg >= 500000) {
 							r.push(r.pop() + `" ${HeU} looks ready to vomit after having inspected your body-turned-womb, "This is going to haunt my dreams. How, why? I can't understand what would propel a child to do this to themselves. I have no advice for you other than taking residency here until whatever happens, happens. I just hope there's something left to salvage...`);
@@ -148,7 +148,7 @@ App.UI.doctorConsultation = function() {
 						r.push(r.pop() + `" ${HeU} glances uncomfortably at your stomach, "Your pregnancy is progressing smoothly, for now. But children aren't ready to make babies, so please take it easy.`);
 					}
 				} else {
-					r.push(`Your urine sample says you are... <span class="pregnancy">pregnant.</span> If someone took advantage of you, you can tell us you know. This is a safe place. Or, um, have you been 'experimenting'? No, no, I don't want to know if you have been.`);
+					r.push(`Your urine sample says you are... <span class="pregnancy">pregnant.</span> If someone took advantage of you, you can tell us, you know. This is a safe place. Or, um, have you been 'experimenting'? No, no, I don't want to know if you have been.`);
 					V.PC.pregKnown = 1;
 				}
 			} else if (V.PC.actualAge < V.minimumSlaveAge) {
@@ -157,7 +157,7 @@ App.UI.doctorConsultation = function() {
 						r.push(`I didn't want to say anything at the moment, but you're fully dilated, and since you're a bit young still, should I take you to maternity or...?`);
 					} else if (V.dangerousPregnancy === 1) {
 						if ((V.PC.belly > (V.PC.pregAdaptation * 3200)) || V.PC.bellyPreg >= 500000) {
-							r.push(`Dear god, how did you manage to get yourself into this state? At your age, to be swollen like that; it's just disturbing to see. Anyway, Assuming your womb just doesn't burst on its own, try to stay as still as much as possible and, um, avoid pointy objects?`);
+							r.push(`Dear god, how did you manage to get yourself into this state? At your age, to be swollen like that; it's just disturbing to see. Anyway, assuming your womb just doesn't burst on its own, try to stay as still as much as possible and, um, avoid pointy objects?`);
 						} else if ((V.PC.bellyPreg >= V.PC.pregAdaptation * 2200) || (V.PC.womb.find((ft) => ft.genetics.geneticQuirks.polyhydramnios === 2 && ft.age >= 20))) {
 							r.push(`Hmm, your body is struggling to bear the weight in your womb. Try to stay put as much as you can and don't move around too much. No strenuous activities, either! Especially 'fooling around' after it got you into this state!`);
 						} else if (V.PC.bellyPreg > V.PC.pregAdaptation * 1000) {
@@ -199,7 +199,7 @@ App.UI.doctorConsultation = function() {
 			r.push(`We have drugs that can delay birth to an extent, helping to avoid miscarriage and premature birth in at-risk mothers. With what I've seen, you're eligible for them. They aren't the healthiest things to take, however, and there are serious issues if you accidentally forget to stop taking them to allow for birth when you're due.`);
 		}
 		if (V.PC.preg > V.PC.pregData.normalBirth / 1.42 && V.PC.hips === -2 && V.PC.hipsImplant === 0) {
-			r.push(`Your hips are a bit too narrow for birth and, assuming you manage, you will end up splitting your pelvis. You could take these tablets to boost the amount of relaxing in your system in an effort to widen your hips, but long term use will cause more problems than its worth. It's up to you if you want to take them or just opt for a cesarean section.`);
+			r.push(`Your hips are a bit too narrow for birth and, assuming you manage, you will end up splitting your pelvis. You could take these tablets to boost the amount of relaxin in your system in an effort to widen your hips, but long term use will cause more problems than it's worth. It's up to you if you want to take them or just opt for a cesarean section.`);
 		}
 
 		// injuries
@@ -221,14 +221,14 @@ App.UI.doctorConsultation = function() {
 
 		if (V.PC.energy > 95) {
 			if (V.PC.actualAge <= 12) {
-				r.push(`Anaphrodisiacs. I'm prescribing them to you. You are way too young to doing things like that. Now I feel dirty thanks to you.`);
+				r.push(`Anaphrodisiacs. I'm prescribing them to you. You are way too young to be doing things like that. Now I feel dirty thanks to you.`);
 			} else {
 				r.push(`I noticed your orgasm during the cancer screening. You've lost control of your sex drive, haven't you? I can prescribe anaphrodisiacs to you if you want to regain your composure.`);
 			}
 		}
 
 		if (V.PC.addict > 3 || V.PC.aphrodisiacs > 0 || V.PC.inflationType === "aphrodisiac") {
-			r.push(`The urinalyses tells me you've been hitting the aphrodisiacs. I hope you know the risks involved with that. I'm sure you do, but if you ever need any assistance with it, we do have detox pills available.`);
+			r.push(`The urinalysis tells me you've been hitting the aphrodisiacs. I hope you know the risks involved with that. I'm sure you do, but if you ever need any assistance with it, we do have detox pills available.`);
 		}
 
 		if (V.PC.chem > 5) {
@@ -240,7 +240,7 @@ App.UI.doctorConsultation = function() {
 		}
 
 		if (V.week > 45 && V.PC.digestiveSystem === "atrophied") {
-			r.push(`<span class="noteworthy">Some progress has been made when it comes to reversing the effects of long-term consumption of slave food.</span> It's best described as an intermediary diet to get your body used to real food again. From what I've heard, the process is horrible, and you can't stop once you start or you'll undo all your effort. Hmm, it also says not to give it pregnant and nursing women, the infirm, and those with compromised immune systems. Oh, and that one should put on some bodyfat before starting, to help offset the whole starvation thing. The more I read, the worse it gets, but it may be worth considering, given your, you know, past.`);
+			r.push(`<span class="noteworthy">Some progress has been made when it comes to reversing the effects of long-term consumption of slave food.</span> It's best described as an intermediary diet to get your body used to real food again. From what I've heard, the process is horrible, and you can't stop once you start or you'll undo all your effort. Hmm, it also says not to give it to pregnant and nursing women, the infirm, and those with compromised immune systems. Oh, and that one should put on some body fat before starting, to help offset the whole starvation thing. The more I read, the worse it gets, but it may be worth considering, given your, you know, past.`);
 		}
 		r.push(`And that's all that's worth really noting."`);
 
@@ -489,7 +489,7 @@ App.UI.doctorConsultation = function() {
 				]));
 			} else if (V.PC.health.condition <= 20) {
 				text.push(App.UI.DOM.disabledLink(`Start the process`, [
-					`In your condition, this diet while have a deleterious effect on your health.`,
+					`In your condition, this diet will have a deleterious effect on your health.`,
 				]));
 			} else if (V.PC.health.illness > 1) {
 				text.push(App.UI.DOM.disabledLink(`Start the process`, [
@@ -517,7 +517,7 @@ App.UI.doctorConsultation = function() {
 	function healthBoost() {
 		const text = [];
 
-		text.push(`${HeU} gives you a quick prick with a syringe. "${V.PC.actualAge > 12 ? `Heres a little something to <span class="health inc">help your health.</span> It's just a quick pick-me-up, but perhaps it will get you back on track` : `That's a good ${girlP}, that wasn't so bad, was it? Here, have a lollipop to feel better. As for the shot, it should <span class="health inc">improve your health a little,</span> and hopefully set you on the road to recovery`}."`);
+		text.push(`${HeU} gives you a quick prick with a syringe. "${V.PC.actualAge > 12 ? `Here's a little something to <span class="health inc">help your health.</span> It's just a quick pick-me-up, but perhaps it will get you back on track` : `That's a good ${girlP}, that wasn't so bad, was it? Here, have a lollipop to feel better. As for the shot, it should <span class="health inc">improve your health a little,</span> and hopefully set you on the road to recovery`}."`);
 		improveCondition(V.PC, 5);
 
 		App.Events.addNode(treatDiv, text);
diff --git a/src/player/electiveSurgery.js b/src/player/electiveSurgery.js
index b0ead916ad6d2ddd4921085630c5e961d82b4dfe..cf8db44f21b05c13bdd5eed6176b5b436ad52e3d 100644
--- a/src/player/electiveSurgery.js
+++ b/src/player/electiveSurgery.js
@@ -100,10 +100,10 @@ App.UI.electiveSurgery = function() {
 		}
 	} else {
 		App.Events.addParagraph(el, [
-			`You ${canWalk(V.PC) ? "wander" : "drive"} up and down ${arcology.name}'s primary medical pavilion, taking in what practices are available and their relative popularity. ${arcology.FSBodyPurist !== "unset" ? "Most of the plastic surgeons have packed up and left, but of those that chose to stay," : "While there is no shortage of plastic surgeons to choose from,"} there is a clear winner; the small suite at the end of the wing completely swarmed by patrons. It takes some effort to work your way through the crowd, but the moment the ${nurse.boobs > 2000 ? "busty" : "cute"} assistant behind the counter notices you and ${nurse.belly >= 10000 ? "waddles" : "rushes"} over${nurse.butt > 10 ? `, practically bulldozing ${himselfU} a path in the process with ${hisU} absurd hips and rear` : ""}, do you find yourself whisked away to an exam room by ${himU}. "${V.PC.visualAge < V.minimumSlaveAge ? "Oh my god! You're so cute! Does your mother know you're here? If she doesn't, your secret's safe with us!" : "You're the new owner, right? Recognized you from the newsfeeds"}. Anyway, we'll need to do a few measurements, take some biometrics, and sign a couple papers before we can put you under the knife. You know, standard business and all that." With the paperwork taken care of, and after what can only be called an "intimate fondlng" under the guise of a medical examination${nurse.butt > 10 || nurse.belly >= 5000 || nurse.boobs > 2000 ? `, with a little helping of ${hisU} larger assets rubbing against you on the side` : ""}, you're ready to look over the available procedures. ${nurse.butt > 10 || nurse.belly >= 5000 || nurse.boobs > 2000 ? `"Heh, yeah I can get a little handsy, and feeling all of this," ${heU} gestures at ${hisU} enhanced curves, "pushing against someone is just soo thrilling!"` : `"Heh, yeah I can get a little handsy"`}. I think that's part of why we're so popular, not that the doctors' work is shabby or anything! I mean, I came out okay, right? Plus I really do enjoy seeing what they can come up with, it's an art form, really, and boy does it get me excited." ${HeU} coughs and gets back to the heart of the matter. "You have a dream body, and we have the means to make it happen! So, what can I help you with?"`
+			`You ${canWalk(V.PC) ? "wander" : "drive"} up and down ${arcology.name}'s primary medical pavilion, taking in what practices are available and their relative popularity. ${arcology.FSBodyPurist !== "unset" ? "Most of the plastic surgeons have packed up and left, but of those that chose to stay," : "While there is no shortage of plastic surgeons to choose from,"} there is a clear winner; the small suite at the end of the wing completely swarmed by patrons. It takes some effort to work your way through the crowd, but the moment the ${nurse.boobs > 2000 ? "busty" : "cute"} assistant behind the counter notices you and ${nurse.belly >= 10000 ? "waddles" : "rushes"} over${nurse.butt > 10 ? `, practically bulldozing ${himselfU} a path in the process with ${hisU} absurd hips and rear` : ""}, do you find yourself whisked away to an exam room by ${himU}. "${V.PC.visualAge < V.minimumSlaveAge ? "Oh my god! You're so cute! Does your mother know you're here? If she doesn't, your secret's safe with us!" : "You're the new owner, right? Recognized you from the newsfeeds"}. Anyway, we'll need to do a few measurements, take some biometrics, and sign a couple papers before we can put you under the knife. You know, standard business and all that." With the paperwork taken care of, and after what can only be called an "intimate fondlng" under the guise of a medical examination${nurse.butt > 10 || nurse.belly >= 5000 || nurse.boobs > 2000 ? `, with a little helping of ${hisU} larger assets rubbing against you on the side` : ""}, you're ready to look over the available procedures. ${nurse.butt > 10 || nurse.belly >= 5000 || nurse.boobs > 2000 ? `"Heh, yeah I can get a little handsy, and feeling all of this," ${heU} gestures at ${hisU} enhanced curves, "pushing against someone is just soo thrilling!` : `"Heh, yeah I can get a little handsy.`} I think that's part of why we're so popular, not that the doctor's work is shabby or anything! I mean, I came out okay, right? Plus I really do enjoy seeing what they can come up with, it's an art form, really, and boy does it get me excited." ${HeU} coughs and gets back to the heart of the matter. "You have a dream body, and we have the means to make it happen! So, what can I help you with?"`
 		]);
 		App.Events.addParagraph(el, [
-			`"Oh! I almost forgot! Since you're a new client, <span class="green">today's basic surgery is half off!</span>${arcology.FSBodyPurist !== "unset" ? `But, <span class="red">the cost of implants is still high</span> due to policy, unfortunately...` : arcology.FSTransformationFetishist !== "unset" ? `And with <span class="green">implants being so cheap,</span> we're practically giving them away!` : ""}"`
+			`"Oh! I almost forgot! Since you're a new client, <span class="green">today's basic surgery is half off!</span>${arcology.FSBodyPurist !== "unset" ? ` But, <span class="red">the cost of implants is still high</span> due to policy, unfortunately...` : arcology.FSTransformationFetishist !== "unset" ? ` And with <span class="green">implants being so cheap,</span> we're practically giving them away!` : ""}"`
 		]);
 		freebie = 1;
 		V.pSurgery.state = 1;
diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js
index 7136ca0a315b1e27423a3597ed7aec7df5d6a57f..18ea55c44bf34ad1a8b9c25b2e34676959b32c72 100644
--- a/src/player/js/PlayerState.js
+++ b/src/player/js/PlayerState.js
@@ -349,6 +349,11 @@ App.Entity.PlayerState = class PlayerState {
 		 * @type {FC.MinorInjury}
 		 */
 		this.minorInjury = 0;
+		/**
+		 * you have taken a major injury
+		 * number of weeks laid up in bed until recovery
+		 */
+		this.majorInjury = 0;
 		/**
 		 * you have a life-changing injury/malaise
 		 * @type {number | string}
diff --git a/src/player/managePersonalAffairs.js b/src/player/managePersonalAffairs.js
index 3056d1f91c54b82b86c634c9b8a02512a935e473..94142b5de8ad06136adddd3661dcb53b5813ac71 100644
--- a/src/player/managePersonalAffairs.js
+++ b/src/player/managePersonalAffairs.js
@@ -287,7 +287,7 @@ App.UI.managePersonalAffairs = function() {
 			familyDiv.append(App.UI.DOM.linkReplace(`Pull up the file on your family tree`, renderFamilyTree(V.slaves, -1)));
 
 			if (totalPlayerRelatives(PC) > 0 || (V.showMissingSlaves && (PC.mother in V.missingTable || PC.father in V.missingTable))) {
-				App.Events.addNode(familyDiv, [App.Desc.family(PC)]);
+				familyDiv.append(App.Desc.family(PC, true));
 			}
 
 			return familyDiv;
@@ -728,7 +728,7 @@ App.UI.managePersonalAffairs = function() {
 			links.push(App.UI.DOM.disabledLink(`Gain weight`, [
 				`${onDiet}`,
 			]));
-		} else if (PC.weight >= -95) {
+		} else if (PC.weight <= 195) {
 			links.push(App.UI.DOM.link(`Gain weight`, () => {
 				PC.diet = "fattening";
 				App.UI.DOM.replace(dietDiv, diet);
@@ -742,29 +742,37 @@ App.UI.managePersonalAffairs = function() {
 			links.push(App.UI.DOM.disabledLink(`Build muscle`, [
 				`${onDiet}`,
 			]));
-		} else if (PC.muscles < 100 && !isAmputee(PC)) {
+		} else if (PC.muscles < 100 && !isAmputee(PC) && !onBedRest(PC)) {
 			links.push(App.UI.DOM.link(`Build muscle`, () => {
 				PC.diet = "muscle building";
 				App.UI.DOM.replace(dietDiv, diet);
 			}));
-		} else if (!isAmputee(PC)) {
+		} else if (isAmputee(PC)) {
 			links.push(App.UI.DOM.disabledLink(`Build muscle`, [
-				`You can't get any stronger`,
+				`You can't work out with no limbs`,
+			]));
+		} else if (onBedRest(PC)) {
+			links.push(App.UI.DOM.disabledLink(`Build muscle`, [
+				`You are in no condition to work out`,
 			]));
 		} else {
 			links.push(App.UI.DOM.disabledLink(`Build muscle`, [
-				`You can't work out with no limbs`,
+				`You can't get any stronger`,
 			]));
 		}
 		if (PC.diet === "slimming") {
 			links.push(App.UI.DOM.disabledLink(`Slim down`, [
 				`${onDiet}`,
 			]));
-		} else if (PC.muscles > 0 && canWalk(PC)) {
+		} else if (PC.muscles > 0 && canWalk(PC) && !onBedRest(PC)) {
 			links.push(App.UI.DOM.link(`Slim down`, () => {
 				PC.diet = "slimming";
 				App.UI.DOM.replace(dietDiv, diet);
 			}));
+		} else if (onBedRest(PC)) {
+			links.push(App.UI.DOM.disabledLink(`Build muscle`, [
+				`You are in no condition to be doing cardio`,
+			]));
 		} else if (!canWalk(PC)) {
 			links.push(App.UI.DOM.disabledLink(`Slim down`, [
 				`You can't focus on cardio if you can't walk`,
diff --git a/src/player/pcSurgeryDegradation.js b/src/player/pcSurgeryDegradation.js
index 68000e8d82b92cf630143aad61937b72b16ef9d9..523c89ad7f101fad94c62294b27f2c0c24b84804 100644
--- a/src/player/pcSurgeryDegradation.js
+++ b/src/player/pcSurgeryDegradation.js
@@ -147,7 +147,7 @@ App.UI.PCSurgeryDegradation = function(surgeryType) {
 				}
 				r.push(`Either way, this is a good thing. Your breasts work."`);
 			}
-			r.push(`You can't help but moan under your building arousal as ${heU} massages and teases your implant laden breasts. "Enjoying yourself are we? Let me finish you off." ${HeU} sneaks a hand down to your`);
+			r.push(`You can't help but moan under your building arousal as ${heU} massages and teases your implant-laden breasts. "Enjoying yourself are we? Let me finish you off." ${HeU} sneaks a hand down to your`);
 			if (V.PC.dick !== 0) {
 				r.push(`stiff prick and begins stroking its length, quickly bringing you to orgasm and relieving you of your built up tension.`);
 			} else {
@@ -269,7 +269,7 @@ App.UI.PCSurgeryDegradation = function(surgeryType) {
 			} else {
 				r.push(`big`);
 			}
-			r.push(`rounded butt. "Size isn't everything in an ass, shape is important too, though I think you've got a good balance. We didn't need to do much reshaping when we put in the implant." ${HeU} begins groping your bottom, feeling the silicone filled implant for any oddities. "I know you're still a little sore, but bear with it. There, everything feels good, now rest up and you'll be set! Though you may need some help righting yourself until you get used to its added weight. Feel free to rest as long as you need before departing. If you need, or want, me, I'll be around." Groggy, you lie back down to sleep off the rest of the anesthesia before returning to your arcology.`);
+			r.push(`rounded butt. "Size isn't everything in an ass, shape is important too, though I think you've got a good balance. We didn't need to do much reshaping when we put in the implant." ${HeU} begins groping your bottom, feeling the silicone-filled implant for any oddities. "I know you're still a little sore, but bear with it. There, everything feels good, now rest up and you'll be set! Though you may need some help righting yourself until you get used to its added weight. Feel free to rest as long as you need before departing. If you need, or want, me, I'll be around." Groggy, you lie back down to sleep off the rest of the anesthesia before returning to your arcology.`);
 			break;
 		case "buttEnlargement":
 			r.push(`After a few hours, you awaken in the recovery wing, face-down in a bed made to accommodate a person with your body type, with a sore ass. You push yourself up and look at the mass under the cover behind you that is your rear, taking note of how much bigger it is now than when you arrived. "So do you like it?", asks the surgeon's assistant, seating ${himselfU} beside you and bringing ${hisU} hands to your`);
diff --git a/src/pregmod/surrogacy.js b/src/pregmod/surrogacy.js
index fbef7512ce011569c29f65e07069164d5666dc33..1eadac307093958748fb2645737b7ebf83fa4211 100644
--- a/src/pregmod/surrogacy.js
+++ b/src/pregmod/surrogacy.js
@@ -24,7 +24,7 @@ App.UI.surrogacy = function() {
 			if (V.impregnatrix.ID === -1) {
 				return V.PC;
 			} else {
-				return getSlave(V.impregnatrix.ID) || V.incubator.tanks.find(t => t.ID === V.impregnatrix.ID);
+				return findFather(V.impregnatrix.ID);
 			}
 		}
 	}
diff --git a/src/zz1-last/setupEventHandlers.js b/src/zz1-last/setupEventHandlers.js
index 44e3eb0ff12766cd4d9cd3e22cc761cfe6d0f20f..896ed386a423cbfecb38f5b1ab0d3a56fe463e76 100644
--- a/src/zz1-last/setupEventHandlers.js
+++ b/src/zz1-last/setupEventHandlers.js
@@ -14,6 +14,7 @@ $(document).on(":passageinit", () => {
 		delete V.passageSwitchHandler;
 	}
 	App.UI.Tabs.clear();
+	App.Reminders.clear();
 	profileEvents.passageinit();
 });